some refactoring. parsing a single DIE now appears to be working
[pyelftools.git] / elftools / dwarf / die.py
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/die.py
3 #
4 # DWARF Debugging Information Entry
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from collections import namedtuple
10
11 from ..common.ordereddict import OrderedDict
12 from ..common.utils import struct_parse, preserve_stream_pos
13
14
15 # AttributeValue - describes an attribute value in the DIE:
16 #
17 # form:
18 # The DW_FORM_* name of this attribute
19 #
20 # value:
21 # The value parsed from the section and translated accordingly to the form
22 # (e.g. for a DW_FORM_strp it's the actual string taken from the string table)
23 #
24 # raw_value:
25 # Raw value as parsed from the section - used for debugging and presentation
26 # (e.g. for a DW_FORM_strp it's the raw string offset into the table)
27 #
28 AttributeValue = namedtuple('AttributeValue', 'form value raw_value')
29
30
31 class DIE(object):
32 """ A DWARF debugging information entry. On creation, parses itself from
33 the stream. Each DIE is held by a CU.
34
35 Accessible attributes:
36
37 tag:
38 The DIE tag
39
40 size:
41 The size this DIE occupies in the section
42
43 attributes:
44 An ordered dictionary mapping attribute names to values. It's
45 ordered to enable both efficient name->value mapping and
46 preserve the order of attributes in the section
47
48 has_children:
49 Specifies whether this DIE has children
50 """
51 def __init__(self, cu, stream, offset):
52 """ cu:
53 CompileUnit object this DIE belongs to. Used to obtain context
54 information (structs, abbrev table, etc.)
55
56 stream, offset:
57 The stream and offset into it where this DIE's data is located
58 """
59 self.cu = cu
60 self.dwarfinfo = self.cu.dwarfinfo # get DWARFInfo context
61 self.stream = stream
62 self.offset = offset
63 self.attributes = OrderedDict()
64 self._parse_DIE()
65
66 def _parse_DIE(self):
67 """ Parses the DIE info from the section, based on the abbreviation
68 table of the CU
69 """
70 structs = self.cu.structs
71
72 # A DIE begins with the abbreviation code. Read it and use it to
73 # obtain the abbrev declaration for this DIE.
74 # Note: here and elsewhere, preserve_stream_pos is used on operations
75 # that manipulate the stream by reading data from it.
76 #
77 abbrev_code = struct_parse(
78 structs.Dwarf_uleb128(''), self.stream, self.offset)
79 with preserve_stream_pos(self.stream):
80 abbrev_decl = self.cu.get_abbrev_table().get_abbrev(abbrev_code)
81 self.has_children = abbrev_decl.has_children()
82
83 # Guided by the attributes listed in the abbreviation declaration, parse
84 # values from the stream.
85 #
86 for name, form in abbrev_decl.iter_attr_specs():
87 raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream)
88 value = self._translate_attr_value(form, raw_value)
89 self.attributes[name] = AttributeValue(form, value, raw_value)
90
91 self.size = self.stream.tell() - self.offset
92
93 def _translate_attr_value(self, form, raw_value):
94 """ Translate a raw attr value according to the form
95 """
96 value = None
97 if form == 'DW_FORM_strp':
98 with preserve_stream_pos(self.stream):
99 value = self.dwarfinfo.get_string_from_table(raw_value)
100 elif form == 'DW_FORM_flag':
101 value = not raw_value == 0
102 elif form == 'DW_FORM_indirect':
103 form = raw_value
104 raw_value = struct_parse(
105 structs.Dwarf_dw_form[form], self.stream)
106 # Let's hope this doesn't get too deep :-)
107 return self._translate_attr_value(form, raw_value)
108 else:
109 value = raw_value
110 return value
111
112