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