Eli Bendersky | 1a516a3 | 2011-12-22 15:22:00 +0200 | [diff] [blame] | 1 | #------------------------------------------------------------------------------- |
| 2 | # elftools example: dwarf_die_tree.py |
| 3 | # |
| 4 | # In the .debug_info section, Dwarf Information Entries (DIEs) form a tree. |
| 5 | # pyelftools provides easy access to this tree, as demonstrated here. |
| 6 | # |
| 7 | # Eli Bendersky (eliben@gmail.com) |
| 8 | # This code is in the public domain |
| 9 | #------------------------------------------------------------------------------- |
| 10 | from __future__ import print_function |
| 11 | import sys |
Eli Bendersky | ce5d187 | 2011-12-22 20:03:06 +0200 | [diff] [blame] | 12 | |
| 13 | # If elftools is not installed, maybe we're running from the root or examples |
| 14 | # dir of the source distribution |
| 15 | try: |
| 16 | import elftools |
| 17 | except ImportError: |
Eli Bendersky | dd71c43 | 2013-04-08 06:38:57 -0700 | [diff] [blame^] | 18 | sys.path[0:0] = ['.', '..'] |
Eli Bendersky | ce5d187 | 2011-12-22 20:03:06 +0200 | [diff] [blame] | 19 | |
Eli Bendersky | 79271e9 | 2012-01-27 10:25:47 +0200 | [diff] [blame] | 20 | from elftools.common.py3compat import bytes2str |
Eli Bendersky | 1a516a3 | 2011-12-22 15:22:00 +0200 | [diff] [blame] | 21 | from elftools.elf.elffile import ELFFile |
| 22 | |
| 23 | |
| 24 | def process_file(filename): |
| 25 | print('Processing file:', filename) |
eli.bendersky | 3bd3ecc | 2012-01-11 15:56:41 +0200 | [diff] [blame] | 26 | with open(filename, 'rb') as f: |
Eli Bendersky | 1a516a3 | 2011-12-22 15:22:00 +0200 | [diff] [blame] | 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 | for CU in dwarfinfo.iter_CUs(): |
| 38 | # DWARFInfo allows to iterate over the compile units contained in |
| 39 | # the .debug_info section. CU is a CompileUnit object, with some |
| 40 | # computed attributes (such as its offset in the section) and |
| 41 | # a header which conforms to the DWARF standard. The access to |
| 42 | # header elements is, as usual, via item-lookup. |
| 43 | print(' Found a compile unit at offset %s, length %s' % ( |
| 44 | CU.cu_offset, CU['unit_length'])) |
| 45 | |
| 46 | # Start with the top DIE, the root for this CU's DIE tree |
| 47 | top_DIE = CU.get_top_DIE() |
| 48 | print(' Top DIE with tag=%s' % top_DIE.tag) |
| 49 | |
| 50 | # Each DIE holds an OrderedDict of attributes, mapping names to |
| 51 | # values. Values are represented by AttributeValue objects in |
| 52 | # elftools/dwarf/die.py |
| 53 | # We're interested in the DW_AT_name attribute. Note that its value |
| 54 | # is usually a string taken from the .debug_string section. This |
| 55 | # is done transparently by the library, and such a value will be |
| 56 | # simply given as a string. |
| 57 | name_attr = top_DIE.attributes['DW_AT_name'] |
Eli Bendersky | 79271e9 | 2012-01-27 10:25:47 +0200 | [diff] [blame] | 58 | print(' name=%s' % bytes2str(name_attr.value)) |
Eli Bendersky | 1a516a3 | 2011-12-22 15:22:00 +0200 | [diff] [blame] | 59 | |
| 60 | # Display DIEs recursively starting with top_DIE |
| 61 | die_info_rec(top_DIE) |
| 62 | |
| 63 | |
| 64 | def die_info_rec(die, indent_level=' '): |
| 65 | """ A recursive function for showing information about a DIE and its |
| 66 | children. |
| 67 | """ |
| 68 | print(indent_level + 'DIE tag=%s' % die.tag) |
| 69 | child_indent = indent_level + ' ' |
| 70 | for child in die.iter_children(): |
| 71 | die_info_rec(child, child_indent) |
| 72 | |
| 73 | |
| 74 | if __name__ == '__main__': |
| 75 | for filename in sys.argv[1:]: |
| 76 | process_file(filename) |
| 77 | |
| 78 | |
| 79 | |
| 80 | |
| 81 | |
| 82 | |