added Symbol decoding from a symbol table section
authorEli Bendersky <eliben@gmail.com>
Fri, 9 Sep 2011 03:02:47 +0000 (06:02 +0300)
committerEli Bendersky <eliben@gmail.com>
Fri, 9 Sep 2011 03:02:47 +0000 (06:02 +0300)
elftools/elf/elffile.py
elftools/elf/enums.py
elftools/elf/sections.py
elftools/elf/structs.py
z.py

index dc1b246d2d9c02f8841d6160b49d9544708aba30..b0e2b674ba522a428ab352b4b6dcfb00f4c07570 100644 (file)
@@ -150,6 +150,7 @@ class ELFFile(object):
         strtab_section = self.get_section(linked_strtab_index)
         return SymbolTableSection(
             section_header, name, self.stream,
+            elfstructs=self.structs,
             stringtable=strtab_section)
 
     def _get_segment_header(self, n):
index 31647ac61df1e3df6ff763e7fed36b11f6e15c63..1cd5a9b6c363cf62b10eec2534fce883d733cefa 100644 (file)
@@ -105,3 +105,30 @@ ENUM_P_TYPE = dict(
     PT_GNU_RELRO=0x6474e552,
 )
 
+# st_info bindings in the symbol header
+ENUM_ST_INFO_BIND = dict(
+    STB_LOCAL=0,
+    STB_GLOBAL=1,
+    STB_WEAK=2,
+    STB_NUM=3,
+    STB_LOOS=10,
+    STB_HIOS=12,
+    STB_LOPROC=13,
+    STB_HIPROC=15,
+)
+
+# st_info type in the symbol header
+ENUM_ST_INFO_TYPE = dict(
+    STT_NOTYPE=0,
+    STT_OBJECT=1,
+    STT_FUNC=2,
+    STT_SECTION=3,
+    STT_FILE=4,
+    STT_COMMON=5,
+    STT_TLS=6,
+    STT_NUM=7,
+    STT_LOOS=10,
+    STT_HIOS=12,
+    STT_LOPROC=13,
+    STT_HIPROC=15,
+)
index 04410f30c720d6b254af4e86c77ef13ec23b44a9..fd11875ff72d6d0145037e23ed4a36cc968e7ffa 100644 (file)
@@ -55,6 +55,50 @@ class SymbolTableSection(Section):
     """ ELF symbol table section. Has an associated StringTableSection that's
         passed in the constructor.
     """
-    def __init__(self, header, name, stream, stringtable):
+    def __init__(self, header, name, stream, elfstructs, stringtable):
         super(SymbolTableSection, self).__init__(header, name, stream)
+        self.elfstructs = elfstructs
         self.stringtable = stringtable
+        elf_assert(self['sh_entsize'] > 0,
+                'Expected entry size of section %s to be > 0' % name)
+        elf_assert(self['sh_size'] % self['sh_entsize'] == 0,
+                'Expected section size to be a multiple of entry size in section %s' % name)
+
+    def num_symbols(self):
+        """ Number of symbols in the table
+        """
+        return self['sh_size'] // self['sh_entsize']
+        
+    def get_symbol(self, n):
+        """ Get the symbol at index #n from the table (Symbol object)
+        """
+        # Grab the symbol's entry from the stream
+        entry_offset = self['sh_offset'] + n * self['sh_entsize']
+        entry = struct_parse(
+            self.elfstructs.Elf_Sym,
+            self.stream,
+            stream_pos=entry_offset)
+        # Find the symbol name in the associated string table
+        name = self.stringtable.get_string(entry['st_name'])
+        return Symbol(entry, name)
+
+    def iter_symbols(self):
+        """ Yield all the symbols in the table
+        """
+        for i in range(self.num_symbols()):
+            yield self.get_symbol(i)
+
+
+class Symbol(object):
+    """ Symbol object - representing a single symbol entry from a symbol table
+        section.
+    """
+    def __init__(self, entry, name):
+        self.entry = entry
+        self.name = name
+
+    def __getitem__(self, name):
+        """ Implement dict-like access to entries
+        """
+        return self.entry[name]
+
index c628c931db172d75c9934445ae23345e4d4e025e..21ea2b7c996b6b64b3b0b434ceffd775cf739e06 100644 (file)
@@ -11,7 +11,7 @@ from ..construct import (
     UBInt8, UBInt16, UBInt32, UBInt64,
     ULInt8, ULInt16, ULInt32, ULInt64,
     SBInt32, SLInt32, SBInt64, SLInt64,
-    Struct, Array, Enum, Padding,
+    Struct, Array, Enum, Padding, BitStruct, BitField,
     )
 
 from .enums import *
@@ -130,19 +130,22 @@ class ELFStructs(object):
         )
     
     def _create_sym(self):
+        st_info_struct = BitStruct('st_info',
+            Enum(BitField('bind', 4), **ENUM_ST_INFO_BIND),
+            Enum(BitField('type', 4), **ENUM_ST_INFO_TYPE))
         if self.elfclass == 32:
             self.Elf_Sym = Struct('Elf_Sym',
                 self.Elf_word('st_name'),
                 self.Elf_addr('st_value'),
                 self.Elf_word('st_size'),
-                self.Elf_byte('st_info'),
+                st_info_struct,
                 self.Elf_byte('st_other'),
                 self.Elf_half('st_shndx'),
             )
         else:
             self.Elf_Sym = Struct('Elf_Sym',
                 self.Elf_word('st_name'),
-                self.Elf_byte('st_info'),
+                st_info_struct,
                 self.Elf_byte('st_other'),
                 self.Elf_half('st_shndx'),
                 self.Elf_addr('st_value'),
diff --git a/z.py b/z.py
index fc295e7b941f9d3bad1f50b7a75410c3c40b1e5a..dd2ab54fd09876b3b3d22995d5116a0e11fb01b4 100644 (file)
--- a/z.py
+++ b/z.py
@@ -22,6 +22,12 @@ for sec in efile.iter_sections():
 for seg in efile.iter_segments():
     print seg['p_type'], seg['p_offset']
 
+for sec in efile.iter_sections():
+    if isinstance(sec, SymbolTableSection):
+        print 'symbol table "%s ~~~"' % sec.name
+        for sym in sec.iter_symbols():
+            print '%-26s %s %s' % (sym.name, sym['st_info']['type'], sym['st_info']['bind'])
+
 
 #~ print 'num', efile.num_sections()
 #~ sec = efile.get_section(39)