blob: 4b9ecdc3f5b8679a146270b65e21401721681ba2 [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
13# If elftools is not installed, maybe we're running from the root or examples
14# dir of the source distribution
15try:
16 import elftools
17except ImportError:
Eli Benderskydd71c432013-04-08 06:38:57 -070018 sys.path[0:0] = ['.', '..']
Eli Benderskyeb3dc082012-07-05 06:32:09 +030019
20from elftools.common.py3compat import maxint, bytes2str
21from elftools.elf.elffile import ELFFile
22
23
24def process_file(filename, address):
25 print('Processing file:', filename)
26 with open(filename, 'rb') as f:
27 elffile = ELFFile(f)
28
29 if not elffile.has_dwarf_info():
30 print(' file has no DWARF info')
31 return
32
33 # get_dwarf_info returns a DWARFInfo context object, which is the
34 # starting point for all DWARF-based processing in pyelftools.
35 dwarfinfo = elffile.get_dwarf_info()
36
37 funcname = decode_funcname(dwarfinfo, address)
38 file, line = decode_file_line(dwarfinfo, address)
39
40 print('Function:', bytes2str(funcname))
41 print('File:', bytes2str(file))
42 print('Line:', line)
43
44
45def decode_funcname(dwarfinfo, address):
46 # Go over all DIEs in the DWARF information, looking for a subprogram
47 # entry with an address range that includes the given address. Note that
Eli Benderskydd71c432013-04-08 06:38:57 -070048 # this simplifies things by disregarding subprograms that may have
Eli Benderskyeb3dc082012-07-05 06:32:09 +030049 # split address ranges.
50 for CU in dwarfinfo.iter_CUs():
51 for DIE in CU.iter_DIEs():
52 try:
53 if DIE.tag == 'DW_TAG_subprogram':
54 lowpc = DIE.attributes['DW_AT_low_pc'].value
55 highpc = DIE.attributes['DW_AT_high_pc'].value
56 if lowpc <= address <= highpc:
57 return DIE.attributes['DW_AT_name'].value
58 except KeyError:
59 continue
60 return None
61
62
63def decode_file_line(dwarfinfo, address):
64 # Go over all the line programs in the DWARF information, looking for
65 # one that describes the given address.
66 for CU in dwarfinfo.iter_CUs():
67 # First, look at line programs to find the file/line for the address
68 lineprog = dwarfinfo.line_program_for_CU(CU)
69 prevaddr = maxint
70 for entry in lineprog.get_entries():
71 # We're interested in those entries where a new state is assigned
72 state = entry.state
73 if state is not None and not state.end_sequence:
74 if prevaddr <= address <= state.address:
75 filename = lineprog['file_entry'][state.file - 1].name
76 line = state.line
77 return filename, line
78 prevaddr = state.address
79 return None, None
80
81
82if __name__ == '__main__':
83 for filename in sys.argv[1:]:
84 # For testing we use a hardcoded address.
85 process_file(filename, 0x400503)
86