1#-------------------------------------------------------------------------------
2# elftools example: dwarf_pubnames_types.py
3#
4# Dump the contents of .debug_pubnames and .debug_pubtypes sections from the
5# ELF file.
6#
7# Note: sample_exe64.elf doesn't have a .debug_pubtypes section.
8#
9# Vijay Ramasami (rvijayc@gmail.com)
10# This code is in the public domain
11#-------------------------------------------------------------------------------
12from __future__ import print_function
13import sys
14
15# If pyelftools is not installed, the example can also run from the root or
16# examples/ dir of the source distribution.
17sys.path[0:0] = ['.', '..']
18
19from elftools.elf.elffile import ELFFile
20from elftools.common.py3compat import bytes2str
21
22def process_file(filename):
23    print('Processing file:', filename)
24    with open(filename, 'rb') as f:
25        elffile = ELFFile(f)
26
27        if not elffile.has_dwarf_info():
28            print('  file has no DWARF info')
29            return
30
31        # get_dwarf_info returns a DWARFInfo context object, which is the
32        # starting point for all DWARF-based processing in pyelftools.
33        dwarfinfo = elffile.get_dwarf_info()
34
35        # get .debug_pubtypes section.
36        pubnames = dwarfinfo.get_pubnames()
37        if pubnames is None:
38            print('ERROR: No .debug_pubnames section found in ELF.')
39        else:
40            print('%d entries found in .debug_pubnames' % len(pubnames))
41
42            print('Trying pubnames example ...')
43            for name, entry in pubnames.items():
44                print('%s: cu_ofs = %d, die_ofs = %d' %
45                        (name, entry.cu_ofs, entry.die_ofs))
46
47                # get the actual CU/DIE that has this information.
48                print('Fetching the actual die for %s ...' % name)
49                for cu in dwarfinfo.iter_CUs():
50                    if cu.cu_offset == entry.cu_ofs:
51                        for die in cu.iter_DIEs():
52                            if die.offset == entry.die_ofs:
53                                print('Die Name: %s' %
54                                        bytes2str(die.attributes['DW_AT_name'].value))
55
56            # dump all entries in .debug_pubnames section.
57            print('Dumping .debug_pubnames table ...')
58            print('-' * 66)
59            print('%50s%8s%8s' % ('Symbol', 'CU_OFS', 'DIE_OFS'))
60            print('-' * 66)
61            for (name, entry) in pubnames.items():
62                print('%50s%8d%8d' % (name, entry.cu_ofs, entry.die_ofs))
63            print('-' * 66)
64
65        # get .debug_pubtypes section.
66        pubtypes = dwarfinfo.get_pubtypes()
67        if pubtypes is None:
68            print('ERROR: No .debug_pubtypes section found in ELF')
69        else:
70            print('%d entries found in .debug_pubtypes' % len(pubtypes))
71
72            for name, entry in pubtypes.items():
73                print('%s: cu_ofs = %d, die_ofs = %d' %
74                        (name, entry.cu_ofs, entry.die_ofs))
75
76                # get the actual CU/DIE that has this information.
77                print('Fetching the actual die for %s ...' % name)
78                for cu in dwarfinfo.iter_CUs():
79                    if cu.cu_offset == entry.cu_ofs:
80                        for die in cu.iter_DIEs():
81                            if die.offset == entry.die_ofs:
82                                print('Die Name: %s' %
83                                        bytes2str(die.attributes['DW_AT_name'].value))
84                                die_info_rec(die)
85
86            # dump all entries in .debug_pubtypes section.
87            print('Dumping .debug_pubtypes table ...')
88            print('-' * 66)
89            print('%50s%8s%8s' % ('Symbol', 'CU_OFS', 'DIE_OFS'))
90            print('-' * 66)
91            for (name, entry) in pubtypes.items():
92                print('%50s%8d%8d' % (name, entry.cu_ofs, entry.die_ofs))
93            print('-' * 66)
94
95
96def die_info_rec(die, indent_level='    '):
97    """ A recursive function for showing information about a DIE and its
98        children.
99    """
100    print(indent_level + 'DIE tag=%s, attrs=' % die.tag)
101    for name, val in die.attributes.items():
102        print(indent_level + '  %s = %s' % (name, val))
103    child_indent = indent_level + '  '
104    for child in die.iter_children():
105        die_info_rec(child, child_indent)
106
107
108if __name__ == '__main__':
109    if sys.argv[1] == '--test':
110        process_file(sys.argv[2])
111        sys.exit(0)
112
113    if len(sys.argv) < 2:
114        print('Expected usage: {0} <executable>'.format(sys.argv[0]))
115        sys.exit(1)
116    process_file(sys.argv[1])
117