Commits

Chris Perl committed d4eb0f0

More refactoring around passing elfclass, byte_order, and managing whether or not to display symbolically

  • Participants
  • Parent commits b69157c

Comments (0)

Files changed (2)

 #!/usr/bin/env python
 
-# vim: ts=4 sw=4 sts=4 et tw=100
+# vim: ts=4 sw=4 sts=4 et tw=79
 
 import struct
 import StringIO
     pass
 
 class ElfObject(object):
-    # Variables that control certain behavior
-    SYMBOLIC = True
-
-    def __init__(self, elfclass=None, byte_order=None):
-        self.elfclass = elfclass
-        self.byte_order = byte_order
+    def __init__(self, elf_hdr=None):
+        self.elf_hdr = elf_hdr
 
     def __repr__(self):
         values = [ getattr(self, x) for x in self.fields ]
         combined = zip(self.fields, values)
         tmp = []
-        if self.SYMBOLIC:
+        if self.elf_hdr.owner.SYMBOLIC:
             for f, v in combined:
                 # Allow an object to override resolving of symbols for a given attribute.  This is
                 # necessary for attributes that have special interpretations, like bit fields, or
         else:
             return value 
 
-    def _unpack(self, elfclass, byte_order, f, obj32, obj64):
+    def _unpack(self, f, obj32, obj64):
         """
         Unpacks an ElfObject subclass.  If the object is 32 bit, it uses the keys from the obj32
         dictionary, while if the object is 64 bit, it uses the keys from the obj64 dictionary.
         """
+        elfclass = self.elf_hdr.elfclass
         if elfclass == ElfIdent.ELFCLASS32:
             fmt    = obj32['fmt']
             fields = obj32['fields']
         else:
             raise InvalidFileFormat("Unsupported elfclass for %s: %d" % (self.__class__.__name__, elfclass))
 
+        byte_order = self.elf_hdr.byte_order
         if byte_order == ElfIdent.ELFDATALSB:
             fmt = '<' + fmt
         elif byte_order == ElfIdent.ELFDATAMSB:
         for field, value in zip(fields, values):
             setattr(self, field, value)
 
