unflattening the DIE tree by CU done - now DIEs have functional iter_children, get_pa...
authoreliben <devnull@localhost>
Sun, 2 Oct 2011 07:50:37 +0000 (09:50 +0200)
committereliben <devnull@localhost>
Sun, 2 Oct 2011 07:50:37 +0000 (09:50 +0200)
elftools/dwarf/compileunit.py
elftools/dwarf/die.py
z.py

index daee885faba4e7e4e933909891dcc1ac3a0c7837..6e02e333d63a41e2fb073fd57e6371ea0525f52a 100644 (file)
@@ -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()
+
index b92c31a79441cc515c23af7664d8f1a44757deb7..f49efc9deedc3bfe25cc3935664a6dd377d2cfab 100644 (file)
@@ -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 c8cdbce377759b52fb423e88c271bae5b596d04c..7780365713bdb729e93ecec8fac5811952a4dc59 100644 (file)
--- 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()