1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/die.py
4 # DWARF Debugging Information Entry
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from collections import namedtuple
11 from ..common.py3compat import OrderedDict
12 from ..common.utils import struct_parse, preserve_stream_pos
15 # AttributeValue - describes an attribute value in the DIE:
18 # The name (DW_AT_*) of this attribute
21 # The DW_FORM_* name of this attribute
24 # The value parsed from the section and translated accordingly to the form
25 # (e.g. for a DW_FORM_strp it's the actual string taken from the string table)
28 # Raw value as parsed from the section - used for debugging and presentation
29 # (e.g. for a DW_FORM_strp it's the raw string offset into the table)
32 # Offset of this attribute's value in the stream (absolute offset, relative
33 # the beginning of the whole stream)
35 AttributeValue = namedtuple(
36 'AttributeValue', 'name form value raw_value offset')
40 """ A DWARF debugging information entry. On creation, parses itself from
41 the stream. Each DIE is held by a CU.
43 Accessible attributes:
49 The size this DIE occupies in the section
52 The offset of this DIE in the stream
55 An ordered dictionary mapping attribute names to values. It's
56 ordered to preserve the order of attributes in the section
59 Specifies whether this DIE has children
62 The abbreviation code pointing to an abbreviation entry (not
63 that this is for informational pusposes only - this object
64 interacts with its abbreviation table transparently).
66 See also the public methods.
68 def __init__(self, cu, stream, offset):
70 CompileUnit object this DIE belongs to. Used to obtain context
71 information (structs, abbrev table, etc.)
74 The stream and offset into it where this DIE's data is located
77 self.dwarfinfo = self.cu.dwarfinfo # get DWARFInfo context
81 self.attributes = OrderedDict()
83 self.has_children = None
84 self.abbrev_code = None
92 """ Is this a null entry?
94 return self.tag is None
97 """ The parent DIE of this DIE. None if the DIE has no parent (i.e. a
102 def iter_children(self):
103 """ Yield all children of this DIE
105 return iter(self._children)
107 def iter_siblings(self):
108 """ Yield all siblings of this DIE
111 for sibling in self._parent.iter_children():
112 if sibling is not self:
115 raise StopIteration()
117 # The following methods are used while creating the DIE and should not be
118 # interesting to consumers
120 def add_child(self, die):
121 self._children.append(die)
123 def set_parent(self, die):
126 #------ PRIVATE ------#
129 s = 'DIE %s, size=%s, has_chidren=%s\n' % (
130 self.tag, self.size, self.has_children)
131 for attrname, attrval in self.attributes.iteritems():
132 s += ' |%-18s: %s\n' % (attrname, attrval)
136 return self.__repr__()
138 def _parse_DIE(self):
139 """ Parses the DIE info from the section, based on the abbreviation
142 structs = self.cu.structs
144 # A DIE begins with the abbreviation code. Read it and use it to
145 # obtain the abbrev declaration for this DIE.
146 # Note: here and elsewhere, preserve_stream_pos is used on operations
147 # that manipulate the stream by reading data from it.
149 self.abbrev_code = struct_parse(
150 structs.Dwarf_uleb128(''), self.stream, self.offset)
152 # This may be a null entry
153 if self.abbrev_code == 0:
154 self.size = self.stream.tell() - self.offset
157 with preserve_stream_pos(self.stream):
158 abbrev_decl = self.cu.get_abbrev_table().get_abbrev(
160 self.tag = abbrev_decl['tag']
161 self.has_children = abbrev_decl.has_children()
163 # Guided by the attributes listed in the abbreviation declaration, parse
164 # values from the stream.
166 for name, form in abbrev_decl.iter_attr_specs():
167 attr_offset = self.stream.tell()
168 raw_value = struct_parse(structs.Dwarf_dw_form[form], self.stream)
170 value = self._translate_attr_value(form, raw_value)
171 self.attributes[name] = AttributeValue(
178 self.size = self.stream.tell() - self.offset
180 def _translate_attr_value(self, form, raw_value):
181 """ Translate a raw attr value according to the form
184 if form == 'DW_FORM_strp':
185 with preserve_stream_pos(self.stream):
186 value = self.dwarfinfo.get_string_from_table(raw_value)
187 elif form == 'DW_FORM_flag':
188 value = not raw_value == 0
189 elif form == 'DW_FORM_indirect':
191 raw_value = struct_parse(
192 structs.Dwarf_dw_form[form], self.stream)
193 # Let's hope this doesn't get too deep :-)
194 return self._translate_attr_value(form, raw_value)