1 #-------------------------------------------------------------------------------
2 # elftools example: dwarf_location_info.py
4 # Examine DIE entries which have either location list values or location
5 # expression values and decode that information.
7 # Location information can either be completely contained within a DIE
8 # (using 'DW_FORM_exprloc' in DWARFv4 or 'DW_FORM_block1' in earlier
9 # versions) or be a reference to a location list contained within
10 # the .debug_loc section (using 'DW_FORM_sec_offset' in DWARFv4 or
11 # 'DW_FORM_data4' / 'DW_FORM_data8' in earlier versions).
13 # The LocationParser object parses the DIE attributes and handles both
16 # The directory 'test/testfiles_for_location_info' contains test files with
17 # location information represented in both DWARFv4 and DWARFv2 forms.
19 # Eli Bendersky (eliben@gmail.com)
20 # This code is in the public domain
21 #-------------------------------------------------------------------------------
22 from __future__
import print_function
25 # If pyelftools is not installed, the example can also run from the root or
26 # examples/ dir of the source distribution.
27 sys
.path
[0:0] = ['.', '..']
29 from elftools
.elf
.elffile
import ELFFile
30 from elftools
.dwarf
.descriptions
import (
31 describe_DWARF_expr
, set_global_machine_arch
)
32 from elftools
.dwarf
.locationlists
import (
33 LocationEntry
, LocationExpr
, LocationParser
)
35 def process_file(filename
):
36 print('Processing file:', filename
)
37 with
open(filename
, 'rb') as f
:
40 if not elffile
.has_dwarf_info():
41 print(' file has no DWARF info')
44 # get_dwarf_info returns a DWARFInfo context object, which is the
45 # starting point for all DWARF-based processing in pyelftools.
46 dwarfinfo
= elffile
.get_dwarf_info()
48 # The location lists are extracted by DWARFInfo from the .debug_loc
49 # section, and returned here as a LocationLists object.
50 location_lists
= dwarfinfo
.location_lists()
52 # This is required for the descriptions module to correctly decode
53 # register names contained in DWARF expressions.
54 set_global_machine_arch(elffile
.get_machine_arch())
56 # Create a LocationParser object that parses the DIE attributes and
57 # creates objects representing the actual location information.
58 loc_parser
= LocationParser(location_lists
)
60 for CU
in dwarfinfo
.iter_CUs():
61 # DWARFInfo allows to iterate over the compile units contained in
62 # the .debug_info section. CU is a CompileUnit object, with some
63 # computed attributes (such as its offset in the section) and
64 # a header which conforms to the DWARF standard. The access to
65 # header elements is, as usual, via item-lookup.
66 print(' Found a compile unit at offset %s, length %s' % (
67 CU
.cu_offset
, CU
['unit_length']))
69 # A CU provides a simple API to iterate over all the DIEs in it.
70 for DIE
in CU
.iter_DIEs():
71 # Go over all attributes of the DIE. Each attribute is an
72 # AttributeValue object (from elftools.dwarf.die), which we
74 for attr
in DIE
.attributes
.values():
75 # Check if this attribute contains location information
76 if loc_parser
.attribute_has_location(attr
, CU
['version']):
77 print(' DIE %s. attr %s.' % (DIE
.tag
, attr
.name
))
78 loc
= loc_parser
.parse_from_attribute(attr
,
80 # We either get a list (in case the attribute is a
81 # reference to the .debug_loc section) or a LocationExpr
82 # object (in case the attribute itself contains location
84 if isinstance(loc
, LocationExpr
):
86 describe_DWARF_expr(loc
.loc_expr
,
87 dwarfinfo
.structs
, CU
.cu_offset
)))
88 elif isinstance(loc
, list):
89 print(show_loclist(loc
,
93 def show_loclist(loclist
, dwarfinfo
, indent
, cu_offset
):
94 """ Display a location list nicely, decoding the DWARF expressions
98 for loc_entity
in loclist
:
99 if isinstance(loc_entity
, LocationEntry
):
100 d
.append('%s <<%s>>' % (
102 describe_DWARF_expr(loc_entity
.loc_expr
, dwarfinfo
.structs
, cu_offset
)))
104 d
.append(str(loc_entity
))
105 return '\n'.join(indent
+ s
for s
in d
)
107 if __name__
== '__main__':
108 if sys
.argv
[1] == '--test':
109 for filename
in sys
.argv
[2:]:
110 process_file(filename
)