minor tweak in output formatting for symbols
[pyelftools.git] / scripts / readelf.py
old mode 100644 (file)
new mode 100755 (executable)
index e6addb7..c7f0a8f
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 #-------------------------------------------------------------------------------
 # readelf.py
 #
@@ -20,11 +21,14 @@ except ImportError:
 from elftools.common.exceptions import ELFError
 from elftools.elf.elffile import ELFFile
 from elftools.elf.segments import InterpSegment
+from elftools.elf.sections import SymbolTableSection
 from elftools.elf.descriptions import (
     describe_ei_class, describe_ei_data, describe_ei_version,
     describe_ei_osabi, describe_e_type, describe_e_machine,
     describe_e_version_numeric, describe_p_type, describe_p_flags,
-
+    describe_sh_type, describe_sh_flags,
+    describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
+    describe_symbol_shndx,
     )
 
 
@@ -95,11 +99,13 @@ class ReadElf(object):
         self._emitline()
         elfheader = self.elffile.header
         self._emitline('Elf file type is %s' %
-                describe_e_type(elfheader['e_type']))
+            describe_e_type(elfheader['e_type']))
         self._emitline('Entry point is %s' %
-                self._format_hex(elfheader['e_entry']))
+            self._format_hex(elfheader['e_entry']))
+        # readelf weirness - why isn't e_phoff printed as hex? (for section
+        # headers, it is...)
         self._emitline('There are %s program headers, starting at offset %s' % (
-                elfheader['e_phnum'], elfheader['e_phoff']))
+            elfheader['e_phnum'], elfheader['e_phoff']))
 
         self._emitline('\nProgram headers:')
 
@@ -165,8 +171,88 @@ class ReadElf(object):
 
             self._emitline('')
 
+    def display_section_headers(self):
+        """ Display the ELF section headers
+        """
+        elfheader = self.elffile.header
+        self._emitline('There are %s section headers, starting at offset %s' % (
+            elfheader['e_shnum'], self._format_hex(elfheader['e_shoff'])))
+
+        self._emitline('\nSection header%s:' % (
+            's' if elfheader['e_shnum'] > 1 else ''))
+
+        # Different formatting constraints of 32-bit and 64-bit addresses
+        #
+        if self.elffile.elfclass == 32:
+            self._emitline('  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al')
+        else:
+            self._emitline('  [Nr] Name              Type             Address           Offset')
+            self._emitline('       Size              EntSize          Flags  Link  Info  Align')
+
+        # Now the entries
+        #
+        for nsec, section in enumerate(self.elffile.iter_sections()):
+            self._emit('  [%2u] %-17.17s %-15.15s ' % (
+                nsec, section.name, describe_sh_type(section['sh_type'])))
 
+            if self.elffile.elfclass == 32:
+                self._emitline('%s %s %s %s %3s %2s %3s %2s' % (
+                    self._format_hex(section['sh_addr'], fieldsize=8, lead0x=False),
+                    self._format_hex(section['sh_offset'], fieldsize=6, lead0x=False),
+                    self._format_hex(section['sh_size'], fieldsize=6, lead0x=False),
+                    self._format_hex(section['sh_entsize'], fieldsize=2, lead0x=False),
+                    describe_sh_flags(section['sh_flags']),
+                    section['sh_link'], section['sh_info'],
+                    section['sh_addralign']))
+            else: # 64
+                self._emitline(' %s  %s' % (
+                    self._format_hex(section['sh_addr'], fullhex=True, lead0x=False),
+                    self._format_hex(section['sh_offset'],
+                        fieldsize=16 if section['sh_offset'] > 0xffffffff else 8,
+                        lead0x=False)))
+                self._emitline('       %s  %s %3s      %2s   %3s     %s' % (
+                    self._format_hex(section['sh_size'], fullhex=True, lead0x=False),
+                    self._format_hex(section['sh_entsize'], fullhex=True, lead0x=False),
+                    describe_sh_flags(section['sh_flags']),
+                    section['sh_link'], section['sh_info'],
+                    section['sh_addralign']))
+
+        self._emitline('Key to Flags:')
+        self._emitline('  W (write), A (alloc), X (execute), M (merge), S (strings)')
+        self._emitline('  I (info), L (link order), G (group), x (unknown)')
+        self._emitline('  O (extra OS processing required) o (OS specific), p (processor specific)')
+
+    def display_symbol_tables(self):
+        """ Display the symbol tables contained in the file
+        """
+        for section in self.elffile.iter_sections():
+            if not isinstance(section, SymbolTableSection):
+                continue
+
+            if section['sh_entsize'] == 0:
+                self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
+                    section.name))
+                continue
+
+            self._emitline("\nSymbol table '%s' contains %s entries:" % (
+                section.name, section.num_symbols()))
+
+            if self.elffile.elfclass == 32:
+                self._emitline('   Num:    Value  Size Type    Bind   Vis      Ndx Name')
+            else: # 64
+                self._emitline('   Num:    Value          Size Type    Bind   Vis      Ndx Name')
 
+            for nsym, symbol in enumerate(section.iter_symbols()):
+                # symbol names are truncated to 25 chars, similarly to readelf
+                self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
+                    nsym,
+                    self._format_hex(symbol['st_value'], fullhex=True, lead0x=False),
+                    symbol['st_size'],
+                    describe_symbol_type(symbol['st_info']['type']),
+                    describe_symbol_bind(symbol['st_info']['bind']),
+                    describe_symbol_visibility(symbol['st_other']['visibility']),
+                    describe_symbol_shndx(symbol['st_shndx']),
+                    symbol.name))
         
     def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True):
         """ Format an address into a hexadecimal string.
@@ -211,9 +297,10 @@ def main():
     with open(args[0], 'rb') as file:
         try:
             readelf = ReadElf(file, sys.stdout)
-            readelf.display_file_header()
-            print '----'
-            readelf.display_program_headers()
+            #readelf.display_file_header()
+            #readelf.display_program_headers()
+            #readelf.display_section_headers()
+            readelf.display_symbol_tables()
         except ELFError as ex:
             sys.stderr.write('ELF read error: %s\n' % ex)
             sys.exit(1)