from .abbrevtable import AbbrevTable
from .lineprogram import LineProgram
from .callframe import CallFrameInfo
+from .locationlists import LocationLists
# Describes a debug section
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):
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------------
+import os
from collections import namedtuple
from ..common.utils import struct_parse
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 = []
# 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
--- /dev/null
+#-------------------------------------------------------------------------------
+# 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)
+
+
+
+
+
+
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)
+
+