blob: 55b31c7dfbb05ae909d79ff02f6f3eafbe3d5397 [file] [log] [blame]
Eli Benderskyeb3dc082012-07-05 06:32:09 +03001#-------------------------------------------------------------------------------
2# elftools example: dwarf_decode_address.py
3#
4# Decode an address in an ELF file to find out which function it belongs to
5# and from which filename/line it comes in the original source file.
6#
7# Eli Bendersky (eliben@gmail.com)
8# This code is in the public domain
9#-------------------------------------------------------------------------------
10from __future__ import print_function
11import sys
12
Eli Benderskycc1e5572013-04-09 21:25:54 -070013# If pyelftools is not installed, the example can also run from the root or
14# examples/ dir of the source distribution.
15sys.path[0:0] = ['.', '..']
Eli Benderskyeb3dc082012-07-05 06:32:09 +030016
17from elftools.common.py3compat import maxint, bytes2str
18from elftools.elf.elffile import ELFFile
19
20
21def process_file(filename, address):
22 print('Processing file:', filename)
23 with open(filename, 'rb') as f:
24 elffile = ELFFile(f)
25
26 if not elffile.has_dwarf_info():
27 print(' file has no DWARF info')
28 return
29
30 # get_dwarf_info returns a DWARFInfo context object, which is the
31 # starting point for all DWARF-based processing in pyelftools.
32 dwarfinfo = elffile.get_dwarf_info()
33
34 funcname = decode_funcname(dwarfinfo, address)
35 file, line = decode_file_line(dwarfinfo, address)
36
37 print('Function:', bytes2str(funcname))
38 print('File:', bytes2str(file))
39 print('Line:', line)
40
41
42def decode_funcname(dwarfinfo, address):
43 # Go over all DIEs in the DWARF information, looking for a subprogram
44 # entry with an address range that includes the given address. Note that
Eli Benderskydd71c432013-04-08 06:38:57 -070045 # this simplifies things by disregarding subprograms that may have
Eli Benderskyeb3dc082012-07-05 06:32:09 +030046 # split address ranges.
47 for CU in dwarfinfo.iter_CUs():
48 for DIE in CU.iter_DIEs():
49 try:
50 if DIE.tag == 'DW_TAG_subprogram':
51 lowpc = DIE.attributes['DW_AT_low_pc'].value
52 highpc = DIE.attributes['DW_AT_high_pc'].value
53 if lowpc <= address <= highpc:
54 return DIE.attributes['DW_AT_name'].value
55 except KeyError:
56 continue
57 return None
58
59
60def decode_file_line(dwarfinfo, address):
61 # Go over all the line programs in the DWARF information, looking for
62 # one that describes the given address.
63 for CU in dwarfinfo.iter_CUs():
64 # First, look at line programs to find the file/line for the address
65 lineprog = dwarfinfo.line_program_for_CU(CU)
66 prevaddr = maxint
67 for entry in lineprog.get_entries():
68 # We're interested in those entries where a new state is assigned
69 state = entry.state
70 if state is not None and not state.end_sequence:
71 if prevaddr <= address <= state.address:
72 filename = lineprog['file_entry'][state.file - 1].name
73 line = state.line
74 return filename, line
75 prevaddr = state.address
76 return None, None
77
78
79if __name__ == '__main__':
80 for filename in sys.argv[1:]:
81 # For testing we use a hardcoded address.
82 process_file(filename, 0x400503)
83