From 0fc47afb007485d0741320b87695a7049469bb46 Mon Sep 17 00:00:00 2001 From: eliben Date: Sun, 2 Oct 2011 13:47:12 +0200 Subject: [PATCH] * start adding debug_dump=info to readelf.py * adding support to dwarf code for the above --- elftools/dwarf/compileunit.py | 20 +++++++++-- elftools/dwarf/die.py | 13 +++++-- scripts/readelf.py | 67 +++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 6 deletions(-) diff --git a/elftools/dwarf/compileunit.py b/elftools/dwarf/compileunit.py index 6e02e33..fda4980 100644 --- a/elftools/dwarf/compileunit.py +++ b/elftools/dwarf/compileunit.py @@ -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 + diff --git a/elftools/dwarf/die.py b/elftools/dwarf/die.py index f49efc9..ad81892 100644 --- a/elftools/dwarf/die.py +++ b/elftools/dwarf/die.py @@ -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() diff --git a/scripts/readelf.py b/scripts/readelf.py index d103643..b1fd9c4 100755 --- a/scripts/readelf.py +++ b/scripts/readelf.py @@ -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='', help='Dump the contents of section as strings') + optparser.add_option('--debug-dump', + action='store', dest='debug_dump_section', metavar='
', + 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) -- 2.30.2