1 #-------------------------------------------------------------------------------
2 # elftools example: dwarf_decode_address.py
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.
7 # Eli Bendersky (eliben@gmail.com)
8 # This code is in the public domain
9 #-------------------------------------------------------------------------------
10 from __future__ import print_function
13 # If elftools is not installed, maybe we're running from the root or examples
14 # dir of the source distribution
18 sys.path.extend(['.', '..'])
20 from elftools.common.py3compat import maxint, bytes2str
21 from elftools.elf.elffile import ELFFile
24 def process_file(filename, address):
25 print('Processing file:', filename)
26 with open(filename, 'rb') as f:
29 if not elffile.has_dwarf_info():
30 print(' file has no DWARF info')
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()
37 funcname = decode_funcname(dwarfinfo, address)
38 file, line = decode_file_line(dwarfinfo, address)
40 print('Function:', bytes2str(funcname))
41 print('File:', bytes2str(file))
45 def 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
48 # this simplifies things by disregarding subprograms that may have
49 # split address ranges.
50 for CU in dwarfinfo.iter_CUs():
51 for DIE in CU.iter_DIEs():
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
63 def 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)
70 for entry in lineprog.get_entries():
71 # We're interested in those entries where a new state is assigned
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
78 prevaddr = state.address
82 if __name__ == '__main__':
83 for filename in sys.argv[1:]:
84 # For testing we use a hardcoded address.
85 process_file(filename, 0x400503)