From: Eli Bendersky Date: Wed, 28 Dec 2011 04:37:16 +0000 (+0200) Subject: location lists kinda working. need more docs & readelf support X-Git-Tag: v0.10~4 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=90a3f6b1027fa3432e09a9aa1846d8dec42c653d;p=pyelftools.git location lists kinda working. need more docs & readelf support --- diff --git a/elftools/dwarf/dwarfinfo.py b/elftools/dwarf/dwarfinfo.py index cc2a7b9..665f4d4 100644 --- a/elftools/dwarf/dwarfinfo.py +++ b/elftools/dwarf/dwarfinfo.py @@ -16,6 +16,7 @@ from .compileunit import CompileUnit from .abbrevtable import AbbrevTable from .lineprogram import LineProgram from .callframe import CallFrameInfo +from .locationlists import LocationLists # Describes a debug section @@ -148,6 +149,12 @@ class DWARFInfo(object): base_structs=self.structs) return cfi.get_entries() + def location_lists(self): + """ Get a LocationLists object representing the .debug_loc section of + the DWARF data, or None if this section doesn't exist. + """ + return LocationLists(self.debug_loc_sec.stream, self.structs) + #------ PRIVATE ------# def _parse_CUs_iter(self): diff --git a/elftools/dwarf/locationlists.py b/elftools/dwarf/locationlists.py index afe12e3..2e08b0d 100644 --- a/elftools/dwarf/locationlists.py +++ b/elftools/dwarf/locationlists.py @@ -6,6 +6,7 @@ # Eli Bendersky (eliben@gmail.com) # This code is in the public domain #------------------------------------------------------------------------------- +import os from collections import namedtuple from ..common.utils import struct_parse @@ -16,14 +17,32 @@ BaseAddressEntry = namedtuple('BaseAddressEntry', 'base_address') class LocationLists(object): + """ A single location list is a Python list consisting of LocationEntry or + BaseAddressEntry objects. + """ def __init__(self, stream, structs): + self.stream = stream + self.structs = structs self._max_addr = 2 ** (self.structs.address_size * 8) - 1 def get_location_list_at_offset(self, offset): - pass + """ Get a location list at the given offset in the section. + """ + self.stream.seek(offset, os.SEEK_SET) + return self._parse_location_list_from_stream() def iter_location_lists(self): - pass + """ Yield all location lists found in the section. + """ + # Just call _parse_location_list_from_stream until the stream ends + self.stream.seek(0, os.SEEK_END) + endpos = self.stream.tell() + + self.stream.seek(0, os.SEEK_SET) + while self.stream.tell() < endpos: + yield self._parse_location_list_from_stream() + + #------ PRIVATE ------# def _parse_location_list_from_stream(self): lst = [] @@ -36,9 +55,18 @@ class LocationLists(object): # End of list - we're done. break elif begin_offset == self._max_addr: - # base + # Base address selection entry + lst.append(BaseAddressEntry(base_address=end_offset)) else: - # entry... - - + # Location list entry + expr_len = struct_parse( + self.structs.Dwarf_uint16(''), self.stream) + loc_expr = [struct_parse(self.structs.Dwarf_uint8(''), + self.stream) + for i in range(expr_len)] + lst.append(LocationEntry( + begin_offset=begin_offset, + end_offset=end_offset, + loc_expr=loc_expr)) + return lst diff --git a/examples/dwarf_location_lists.py b/examples/dwarf_location_lists.py new file mode 100644 index 0000000..266bceb --- /dev/null +++ b/examples/dwarf_location_lists.py @@ -0,0 +1,76 @@ +#------------------------------------------------------------------------------- +# elftools example: dwarf_location_lists.py +# +# Examine DIE entries which have location list values, and decode these +# location lists. +# +# Eli Bendersky (eliben@gmail.com) +# This code is in the public domain +#------------------------------------------------------------------------------- +from __future__ import print_function +import sys + +# If elftools is not installed, maybe we're running from the root or examples +# dir of the source distribution +try: + import elftools +except ImportError: + sys.path.extend(['.', '..']) + +from elftools.elf.elffile import ELFFile + + +def process_file(filename): + print('Processing file:', filename) + with open(filename) as f: + elffile = ELFFile(f) + + if not elffile.has_dwarf_info(): + print(' file has no DWARF info') + return + + # get_dwarf_info returns a DWARFInfo context object, which is the + # starting point for all DWARF-based processing in pyelftools. + dwarfinfo = elffile.get_dwarf_info() + + # The location lists are extracted by DWARFInfo from the .debug_loc + # section, and returned here as a LocationLists object. + location_lists = dwarfinfo.location_lists() + + for CU in dwarfinfo.iter_CUs(): + # DWARFInfo allows to iterate over the compile units contained in + # the .debug_info section. CU is a CompileUnit object, with some + # computed attributes (such as its offset in the section) and + # a header which conforms to the DWARF standard. The access to + # header elements is, as usual, via item-lookup. + print(' Found a compile unit at offset %s, length %s' % ( + CU.cu_offset, CU['unit_length'])) + + # A CU provides a simple API to iterate over all the DIEs in it. + for DIE in CU.iter_DIEs(): + # Go over all attributes of the DIE. Each attribute is an + # AttributeValue object (from elftools.dwarf.die), which we + # can examine. + for attr in DIE.attributes.itervalues(): + if ( attr.name == 'DW_AT_location' and + attr.form in ('DW_FORM_data4', 'DW_FORM_data8')): + # This is a location list. Its value is an offset into + # the .debug_loc section, so we can use the location + # lists object to decode it. + loclist = location_lists.get_location_list_at_offset( + attr.value) + print(' DIE %s. attr %s.\n %s' % ( + DIE.tag, + attr.name, + loclist)) + + +if __name__ == '__main__': + for filename in sys.argv[1:]: + process_file(filename) + + + + + + diff --git a/z.py b/z.py index e5f26b7..f04c4cd 100644 --- a/z.py +++ b/z.py @@ -16,3 +16,13 @@ efile = ELFFile(stream) print 'elfclass', efile.elfclass print '===> %s sections!' % efile.num_sections() print efile.header + +dinfo = efile.get_dwarf_info() +from elftools.dwarf.locationlists import LocationLists +from elftools.dwarf.descriptions import describe_DWARF_expr +llists = LocationLists(dinfo.debug_loc_sec.stream, dinfo.structs) +for li in llists.get_location_list_at_offset(0): + print li + print describe_DWARF_expr(li.loc_expr, dinfo.structs) + +