3f5108ec3245f611368ca0ef420d66318f95204c
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 pyelftools is not installed, the example can also run from the root or
14 # examples/ dir of the source distribution.
15 sys
.path
[0:0] = ['.', '..']
17 from elftools
.common
.py3compat
import maxint
, bytes2str
18 from elftools
.elf
.elffile
import ELFFile
21 def process_file(filename
, address
):
22 print('Processing file:', filename
)
23 with
open(filename
, 'rb') as f
:
26 if not elffile
.has_dwarf_info():
27 print(' file has no DWARF info')
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()
34 funcname
= decode_funcname(dwarfinfo
, address
)
35 file, line
= decode_file_line(dwarfinfo
, address
)
37 print('Function:', bytes2str(funcname
))
38 print('File:', bytes2str(file))
42 def 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
45 # this simplifies things by disregarding subprograms that may have
46 # split address ranges.
47 for CU
in dwarfinfo
.iter_CUs():
48 for DIE
in CU
.iter_DIEs():
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
60 def 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
)
67 for entry
in lineprog
.get_entries():
68 # We're interested in those entries where a new state is assigned
69 if entry
.state
is None or entry
.state
.end_sequence
:
71 # Looking for a range of addresses in two consecutive states that
72 # contain the required address.
73 if prevstate
and prevstate
.address
<= address
< entry
.state
.address
:
74 filename
= lineprog
['file_entry'][prevstate
.file - 1].name
77 prevstate
= entry
.state
81 if __name__
== '__main__':
82 if sys
.argv
[1] == '--test':
83 process_file(sys
.argv
[2], 0x400503)
87 print('Expected usage: {0} <address> <executable>'.format(sys
.argv
[0]))
89 addr
= int(sys
.argv
[1], 0)
90 process_file(sys
.argv
[2], addr
)