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 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 # The offset of the .debug_info section in the stream. Used to compute
164 # relative offset of attribute values to the beginning of the section.
165 section_offset
= self
.dwarfinfo
.debug_info_sec
.global_offset
167 # Guided by the attributes listed in the abbreviation declaration, parse
168 # values from the stream.
170 for name
, form
in abbrev_decl
.iter_attr_specs():
171 attr_offset
= self
.stream
.tell()
172 raw_value
= struct_parse(structs
.Dwarf_dw_form
[form
], self
.stream
)
174 value
= self
._translate
_attr
_value
(form
, raw_value
)
175 self
.attributes
[name
] = AttributeValue(
182 self
.size
= self
.stream
.tell() - self
.offset
184 def _translate_attr_value(self
, form
, raw_value
):
185 """ Translate a raw attr value according to the form
188 if form
== 'DW_FORM_strp':
189 with
preserve_stream_pos(self
.stream
):
190 value
= self
.dwarfinfo
.get_string_from_table(raw_value
)
191 elif form
== 'DW_FORM_flag':
192 value
= not raw_value
== 0
193 elif form
== 'DW_FORM_indirect':
195 raw_value
= struct_parse(
196 structs
.Dwarf_dw_form
[form
], self
.stream
)
197 # Let's hope this doesn't get too deep :-)
198 return self
._translate
_attr
_value
(form
, raw_value
)