Upstream version 8.36.161.0
[platform/framework/web/crosswalk.git] / src / third_party / pyelftools / 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.py3compat 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 # name:
18 #   The name (DW_AT_*) of this attribute
19
20 # form: 
21 #   The DW_FORM_* name of this attribute
22 #
23 # value:
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)
26 #
27 # raw_value:
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)
30 #
31 # offset:
32 #   Offset of this attribute's value in the stream (absolute offset, relative
33 #   the beginning of the whole stream)
34 #
35 AttributeValue = namedtuple(
36     'AttributeValue', 'name form value raw_value offset')
37
38
39 class DIE(object):
40     """ A DWARF debugging information entry. On creation, parses itself from
41         the stream. Each DIE is held by a CU.
42         
43         Accessible attributes:
44         
45             tag:
46                 The DIE tag
47         
48             size:
49                 The size this DIE occupies in the section
50             
51             offset:
52                 The offset of this DIE in the stream
53             
54             attributes:
55                 An ordered dictionary mapping attribute names to values. It's 
56                 ordered to preserve the order of attributes in the section
57             
58             has_children:
59                 Specifies whether this DIE has children
60             
61             abbrev_code:
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).
65         
66         See also the public methods.
67     """
68     def __init__(self, cu, stream, offset):
69         """ cu:
70                 CompileUnit object this DIE belongs to. Used to obtain context
71                 information (structs, abbrev table, etc.)
72                         
73             stream, offset:
74                 The stream and offset into it where this DIE's data is located
75         """
76         self.cu = cu
77         self.dwarfinfo = self.cu.dwarfinfo # get DWARFInfo context
78         self.stream = stream
79         self.offset = offset
80         
81         self.attributes = OrderedDict()
82         self.tag = None
83         self.has_children = None
84         self.abbrev_code = None
85         self.size = 0
86         self._children = []
87         self._parent = None
88         
89         self._parse_DIE()   
90     
91     def is_null(self):
92         """ Is this a null entry?
93         """
94         return self.tag is None
95     
96     def get_parent(self):
97         """ The parent DIE of this DIE. None if the DIE has no parent (i.e. a 
98             top-level DIE).
99         """
100         return self._parent
101     
102     def iter_children(self):
103         """ Yield all children of this DIE
104         """
105         return iter(self._children)
106     
107     def iter_siblings(self):
108         """ Yield all siblings of this DIE
109         """
110         if self._parent:
111             for sibling in self._parent.iter_children():
112                 if sibling is not self:
113                     yield sibling
114         else:
115             raise StopIteration()
116
117     # The following methods are used while creating the DIE and should not be
118     # interesting to consumers
119     #
120     def add_child(self, die):
121         self._children.append(die)
122     
123     def set_parent(self, die):
124         self._parent = die
125
126     #------ PRIVATE ------#
127     
128     def __repr__(self):
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)
133         return s
134     
135     def __str__(self):
136         return self.__repr__()
137     
138     def _parse_DIE(self):
139         """ Parses the DIE info from the section, based on the abbreviation
140             table of the CU
141         """
142         structs = self.cu.structs
143         
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.
148         #
149         self.abbrev_code = struct_parse(
150             structs.Dwarf_uleb128(''), self.stream, self.offset)
151         
152         # This may be a null entry
153         if self.abbrev_code == 0:
154             self.size = self.stream.tell() - self.offset
155             return
156         
157         with preserve_stream_pos(self.stream):
158             abbrev_decl = self.cu.get_abbrev_table().get_abbrev(
159                 self.abbrev_code)
160         self.tag = abbrev_decl['tag']
161         self.has_children = abbrev_decl.has_children()
162
163         # Guided by the attributes listed in the abbreviation declaration, parse
164         # values from the stream.
165         #
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)
169
170             value = self._translate_attr_value(form, raw_value)            
171             self.attributes[name] = AttributeValue(
172                 name=name,
173                 form=form,
174                 value=value,
175                 raw_value=raw_value,
176                 offset=attr_offset)
177         
178         self.size = self.stream.tell() - self.offset
179
180     def _translate_attr_value(self, form, raw_value):
181         """ Translate a raw attr value according to the form
182         """
183         value = None
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':
190             form = raw_value
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)
195         else:
196             value = raw_value
197         return value
198     
199