cleanups of trailing whitespace
[pyelftools.git] / elftools / dwarf / compileunit.py
1 #-------------------------------------------------------------------------------
2 # elftools: dwarf/compileunit.py
3 #
4 # DWARF compile unit
5 #
6 # Eli Bendersky (eliben@gmail.com)
7 # This code is in the public domain
8 #-------------------------------------------------------------------------------
9 from .die import DIE
10
11
12 class CompileUnit(object):
13 """ A DWARF compilation unit (CU).
14
15 A normal compilation unit typically represents the text and data
16 contributed to an executable by a single relocatable object file.
17 It may be derived from several source files,
18 including pre-processed "include files"
19
20 Serves as a container and context to DIEs that describe objects and code
21 belonging to a compilation unit.
22
23 CU header entries can be accessed as dict keys from this object, i.e.
24 cu = CompileUnit(...)
25 cu['version'] # version field of the CU header
26
27 To get the top-level DIE describing the compilation unit, call the
28 get_top_DIE method.
29 """
30 def __init__(self, header, dwarfinfo, structs, cu_offset, cu_die_offset):
31 """ header:
32 CU header for this compile unit
33
34 dwarfinfo:
35 The DWARFInfo context object which created this one
36
37 structs:
38 A DWARFStructs instance suitable for this compile unit
39
40 cu_offset:
41 Offset in the stream to the beginning of this CU (its header)
42
43 cu_die_offset:
44 Offset in the stream of the top DIE of this CU
45 """
46 self.dwarfinfo = dwarfinfo
47 self.header = header
48 self.structs = structs
49 self.cu_offset = cu_offset
50 self.cu_die_offset = cu_die_offset
51
52 # The abbreviation table for this CU. Filled lazily when DIEs are
53 # requested.
54 self._abbrev_table = None
55
56 # A list of DIEs belonging to this CU. Lazily parsed.
57 self._dielist = []
58
59 def dwarf_format(self):
60 """ Get the DWARF format (32 or 64) for this CU
61 """
62 return self.structs.dwarf_format
63
64 def get_abbrev_table(self):
65 """ Get the abbreviation table (AbbrevTable object) for this CU
66 """
67 if self._abbrev_table is None:
68 self._abbrev_table = self.dwarfinfo.get_abbrev_table(
69 self['debug_abbrev_offset'])
70 return self._abbrev_table
71
72 def get_top_DIE(self):
73 """ Get the top DIE (which is either a DW_TAG_compile_unit or
74 DW_TAG_partial_unit) of this CU
75 """
76 return self._get_DIE(0)
77
78 def iter_DIEs(self):
79 """ Iterate over all the DIEs in the CU, in order of their appearance.
80 Note that null DIEs will also be returned.
81 """
82 self._parse_DIEs()
83 return iter(self._dielist)
84
85 #------ PRIVATE ------#
86
87 def __getitem__(self, name):
88 """ Implement dict-like access to header entries
89 """
90 return self.header[name]
91
92 def _get_DIE(self, index):
93 """ Get the DIE at the given index
94 """
95 self._parse_DIEs()
96 return self._dielist[index]
97
98 def _parse_DIEs(self):
99 """ Parse all the DIEs pertaining to this CU from the stream and shove
100 them sequentially into self._dielist.
101 Also set the child/sibling/parent links in the DIEs according
102 (unflattening the prefix-order of the DIE tree).
103 """
104 if len(self._dielist) > 0:
105 return
106
107 # Compute the boundary (one byte past the bounds) of this CU in the
108 # stream
109 cu_boundary = ( self.cu_offset +
110 self['unit_length'] +
111 self.structs.initial_length_field_size())
112
113 # First pass: parse all DIEs and place them into self._dielist
114 die_offset = self.cu_die_offset
115 while die_offset < cu_boundary:
116 die = DIE(
117 cu=self,
118 stream=self.dwarfinfo.debug_info_sec.stream,
119 offset=die_offset)
120 self._dielist.append(die)
121 die_offset += die.size
122
123 # Second pass - unflatten the DIE tree
124 self._unflatten_tree()
125
126 def _unflatten_tree(self):
127 """ "Unflatten" the DIE tree from it serial representation, by setting
128 the child/sibling/parent links of DIEs.
129
130 Assumes self._dielist was already populated by a linear list of DIEs
131 read from the stream section
132 """
133 # the first DIE in the list is the root node
134 root = self._dielist[0]
135 parentstack = [root]
136
137 for die in self._dielist[1:]:
138 if not die.is_null():
139 cur_parent = parentstack[-1]
140 # This DIE is a child of the current parent
141 cur_parent.add_child(die)
142 die.set_parent(cur_parent)
143 if die.has_children:
144 parentstack.append(die)
145 else:
146 # parentstack should not be really empty here. However, some
147 # compilers generate DWARF that has extra NULLs in the end and
148 # we don't want pyelftools to fail parsing them just because of
149 # this.
150 if len(parentstack) > 0:
151 # end of children for the current parent
152 parentstack.pop()
153