* start adding debug_dump=info to readelf.py
authoreliben <devnull@localhost>
Sun, 2 Oct 2011 11:47:12 +0000 (13:47 +0200)
committereliben <devnull@localhost>
Sun, 2 Oct 2011 11:47:12 +0000 (13:47 +0200)
* adding support to dwarf code for the above

elftools/dwarf/compileunit.py
elftools/dwarf/die.py
scripts/readelf.py

index 6e02e333d63a41e2fb073fd57e6371ea0525f52a..fda4980d9f437aab889cd1b7c93a23658b0c790a 100644 (file)
@@ -55,7 +55,12 @@ class CompileUnit(object):
         
         # A list of DIEs belonging to this CU. Lazily parsed.
         self._dielist = []
-        
+    
+    def dwarf_format(self):
+        """ Get the DWARF format (32 or 64) for this CU
+        """
+        return self.structs.dwarf_format
+    
     def get_abbrev_table(self):
         """ Get the abbreviation table (AbbrevTable object) for this CU
         """
@@ -70,6 +75,13 @@ class CompileUnit(object):
         """
         return self._get_DIE(0)
     
+    def iter_DIEs(self):
+        """ Iterate over all the DIEs in the CU, in order of their appearance.
+            Note that null DIEs will also be returned.
+        """
+        self._parse_DIEs()
+        return iter(self._dielist)
+    
     #------ PRIVATE ------#
     
     def __getitem__(self, name):
@@ -80,8 +92,7 @@ class CompileUnit(object):
     def _get_DIE(self, index):
         """ Get the DIE at the given index 
         """
-        if len(self._dielist) == 0:
-            self._parse_DIEs()
+        self._parse_DIEs()
         return self._dielist[index]
     
     def _parse_DIEs(self):
@@ -90,6 +101,9 @@ class CompileUnit(object):
             Also set the child/sibling/parent links in the DIEs according
             (unflattening the prefix-order of the DIE tree).
         """