-class ElfParser(object):
-    SECTION_HDR_TBL = 0
-    PROGRAM_HDR_TBL = 1
-
-    def __init__(self, fname):
-        f = open(fname, 'r')
-        self._f   = f
-        self.hdr = ElfHeader(self._f)
-
-    def parse(self, what):
-        # called like: for sh in p.parse(ElfParser.SECTION_HDR_TBL):
-        if what == self.SECTION_HDR_TBL:
-            return SectionHeaderTable(self.hdr, self._f)
-        elif what == self.PROGRAM_HDR_TBL:
-            return ProgramHeaderTable(self.hdr, self._f)
-        else:
-            raise StandardError("Unknown Parse Type: %d" % what)
-
 class ElfIdent(object):
     """
     A Class to hold the constants that are related to the first 16 bytes of the ELF header
                "e_phnum", "e_shentsize", 
                "e_shnum", "e_shstrndx" ) 
 
-    def __init__(self, f):
-        super(ElfHeader, self).__init__(elfclass=None, byte_order=None)
+    def __init__(self, f, owner=None):
+        # Note the reference the ElfHeader we're passing here is ourself, because we are the
+        # ElfHeader
+        super(ElfHeader, self).__init__(self)
         self._f = f
+        self.owner = owner
         self.e_ident = struct.unpack("16B", self._f.read(16))
         magic = "".join(map(chr, [self.e_ident[ElfIdent.EI_MAG0],
                                   self.e_ident[ElfIdent.EI_MAG1],
             raise InvalidFileFormat("Incorrect Version Number: %d" % version)
 
         # Set our elfclass and byte_order
-        # Note that for every other class that inherits from ElfObject, these will be set via the
-        # super call to ElfObject, but since we are the first object instantiated and its up to us
-        # to determine these values, we set them here explicitly.
         self.elfclass = self.e_ident[ElfIdent.EI_CLASS]
         self.byte_order = self.e_ident[ElfIdent.EI_DATA]
 
                   'size': 0x30,
                   'fields': ElfHeader.fields[1:],
                   'offset': 0x10 }
-        self._unpack(self.elfclass, self.byte_order, self._f, obj32, obj64)
+        self._unpack(self._f, obj32, obj64)
 
     def _symbol_resolve_e_ident(self, value):
         tmp = []
               "sh_addralign", "sh_entsize" )
 
     def __init__(self, sct_hdr_tbl, sht_offset, idx, size, f, str_tbl):
-        super(SectionHeader, self).__init__(sct_hdr_tbl.elf_hdr.elfclass,
-                                            sct_hdr_tbl.elf_hdr.byte_order)
+        super(SectionHeader, self).__init__(sct_hdr_tbl.elf_hdr)
+                                           
         self.sht = sct_hdr_tbl
         self._f = f
         self._idx = idx
                   'fields': SectionHeader.fields,
                   'offset': sht_offset+(idx*size) }
                  
-        self._unpack(self.elfclass, self.byte_order, self._f, obj32, obj64)
+        self._unpack(self._f, obj32, obj64)
 
         if str_tbl is not None:
             self.name = str_tbl[self.sh_name]
               "p_filesz", "p_memsz", "p_flags", "p_align")
     
     def __init__(self, prg_hdr_tbl, pht_offset, idx, size, f):
-        super(ProgramHeader, self).__init__(prg_hdr_tbl.elf_hdr.elfclass,
-                                            prg_hdr_tbl.elf_hdr.byte_order)
+        super(ProgramHeader, self).__init__(prg_hdr_tbl.elf_hdr)
+
         self.pht = prg_hdr_tbl
         self._f = f
         self._idx = idx
                   'fields': ProgramHeader.fields,
                   'offset': pht_offset+(idx*size) }
                  
-        self._unpack(self.elfclass, self.byte_order, self._f, obj32, obj64)
+        self._unpack(self._f, obj32, obj64)
 
     def _symbol_resolve_p_flags(self, value):
         flags = []
     STT_HIPROC  = 15
 
     def __init__(self, sym_tbl, size, idx, f):
-        super(Symbol, self).__init__(sym_tbl.sct_hdr.sht.elf_hdr.elfclass,
-                                     sym_tbl.sct_hdr.sht.elf_hdr.byte_order)
+        super(Symbol, self).__init__(sym_tbl.sct_hdr.sht.elf_hdr)
         self.st = sym_tbl
         self._f = f
         self._idx = idx
                   'fields': ("st_name", "st_info", "st_other",
                              "st_shndx", "st_value", "st_size"),
                   'offset': self._idx*self._size }
-        self._unpack(self.elfclass, self.byte_order, self._f, obj32, obj64)
+        self._unpack(self._f, obj32, obj64)
 
         # Set the name
         self.name = self.st.str_tbl[self.st_name]
     R_386_GOTPC    = 10
 
     def __init__(self, rel_tbl):
-        super(BaseRelocation, self).__init__(rel_tbl.sct_hdr.sht.elf_hdr.elfclass,
-                                             rel_tbl.sct_hdr.sht.elf_hdr.byte_order)
+        super(BaseRelocation, self).__init__(rel_tbl.sct_hdr.sht.elf_hdr)
 
     # Dynamically define these attributes and this function if we are 32 bit
     @property
                   'size': 0x10,
                   'fields': self.fields,
                   'offset': self._idx*self._size }
-        self._unpack(self.elfclass, self.byte_order, self._f, obj32, obj64)
+        self._unpack(self._f, obj32, obj64)
 
 class RelocationA(BaseRelocation):
 
                   'size': 0x18,
                   'fields': self.fields,
                   'offset': self._idx*self._size }
-        self._unpack(self.elfclass, self.byte_order, self._f, obj32, obj64)
+        self._unpack(self._f, obj32, obj64)
 
 class ELF(object):
     """
