Reference support in view.py. Final(-ish) version of the slides.
authorJorge Gorbe <j.gorbe@stcsl.es>
Thu, 22 Nov 2012 18:11:12 +0000 (19:11 +0100)
committerJorge Gorbe <j.gorbe@stcsl.es>
Thu, 22 Nov 2012 18:11:12 +0000 (19:11 +0100)
samples/view.py
slides/index.html

index 49cfffb205c99b8fc4711129e947a2409db63d9d..fc86c6faebb78a6ba6f2666bdd7fa7c890c19db0 100644 (file)
@@ -12,39 +12,66 @@ def merge_dict(dst, src):
     for i in src:
         dst[i] = src[i]
 
+def address_to_uint(addr):
+    return int(addr.cast(gdb.lookup_type("unsigned int")))
+
+def type_code_string(code):
+    if code == gdb.TYPE_CODE_PTR: return "TYPE_CODE_PTR"
+    elif code == gdb.TYPE_CODE_ARRAY: return "TYPE_CODE_ARRAY"
+    elif code == gdb.TYPE_CODE_STRUCT: return "TYPE_CODE_STRUCT"
 
 def type_has_fields(t):
-    basic_type = gdb.types.get_basic_type(t)
-    return basic_type.code == gdb.TYPE_CODE_STRUCT or basic_type.code == gdb.TYPE_CODE_UNION
+    tt = t.strip_typedefs()
+    return tt.code == gdb.TYPE_CODE_STRUCT or tt.code == gdb.TYPE_CODE_UNION
 
 def type_is_pointer(t):
-    basic_type = gdb.types.get_basic_type(t)
-    return basic_type.code == gdb.TYPE_CODE_PTR or basic_type.code == gdb.TYPE_CODE_REF
+    tt = t.strip_typedefs()
+    return tt.code == gdb.TYPE_CODE_PTR
+
+def type_is_reference(t):
+    tt = t.strip_typedefs()
+    return tt.code == gdb.TYPE_CODE_REF
 
 def find_outgoing_pointers(value):
     """Finds all outgoing pointers from a value, traversing each non-pointer member of a composite type
     (e.g. struct members inside structs) and also each member in every base class, recursively.
     Returns a dict of {field_name:address} where field_name is a string, and address is a gdb.Value."""
+    print "find_outgoing_pointers(",str(value),")"
     try:
         valuetype = value.dynamic_type
     except gdb.error:
+        print "error: dynamic_type"
         valuetype = value.type
+
+    if type_is_reference(valuetype):
+        return find_outgoing_pointers(value.referenced_value())
+    
     if type_is_pointer(valuetype):
+        print "following ptr"
         return {"*": value}
     elif type_has_fields(valuetype):
+        print "type has fields"
         result = {}
         for f in value.type.fields():
+            print "field: ", f.name, "(", f.type, ")"
             if f.is_base_class:
+                print "is base class"
                 base_pointers = find_outgoing_pointers(value.cast(f.type))
                 merge_dict(result, base_pointers)
             elif type_has_fields(f.type):
+                print "has fields"
                 member_pointers = find_outgoing_pointers(value[f.name])
                 merge_dict(result, member_pointers)
             elif type_is_pointer(f.type):
+                print "is pointer"
                 result[f.name] = value[f.name]
+            elif type_is_reference(f.type):
+                print "is_reference"
+                result[f.name] = value[f.name].referenced_value().address
 
         return result
     else:
+        print "blah"
         return {}
 
 
@@ -134,6 +161,8 @@ class GraphViewerNode():
         self.contained_nodes = [] # member structs pointed to directly from the outside get their own nodes, we need to draw this relationship
         self.fill_color = (0.4, 0.4, 0.5)
 
+    def __str__(self):
+        return "GraphViewerNode{address=%s, gdb_value = %s}"%(str(self.gdb_value.address), self.gdb_value)
 
 
 class GraphViewer(gtk.Layout):
