From: Jorge Gorbe Date: Thu, 22 Nov 2012 18:11:12 +0000 (+0100) Subject: Reference support in view.py. Final(-ish) version of the slides. X-Git-Url: http://slack.codemaniacs.com/git/?a=commitdiff_plain;h=9c361fa046f1a9a7933703aa34ea94deb322e82e;p=resacon2012.git Reference support in view.py. Final(-ish) version of the slides. --- diff --git a/samples/view.py b/samples/view.py index 49cfffb..fc86c6f 100644 --- a/samples/view.py +++ b/samples/view.py @@ -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() diff --git a/slides/index.html b/slides/index.html index d576414..f79823c 100644 --- a/slides/index.html +++ b/slides/index.html @@ -114,17 +114,14 @@ End with a line saying just "end".

Canned sequences (1/2)

-
-(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
-
+
define plist
+    set $ptr = $arg0
+    while $ptr != 0
+        print *$ptr
+        set $ptr = $ptr->next
+        end
+    end
+
@@ -169,9 +166,11 @@ End with a line saying just "end".
@@ -184,8 +183,8 @@ End with a line saying just "end".
  • Custom commands
    can even define custom parameters to be set via gdb's set parameter value mechanism
  • -
  • Code auto-loading
    - e.g. load pretty printers when a library is loaded, register things at init +
  • Some more auto-loading points
    + e.g. load pretty printers when a library is loaded
  • Event handlers
    @@ -203,10 +202,9 @@ End with a line saying just "end".

    Python in GDB

    Hello World

    -
    -(gdb) python print "Hello, World!"
    +
    (gdb) python print "Hello, World!"
     Hello, World!
    -
    +

    Ok, now what?

    @@ -318,8 +316,16 @@ DoNothingCommand() # and instance it

    The Python API

    -

    Pretty much every gdb concept is exposed to Python scripts via the API.

    +

    Pretty much every gdb "user" concept is exposed to Python scripts via the API.

    GDB Docs - Python API

    +
      +
    • Future goals (see this wiki page): +
        +
      • make possible to support new languages using only Python
      • +
      • make possible to write useful gdb-based stand-alone tools in Python
      • +
      +
    • +