-    Top level class for ELF object file inspection
+    Top level Factory for ELF object file inspection
     """
-    def __init__(self, path):
-        # setup our parser and create the section hdr table and program hdr tbl
-        self._p = ElfParser(path)
-        self.hdr = self._p.hdr
-        self.sht = self._p.parse(ElfParser.SECTION_HDR_TBL)
-        self.pht = self._p.parse(ElfParser.PROGRAM_HDR_TBL)
+    def __new__(cls, path):
+        obj = super(ELF, cls).__new__(cls)
+        obj.SYMBOLIC = True
+        f = open(path, 'r')
+        obj.hdr = obj.header = ElfHeader(f, owner=obj)
+        obj.sht = obj.section_header_table = SectionHeaderTable(obj.hdr, f)
+        obj.pht = obj.program_header_table = ProgramHeaderTable(obj.hdr, f)
 
         # setup lists of symbol and relocation tables available with both a long and short name
-        self.sts = self.symbol_tables = []
-        self.rts = self.relocation_tables = []
-        for sh in self.sht:
-            if sh.sh_type == SectionHeader.SHT_SYMTAB or \
-               sh.sh_type == SectionHeader.SHT_DYNSYM:
-                self.sts.append(SymbolTable.get_single_instance(sh))
+        obj.sts = obj.symbol_tables = []
+        obj.rts = obj.relocation_tables = []
+        for sct_hdr in obj.sht:
+            if sct_hdr.sh_type == SectionHeader.SHT_SYMTAB or \
+               sct_hdr.sh_type == SectionHeader.SHT_DYNSYM:
+                obj.sts.append(SymbolTable.get_single_instance(sct_hdr))
 
-            if sh.sh_type == SectionHeader.SHT_REL or \
-               sh.sh_type == SectionHeader.SHT_RELA:
-                self.rts.append(RelocationTable.get_single_instance(sh))
+            if sct_hdr.sh_type == SectionHeader.SHT_REL or \
+               sct_hdr.sh_type == SectionHeader.SHT_RELA:
+                obj.rts.append(RelocationTable.get_single_instance(sct_hdr))
+
+        return obj
 
 def main():
         pass
 
 class ElfTests(unittest.TestCase):
     def _setup_common(self, fname):
-        self.p = ElfParser(fname)
-        self.sht = self.p.parse(ElfParser.SECTION_HDR_TBL)
-        self.pht = self.p.parse(ElfParser.PROGRAM_HDR_TBL)
+        self.elf = ELF(fname)
 
     def _test_hdr_common(self):
-        self.assertEqual(self.p.hdr.e_ident[0], 0x7f)
-        self.assertEqual(self.p.hdr.e_ident[1], ord('E'))
-        self.assertEqual(self.p.hdr.e_ident[2], ord('L'))
-        self.assertEqual(self.p.hdr.e_ident[3], ord('F'))
-        self.assertEqual(self.p.hdr.e_version, ElfHeader.EV_CURRENT)
+        self.assertEqual(self.elf.hdr.e_ident[0], 0x7f)
+        self.assertEqual(self.elf.hdr.e_ident[1], ord('E'))
+        self.assertEqual(self.elf.hdr.e_ident[2], ord('L'))
+        self.assertEqual(self.elf.hdr.e_ident[3], ord('F'))
+        self.assertEqual(self.elf.hdr.e_version, ElfHeader.EV_CURRENT)
 
     def _test_num_section_hdr_entries(self, expected):
-        self.assertEqual(len(self.sht), expected)
+        self.assertEqual(len(self.elf.sht), expected)
 
     def _test_num_program_hdr_entries(self, expected):
-        self.assertEqual(len(self.pht), expected)
+        self.assertEqual(len(self.elf.pht), expected)
 
     def _test_section_names(self, names):
         for idx, name in enumerate(names):
-            self.assertEqual(name, self.sht[idx].name)
+            self.assertEqual(name, self.elf.sht[idx].name)
 
     def _test_num_relocation_sections(self, expected):
-        relocation_scts = [x for x in self.sht if (x.sh_type == SectionHeader.SHT_REL or
-                                                   x.sh_type == SectionHeader.SHT_RELA)]
+        relocation_scts = [x for x in self.elf.sht if (x.sh_type == SectionHeader.SHT_REL or
+                                                       x.sh_type == SectionHeader.SHT_RELA)]
         self.assertEqual(len(relocation_scts), expected)
 
     def _test_num_symbol_sections(self, expected):
-        symbol_scts = [x for x in self.sht if (x.sh_type == SectionHeader.SHT_SYMTAB or
-                                               x.sh_type == SectionHeader.SHT_DYNSYM)]
+        symbol_scts = [x for x in self.elf.sht if (x.sh_type == SectionHeader.SHT_SYMTAB or
+                                                   x.sh_type == SectionHeader.SHT_DYNSYM)]
         self.assertEqual(len(symbol_scts), expected)
 
     def _test_symbol_sections(self):
-        sts = map(SymbolTable.get_single_instance, [x for x in self.sht if (x.sh_type == SectionHeader.SHT_SYMTAB or
+        sts = map(SymbolTable.get_single_instance, [x for x in self.elf.sht if (x.sh_type == SectionHeader.SHT_SYMTAB or
                                                                  x.sh_type == SectionHeader.SHT_DYNSYM)])
         for st in sts:
             self.assertTrue(isinstance(st, SymbolTable))
                 self.assertTrue(isinstance(s, Symbol))
 
     def _test_relocation_sections(self):
-        rts = map(RelocationTable.get_single_instance, [x for x in self.sht if (x.sh_type == SectionHeader.SHT_REL or
+        rts = map(RelocationTable.get_single_instance, [x for x in self.elf.sht if (x.sh_type == SectionHeader.SHT_REL or
                                                                      x.sh_type == SectionHeader.SHT_RELA)])
         for rt in rts:
             self.assertTrue(isinstance(rt, RelocationTable))
     def test_hdr(self):
         self._test_hdr_common()
         # Specific to this ELF object
-        self.assertEqual(self.p.hdr.e_ident[ElfIdent.EI_CLASS], ElfIdent.ELFCLASS32)
-        self.assertEqual(self.p.hdr.e_ident[ElfIdent.EI_DATA], ElfIdent.ELFDATALSB)
-        self.assertEqual(self.p.hdr.e_type, ElfHeader.ET_DYN)
-        self.assertEqual(self.p.hdr.e_machine, ElfHeader.EM_386)
-        self.assertEqual(self.p.hdr.e_entry, 0x20740)
-        self.assertEqual(self.p.hdr.e_phoff, 0x34)
-        self.assertEqual(self.p.hdr.e_shoff, 0x1586cc)
-        self.assertEqual(self.p.hdr.e_flags, 0x0)
-        self.assertEqual(self.p.hdr.e_ehsize, 52)
-        self.assertEqual(self.p.hdr.e_phentsize, 32)
-        self.assertEqual(self.p.hdr.e_phnum, 4)
-        self.assertEqual(self.p.hdr.e_shentsize, 40)
-        self.assertEqual(self.p.hdr.e_shnum, 30)
-        self.assertEqual(self.p.hdr.e_shstrndx, 27)
+        self.assertEqual(self.elf.hdr.e_ident[ElfIdent.EI_CLASS], ElfIdent.ELFCLASS32)
+        self.assertEqual(self.elf.hdr.e_ident[ElfIdent.EI_DATA], ElfIdent.ELFDATALSB)
+        self.assertEqual(self.elf.hdr.e_type, ElfHeader.ET_DYN)
+        self.assertEqual(self.elf.hdr.e_machine, ElfHeader.EM_386)
+        self.assertEqual(self.elf.hdr.e_entry, 0x20740)
+        self.assertEqual(self.elf.hdr.e_phoff, 0x34)
+        self.assertEqual(self.elf.hdr.e_shoff, 0x1586cc)
+        self.assertEqual(self.elf.hdr.e_flags, 0x0)
+        self.assertEqual(self.elf.hdr.e_ehsize, 52)
+        self.assertEqual(self.elf.hdr.e_phentsize, 32)
+        self.assertEqual(self.elf.hdr.e_phnum, 4)
+        self.assertEqual(self.elf.hdr.e_shentsize, 40)
+        self.assertEqual(self.elf.hdr.e_shnum, 30)
+        self.assertEqual(self.elf.hdr.e_shstrndx, 27)
 
     def test_num_section_hdr_entries(self):
         self._test_num_section_hdr_entries(30)
     def test_hdr(self):
         self._test_hdr_common()
         # Specific to this ELF object
-        self.assertEqual(self.p.hdr.e_ident[ElfIdent.EI_CLASS], ElfIdent.ELFCLASS64)
-        self.assertEqual(self.p.hdr.e_ident[ElfIdent.EI_DATA], ElfIdent.ELFDATALSB)
-        self.assertEqual(self.p.hdr.e_type, ElfHeader.ET_DYN)
-        self.assertEqual(self.p.hdr.e_machine, ElfHeader.EM_AMD64)
-        self.assertEqual(self.p.hdr.e_entry, 0x120)
-        self.assertEqual(self.p.hdr.e_phoff, 0x40)
-        self.assertEqual(self.p.hdr.e_shoff, 0x1c5c68)
-        self.assertEqual(self.p.hdr.e_flags, 0x0)
-        self.assertEqual(self.p.hdr.e_ehsize, 64)
-        self.assertEqual(self.p.hdr.e_phentsize, 56)
-        self.assertEqual(self.p.hdr.e_phnum, 4)
-        self.assertEqual(self.p.hdr.e_shentsize, 64)
-        self.assertEqual(self.p.hdr.e_shnum, 38)
-        self.assertEqual(self.p.hdr.e_shstrndx, 35)
+        self.assertEqual(self.elf.hdr.e_ident[ElfIdent.EI_CLASS], ElfIdent.ELFCLASS64)
+        self.assertEqual(self.elf.hdr.e_ident[ElfIdent.EI_DATA], ElfIdent.ELFDATALSB)
+        self.assertEqual(self.elf.hdr.e_type, ElfHeader.ET_DYN)
+        self.assertEqual(self.elf.hdr.e_machine, ElfHeader.EM_AMD64)
+        self.assertEqual(self.elf.hdr.e_entry, 0x120)
+        self.assertEqual(self.elf.hdr.e_phoff, 0x40)
+        self.assertEqual(self.elf.hdr.e_shoff, 0x1c5c68)
+        self.assertEqual(self.elf.hdr.e_flags, 0x0)
+        self.assertEqual(self.elf.hdr.e_ehsize, 64)
+        self.assertEqual(self.elf.hdr.e_phentsize, 56)
+        self.assertEqual(self.elf.hdr.e_phnum, 4)
+        self.assertEqual(self.elf.hdr.e_shentsize, 64)
+        self.assertEqual(self.elf.hdr.e_shnum, 38)
+        self.assertEqual(self.elf.hdr.e_shstrndx, 35)
 
     def test_num_section_hdr_entries(self):
         self._test_num_section_hdr_entries(38)