@@ -215,6 +244,9 @@ class GraphViewer(gtk.Layout):
         context.stroke()
 
     def draw_connection(self, context, n1, n2, name):
+        if n1 == n2:
+            print "loop!"
+            return
         (p1, p2) = node_connection_points(n1, n2)
         context.save()
         context.set_source_rgb(0,0,0)
@@ -262,6 +294,7 @@ class GraphViewer(gtk.Layout):
             self.draw_node(context, node)
 
         for node in self.nodes:
+            #print node, node.connections
             for connection_name in node.connections:
                 self.draw_connection(context, node, node.connections[connection_name], connection_name)
 
@@ -367,21 +400,21 @@ class ViewerWindow(gtk.Window):
 
 def visit_values(node_dict, value, x, y, recursion_level):
     """
-    Recursively traverse children of a gdb Value, storing pairs (address, GraphViewerNode).
+    Recursively traverse children of a gdb Value, storing pairs (address_as_uint, GraphViewerNode).
     returns (width, height, node_dict)
     """
     NODE_SPACING = 150
     NODE_OFFSET = 50 + random.randint(-40,40)
 
-    if str(value.address) in node_dict:
+    if address_to_uint(value.address) in node_dict:
         return 0, 0
 
     if recursion_level < 0:
-        node_dict[str(value.address)] = GraphViewerNode(x, y, "...", value)
+        node_dict[address_to_uint(value.address)] = GraphViewerNode(x, y, "...", value)
         return NODE_SPACING, NODE_SPACING
 
     # check if node has already been visited, don't create repeated nodes
-    node_dict[str(value.address)] = GraphViewerNode(x, y, str(value.type), value)
+    node_dict[address_to_uint(value.address)] = GraphViewerNode(x, y, str(value.type), value)
     width = NODE_SPACING
     height = 0
     children_x = x+NODE_SPACING
@@ -389,6 +422,12 @@ def visit_values(node_dict, value, x, y, recursion_level):
     children_height = 0
 
     children = find_outgoing_pointers(value)
+    print "value =",value
+    children2  = {}
+    for k in children:
+        children2[k] = str(children[k])
+    print "children =",children2
+
     for (child_name, child_value) in children.iteritems():
         # compute child "tree" dimensions (layout is always tree-like even if there are edges that make this a generic graph)
         if child_value != 0:
@@ -403,6 +442,30 @@ def visit_values(node_dict, value, x, y, recursion_level):
     return width, height
 
 
+def fill_node_connections(nodes, addr, value):
+    if type_is_reference(value.type):
+        value = value.referenced_value()
+
+    if type_is_pointer(value.type) and value != 0:
+        nodes[addr].connections["*"] = nodes[address_to_uint(value)]
+    else:
+        if type_has_fields(value.type):
+            for f in value.type.fields():
+                if f.is_base_class:
+                    fill_node_connections(nodes, addr, value.cast(f.type))
+                else:
+                    child = value[f.name]
+                    if type_is_pointer(child.type):
+                        if child != 0:
+                            if address_to_uint(child) in nodes:
+                                nodes[addr].connections[f.name] = nodes[address_to_uint(child.referenced_value().address)]
+                    elif type_is_reference(child.type):
+                        if address_to_uint(child.referenced_value().address) in nodes:
+                            nodes[addr].connections[f.name] = nodes[address_to_uint(child.referenced_value().address)]
+        else:
+            print "unknown type:", value.type
+
+
 def create_viewer_nodes(value, recursion_level):
     # create the nodes
     nodes = {}
@@ -411,24 +474,14 @@ def create_viewer_nodes(value, recursion_level):
     # establish connections between nodes when all the nodes are there
     for addr in nodes:
         value = nodes[addr].gdb_value
-        if type_is_pointer(value.type) and value != 0:
-            nodes[addr].connections["*"] = nodes[str(value)]
-        else:
-            for f in value.type.fields():
-                child = value[f.name]
-                if type_is_pointer(child.type):
-                    if child != 0:
-                        if str(child) in nodes:
-                            nodes[addr].connections[f.name] = nodes[str(child)]
+        fill_node_connections(nodes, addr, value)
 
     # establish containment relationships between nodes
     for addr1 in nodes:
