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
.ordereddict
import OrderedDict
12 from ..common
.utils
import struct_parse
, preserve_stream_pos
15 # AttributeValue - describes an attribute value in the DIE:
18 # The DW_FORM_* name of this attribute
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)
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)
29 # Offset of this attribute's value in the stream
31 AttributeValue
= namedtuple(
32 'AttributeValue', 'form value raw_value offset')
36 """ A DWARF debugging information entry. On creation, parses itself from
37 the stream. Each DIE is held by a CU.
39 Accessible attributes:
45 The size this DIE occupies in the section
48 The offset of this DIE in the stream
51 An ordered dictionary mapping attribute names to values. It's
52 ordered to enable both efficient name->value mapping and
53 preserve the order of attributes in the section
56 Specifies whether this DIE has children
58 See also the public methods.
60 def __init__(self
, cu
, stream
, offset
):
62 CompileUnit object this DIE belongs to. Used to obtain context
63 information (structs, abbrev table, etc.)
66 The stream and offset into it where this DIE's data is located
69 self
.dwarfinfo
= self
.cu
.dwarfinfo
# get DWARFInfo context
73 self
.attributes
= OrderedDict()
75 self
.has_children
= None
83 """ Is this a null entry?
85 return self
.tag
is None
88 """ The parent DIE of this DIE. None if the DIE has no parent (i.e. a
93 def iter_children(self
):
94 """ Yield all children of this DIE
96 return iter(self
._children
)
98 def iter_siblings(self
):
99 """ Yield all siblings of this DIE
102 for sibling
in self
._parent
.iter_children():
103 if sibling
is not self
:
106 raise StopIteration()
108 # The following methods are used while creating the DIE and should not be
109 # interesting to consumers
111 def add_child(self
, die
):
112 self
._children
.append(die
)
114 def set_parent(self
, die
):
117 #------ PRIVATE ------#
120 s
= 'DIE %s, size=%s, has_chidren=%s\n' % (
121 self
.tag
, self
.size
, self
.has_children
)
122 for attrname
, attrval
in self
.attributes
.iteritems():
123 s
+= ' |%-18s: %s\n' % (attrname
, attrval
)
127 return self
.__repr
__()
129 def _parse_DIE(self
):
130 """ Parses the DIE info from the section, based on the abbreviation
133 structs
= self
.cu
.structs
135 # A DIE begins with the abbreviation code. Read it and use it to
136 # obtain the abbrev declaration for this DIE.
137 # Note: here and elsewhere, preserve_stream_pos is used on operations
138 # that manipulate the stream by reading data from it.
140 abbrev_code
= struct_parse(
141 structs
.Dwarf_uleb128(''), self
.stream
, self
.offset
)
143 # This may be a null entry
145 self
.size
= self
.stream
.tell() - self
.offset
148 with
preserve_stream_pos(self
.stream
):
149 abbrev_decl
= self
.cu
.get_abbrev_table().get_abbrev(abbrev_code
)
150 self
.tag
= abbrev_decl
['tag']
151 self
.has_children
= abbrev_decl
.has_children()
153 # Guided by the attributes listed in the abbreviation declaration, parse
154 # values from the stream.
156 for name
, form
in abbrev_decl
.iter_attr_specs():
157 attr_offset
= self
.stream
.tell()
158 raw_value
= struct_parse(structs
.Dwarf_dw_form
[form
], self
.stream
)
159 value
= self
._translate
_attr
_value
(form
, raw_value
)
160 self
.attributes
[name
] = AttributeValue(
166 self
.size
= self
.stream
.tell() - self
.offset
168 def _translate_attr_value(self
, form
, raw_value
):
169 """ Translate a raw attr value according to the form
172 if form
== 'DW_FORM_strp':
173 with
preserve_stream_pos(self
.stream
):
174 value
= self
.dwarfinfo
.get_string_from_table(raw_value
)
175 elif form
== 'DW_FORM_flag':
176 value
= not raw_value
== 0
177 elif form
== 'DW_FORM_indirect':
179 raw_value
= struct_parse(
180 structs
.Dwarf_dw_form
[form
], self
.stream
)
181 # Let's hope this doesn't get too deep :-)
182 return self
._translate
_attr
_value
(form
, raw_value
)