+        if len(self._dielist) > 0:
+            return
+            
         # Compute the boundary (one byte past the bounds) of this CU in the 
         # stream
         cu_boundary = ( self.cu_offset + 
index f49efc9deedc3bfe25cc3935664a6dd377d2cfab..ad818920c7c9650ee2e81c0ce710e9b218f77db8 100644 (file)
@@ -54,6 +54,11 @@ class DIE(object):
             
             has_children:
                 Specifies whether this DIE has children
+            
+            abbrev_code:
+                The abbreviation code pointing to an abbreviation entry (not
+                that this is for informational pusposes only - this object 
+                interacts with its abbreviation table transparently).
         
         See also the public methods.
     """
@@ -73,6 +78,7 @@ class DIE(object):
         self.attributes = OrderedDict()
         self.tag = None
         self.has_children = None
+        self.abbrev_code = None
         self.size = 0
         self._children = []
         self._parent = None
@@ -137,16 +143,17 @@ class DIE(object):
         # Note: here and elsewhere, preserve_stream_pos is used on operations
         # that manipulate the stream by reading data from it.
         #
-        abbrev_code = struct_parse(
+        self.abbrev_code = struct_parse(
             structs.Dwarf_uleb128(''), self.stream, self.offset)
         
         # This may be a null entry
-        if abbrev_code == 0:
+        if self.abbrev_code == 0:
             self.size = self.stream.tell() - self.offset
             return
         
         with preserve_stream_pos(self.stream):
-            abbrev_decl = self.cu.get_abbrev_table().get_abbrev(abbrev_code)
+            abbrev_decl = self.cu.get_abbrev_table().get_abbrev(
+                self.abbrev_code)
         self.tag = abbrev_decl['tag']
         self.has_children = abbrev_decl.has_children()
         
index d103643f12447dd1906815861a74f34b5dffc592..b1fd9c43bf421d8339ab5b679a2075c74d65d191 100755 (executable)
@@ -33,6 +33,7 @@ from elftools.elf.descriptions import (
     describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
     describe_symbol_shndx, describe_reloc_type,
     )
+from elftools.dwarf.dwarfinfo import DWARFInfo, DebugSectionLocator
 
 
 class ReadElf(object):
@@ -47,6 +48,9 @@ class ReadElf(object):
         """
         self.elffile = ELFFile(file)
         self.output = output
+        
+        # Lazily initialized if a debug dump is requested
+        self._dwarfinfo = None
 
     def display_file_header(self):
         """ Display the ELF file header
@@ -406,6 +410,18 @@ class ReadElf(object):
         else:
             self._emitline()
 
+    def display_debug_dump(self, section_name):
+        """ Dump a DWARF section
+        """
+        self._init_dwarfinfo()
+        if self._dwarfinfo is None:
+            return
+        
+        if section_name == 'info':
+            self._dump_debug_info()
+        else:
+            self._emitline('debug dump not yet supported for "%s"' % section_name)
+
     def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True):
         """ Format an address into a hexadecimal string.
 
@@ -456,6 +472,52 @@ class ReadElf(object):
                     self._emitline('  Note: This section has relocations against it, but these have NOT been applied to this dump.')
                     return
 
+    def _init_dwarfinfo(self):
+        """ Initialize the DWARF info contained in the file and assign it to
+            self._dwarfinfo.
+            Leave self._dwarfinfo at None if no DWARF info was found in the file
+        """
+        if self._dwarfinfo is not None:
+            return
+        
+        if self.elffile.has_dwarf_info():
+            self._dwarfinfo = self.elffile.get_dwarf_info()
+        else:
+            self._dwarfinfo = None
+
+    def _dump_debug_info(self):
+        """ Dump the debugging info section.
+        """
+        # Offset of the .debug_info section in the stream
+        section_offset = self._dwarfinfo.debug_info_loc.offset
+        
+        for cu in self._dwarfinfo.iter_CUs():
+            self._emitline('  Compilation Unit @ offset %s' %
+                self._format_hex(cu.cu_offset - section_offset))
+            self._emitline('   Length:        %s (%s)' % (
+                self._format_hex(cu['unit_length']),
+                '%s-bit' % cu.dwarf_format()))
+            self._emitline('   Version:       %s' % cu['version']),
+            self._emitline('   Abbrev Offset: %s' % cu['debug_abbrev_offset']),
+            self._emitline('   Pointer Size:  %s' % cu['address_size'])
+            
+            # The nesting depth of each DIE within the tree of DIEs must be 
+            # displayed. To implement this, a counter is incremented each time
+            # the current DIE has children, and decremented when a null die is
+            # encountered. Due to the way the DIE tree is serialized, this will
+            # correctly reflect the nesting depth
+            #
+            die_depth = 0
+            for die in cu.iter_DIEs():
+                if die.is_null():
+                    die_depth -= 1
+                    continue
+                self._emitline(' <%s><%x>: Abbrev Number: %s' % (
+                    die_depth, die.offset - section_offset, die.abbrev_code))
+                
+                if die.has_children:
+                    die_depth += 1
+
     def _emit(self, s=''):
         """ Emit an object to output
         """
@@ -506,6 +568,9 @@ def main():
     optparser.add_option('-p', '--string-dump',
             action='store', dest='show_string_dump', metavar='<number|name>',
             help='Dump the contents of section <number|name> as strings')
+    optparser.add_option('--debug-dump',
+            action='store', dest='debug_dump_section', metavar='<section>',
+            help='Display the contents of DWARF debug sections')
 
     options, args = optparser.parse_args()
 
@@ -539,6 +604,8 @@ def main():
                 readelf.display_hex_dump(options.show_hex_dump)
             if options.show_string_dump:
                 readelf.display_string_dump(options.show_string_dump)
+            if options.debug_dump_section:
+                readelf.display_debug_dump(options.debug_dump_section)
         except ELFError as ex:
             sys.stderr.write('ELF error: %s\n' % ex)
             sys.exit(1)