-        addr1_int = int(addr1, 0)
         node1 = nodes[addr1]
         for addr2 in nodes:
-            addr2_int = int(addr2, 0)
             node2 = nodes[addr2]
-            if addr2_int > addr1_int and addr2_int < addr1_int + node1.gdb_value.type.sizeof:
+            if addr2 > addr1 and addr2 < addr1 + node1.gdb_value.type.sizeof:
                 node1.contained_nodes.append(node2)
 
     return nodes.values()
index d576414b39470ca811b150d46ed2788294844a92..f79823cbbe926a86e1f3ac37950db34f10c984a3 100644 (file)
@@ -114,17 +114,14 @@ End with a line saying just "end".
 
                     <section>
                     <h2> Canned sequences (1/2) </h2>
-<pre>
-(gdb) define plist
-Type commands for definition of "plist".
-End with a line saying just "end".
->set $ptr = $arg0
->while $ptr != 0
- >print *$ptr
- >set $ptr = $ptr->next
- >end
->end
-</pre>
+<pre><code>define plist
+    set $ptr = $arg0
+    while $ptr != 0
+        print *$ptr
+        set $ptr = $ptr->next
+        end
+    end
+</code></pre>
                     </section>
 
                     <section>
@@ -169,9 +166,11 @@ End with a line saying just "end".
                     <ul>
                         <li> GDB 7.x has (optionally) an embedded Python interpreter... </li>
                         <li class="fragment"> ...and a Python API <br>
-                        <img src="reactionguys.jpg">
+                            <center>
+                                <img src="reactionguys.jpg">
+                                <small class="fragment">(there are still some quirks here and there, but it's quite usable :D)</small>
+                            </center>
                         </li>
-                        <small class="fragment">(there are still some quirks here and there, but it's quite usable :D)</small>
                     </ul>
                 </section>
 
@@ -184,8 +183,8 @@ End with a line saying just "end".
                         <li class="fragment">Custom commands <br>
                             <small>can even define custom parameters to be set via gdb's <code>set parameter value</code> mechanism</small>
                         </li>
-                        <li class="fragment">Code auto-loading <br>
-                            <small>e.g. load pretty printers when a library is loaded, register things at init</small>
+                        <li class="fragment">Some more auto-loading points<br>
+                            <small>e.g. load pretty printers when a library is loaded</small>
                         </li>
 
                         <li class="fragment">Event handlers <br>
@@ -203,10 +202,9 @@ End with a line saying just "end".
                 <section>
                     <h2>Python in GDB</h2>
                     <p> Hello World </p>
-<pre>
-(gdb) python print "Hello, World!"
+<pre><code>(gdb) python print "Hello, World!"
 Hello, World!
-</pre>
+</code></pre>
                     <p class="fragment">Ok, now what?</p>
                 </section>
 
@@ -318,8 +316,16 @@ DoNothingCommand() # and instance it
 
                 <section>
                     <h2>The Python API</h2>
-                    <p> Pretty much every gdb concept is exposed to Python scripts via the API. </p>
+                    <p> Pretty much every gdb "user" concept is exposed to Python scripts via the API. </p>
                     <p> <a href="http://sourceware.org/gdb/onlinedocs/gdb/Python-API.html#Python-API">GDB Docs - Python API</a></p>
+                    <ul class="fragment" style="margin-top:30px"> 
+                        <li>Future goals (see <a href="http://sourceware.org/gdb/wiki/PythonGdb">this wiki page</a>):
+                            <ul>
+                                <li>make possible to support new languages using only Python</li>
+                                <li>make possible to write useful gdb-based stand-alone tools in Python</li>
+                            </ul>
+                        </li>
+                    </ul>
                 </section>
 
                 <section>