From: eliben Date: Sun, 2 Oct 2011 07:50:37 +0000 (+0200) Subject: unflattening the DIE tree by CU done - now DIEs have functional iter_children, get_pa... X-Git-Tag: v0.10~88 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8eff3ee04c30c4d7d6a924ad369e5c696f6a7c18;p=pyelftools.git unflattening the DIE tree by CU done - now DIEs have functional iter_children, get_parent and iter_siblings methods! --- diff --git a/elftools/dwarf/compileunit.py b/elftools/dwarf/compileunit.py index daee885..6e02e33 100644 --- a/elftools/dwarf/compileunit.py +++ b/elftools/dwarf/compileunit.py @@ -69,7 +69,9 @@ class CompileUnit(object): DW_TAG_partial_unit) of this CU """ return self._get_DIE(0) - + + #------ PRIVATE ------# + def __getitem__(self, name): """ Implement dict-like access to header entries """ @@ -83,15 +85,47 @@ class CompileUnit(object): return self._dielist[index] def _parse_DIEs(self): + """ Parse all the DIEs pertaining to this CU from the stream and shove + them sequentially into self._dielist. + Also set the child/sibling/parent links in the DIEs according + (unflattening the prefix-order of the DIE tree). + """ # Compute the boundary (one byte past the bounds) of this CU in the # stream cu_boundary = ( self.cu_offset + self['unit_length'] + self.structs.initial_length_field_size()) + # First pass: parse all DIEs and place them into self._dielist die_offset = self.cu_die_offset while die_offset < cu_boundary: die = DIE(cu=self, stream=self.dwarfinfo.stream, offset=die_offset) self._dielist.append(die) die_offset += die.size + # Second pass - unflatten the DIE tree + self._unflatten_tree() + + def _unflatten_tree(self): + """ "Unflatten" the DIE tree from it serial representation, by setting + the child/sibling/parent links of DIEs. + + Assumes self._dielist was already populated by a linear list of DIEs + read from the stream section + """ + # the first DIE in the list is the root node + root = self._dielist[0] + parentstack = [root] + + for die in self._dielist[1:]: + if not die.is_null(): + cur_parent = parentstack[-1] + # This DIE is a child of the current parent + cur_parent.add_child(die) + die.set_parent(cur_parent) + if die.has_children: + parentstack.append(die) + else: + # end of children for the current parent + parentstack.pop() + diff --git a/elftools/dwarf/die.py b/elftools/dwarf/die.py index b92c31a..f49efc9 100644 --- a/elftools/dwarf/die.py +++ b/elftools/dwarf/die.py @@ -54,6 +54,8 @@ class DIE(object): has_children: Specifies whether this DIE has children + + See also the public methods. """ def __init__(self, cu, stream, offset): """ cu: @@ -72,6 +74,8 @@ class DIE(object): self.tag = None self.has_children = None self.size = 0 + self._children = [] + self._parent = None self._parse_DIE() @@ -80,8 +84,48 @@ class DIE(object): """ return self.tag is None + def get_parent(self): + """ The parent DIE of this DIE. None if the DIE has no parent (i.e. a + top-level DIE). + """ + return self._parent + + def iter_children(self): + """ Yield all children of this DIE + """ + return iter(self._children) + + def iter_siblings(self): + """ Yield all siblings of this DIE + """ + if self._parent: + for sibling in self._parent.iter_children(): + if sibling is not self: + yield sibling + else: + raise StopIteration() + + # The following methods are used while creating the DIE and should not be + # interesting to consumers + # + def add_child(self, die): + self._children.append(die) + + def set_parent(self, die): + self._parent = die + #------ PRIVATE ------# + def __repr__(self): + s = 'DIE %s, size=%s, has_chidren=%s\n' % ( + self.tag, self.size, self.has_children) + for attrname, attrval in self.attributes.iteritems(): + s += ' |%-18s: %s\n' % (attrname, attrval) + return s + + def __str__(self): + return self.__repr__() + def _parse_DIE(self): """ Parses the DIE info from the section, based on the abbreviation table of the CU diff --git a/z.py b/z.py index c8cdbce..7780365 100644 --- a/z.py +++ b/z.py @@ -20,16 +20,39 @@ print '===> %s sections!' % efile.num_sections() print efile.has_dwarf_info() dwarfinfo = efile.get_dwarf_info() -tt = dwarfinfo.structs.Dwarf_dw_form['DW_FORM_block1'].parse('\x03\x12\x34\x46') -cu = dwarfinfo.get_CU(1) +cu = dwarfinfo.get_CU(3) print 'CU header', cu.header topdie = cu.get_top_DIE() -for die in cu._dielist: - print 'DIE %s, size=%s' % (die.tag, die.size) - for attrname, val in die.attributes.iteritems(): - print ' ', attrname, val +c = topdie.iter_children().next() + +print c + +print 'siblings.....' + +for s in c.iter_siblings(): + print s + +#~ print c.get_parent() +#~ print topdie + +#~ def recp(d, indent=0): + #~ s = str(d) + #~ lines = s.split('\n') + #~ print '\n'.join(' ' * indent + l for l in lines) + + #~ for c in d.iter_children(): + #~ recp(c, indent + 6) + +#~ recp(topdie) + +#~ for c in topdie.iter_children(): + #~ print c +#~ for die in cu._dielist: + #~ print 'DIE %s, size=%s' % (die.tag, die.size) + #~ for attrname, val in die.attributes.iteritems(): + #~ print ' ', attrname, val #~ topdie = cu.get_top_DIE()