From 28624bfcaca904876f4222015c2a247199386907 Mon Sep 17 00:00:00 2001 From: Jorge Gorbe Date: Fri, 2 Nov 2012 14:56:41 +0100 Subject: [PATCH] inheritance support in property view --- samples/view.py | 105 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 35 deletions(-) diff --git a/samples/view.py b/samples/view.py index 793b093..e5edcb6 100644 --- a/samples/view.py +++ b/samples/view.py @@ -5,10 +5,42 @@ import pango import pangocairo import math +def merge_dict(dst, src): + for i in src: + dst[i] = src[i] + + 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 +def type_is_pointer(t): + basic_type = gdb.types.get_basic_type(t) + return basic_type.code == gdb.TYPE_CODE_PTR + +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.""" + if type_is_pointer(value.dynamic_type): + return {"*": value} + elif type_has_fields(value.dynamic_type): + result = {} + for f in value.type.fields(): + if f.is_base_class: + base_pointers = find_outgoing_pointers(value.cast(f.type)) + merge_dict(result, base_pointers) + elif type_has_fields(f.type): + member_pointers = find_outgoing_pointers(value[f.name]) + merge_dict(result, member_pointers) + elif type_is_pointer(f.type): + result[f.name] = value[f.name] + + return result + else: + return {} + + def segment_intersection(A, B, C, D): """Computes the intersection between the rect segment AB and the rect segment CD. All parameters are 2D points expressed as (x,y) tuples. Result is also a (x,y) tuple, or @@ -85,6 +117,7 @@ def arrow_points(A, B): class GraphViewerNode(): def __init__(self, x, y, name, gdb_value): + print "node created: %d, %d, %s, %s"% (x, y, name, gdb_value.address) self.x = x self.y = y self.width = 30 @@ -197,12 +230,16 @@ class GdbValueViewer(gtk.TreeView): def visit_value(self, value, store_iter): if type_has_fields(value.type): for f in value.type.fields(): - field_value = value[f.name] - if type_has_fields(field_value.type) > 0: - child_iter = self.store.append(store_iter, (f.name, str(f.type))) - self.visit_value(field_value, child_iter) + if f.is_base_class: + child_iter = self.store.append(store_iter, ("Base class", str(f.type))) + self.visit_value(value.cast(f.type), child_iter) else: - self.store.append(store_iter, (f.name, str(field_value))) + field_value = value[f.name] + if type_has_fields(field_value.type) > 0: + child_iter = self.store.append(store_iter, (f.name, "type [%s]"%str(f.type))) + self.visit_value(field_value, child_iter) + else: + self.store.append(store_iter, (f.name, str(field_value))) else: self.store.append(None, ("", str(value))) @@ -234,64 +271,59 @@ class ViewerWindow(gtk.Window): self.set_default_size(1000,600) self.paned.set_position(750) -def merge_dict(dst, src): - for i in src: - dst[i] = src[i] - def visit_values(value, x, y, recursion_level): """ Recursively traverse children of a gdb Value, storing pairs (address, GraphViewerNode). returns (width, height, node_dict) """ - # TODO: CHECK IF NODE HAS ALREADY BEEN VISITED, DON'T CREATE REPEATED NODES :P NODE_SPACING = 100 if recursion_level < 0: return NODE_SPACING, NODE_SPACING, {str(value.address): GraphViewerNode(x, y, "...", value)} result = {} - result[str(value.address)] = GraphViewerNode(x, y, str(value.type), value) + # check if node has already been visited, don't create repeated nodes + if str(value.address) not in result: + result[str(value.address)] = GraphViewerNode(x, y, str(value.type), value) width = NODE_SPACING height = 0 children_x = x+NODE_SPACING children_y = y children_height = 0 - if value.type.code == gdb.TYPE_CODE_PTR and value != 0: - pointee = value.dereference() - pointee_width, pointee_height, pointee_nodes = visit_values(pointee, children_x, children_y, recursion_level - 1) - merge_dict(result, pointee_nodes) - return NODE_SPACING+pointee_width, max(NODE_SPACING, pointee_height), result - elif type_has_fields(value.type): - for f in value.type.fields(): - child = value[f.name] - if child.type.code == gdb.TYPE_CODE_PTR: - if child != 0: - child_width, child_height, child_nodes = visit_values(child.dereference(), children_x, children_y, recursion_level - 1) - children_y += child_height - children_height += child_height - width = max(width, NODE_SPACING + child_width) - merge_dict(result, child_nodes) - else: - pass # TODO: handle nulls - height = max(NODE_SPACING, children_height) - return width, height, result - else: - return NODE_SPACING, NODE_SPACING, result + children = find_outgoing_pointers(value) + 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: + child_width, child_height, child_nodes = visit_values(child_value.dereference(), children_x, children_y, recursion_level - 1) + children_y += child_height + children_height += child_height + width = max(width, NODE_SPACING + child_width) + merge_dict(result, child_nodes) + else: + pass # TODO: draw null pointers somehow + + height = max(NODE_SPACING, children_height) + return width, height, result def create_viewer_nodes(value, recursion_level): # create the nodes + print "creating nodes" width, height, nodes = visit_values(value, 50, 50, recursion_level) + print "creating connections" # create connections between nodes when all the nodes are there for addr in nodes: value = nodes[addr].gdb_value - if value.type.code == gdb.TYPE_CODE_PTR and value != 0: + if type_is_pointer(value.type) and value != 0: + print "pointer node" nodes[addr].connections.append(nodes[str(value)]) else: + print "struct node" for f in value.type.fields(): + print "connection", value, f.name child = value[f.name] - if child.type.code == gdb.TYPE_CODE_PTR and child != 0: + if type_is_pointer(child.type) and child != 0: if str(child) in nodes: nodes[addr].connections.append(nodes[str(child)]) @@ -316,6 +348,8 @@ class ViewerCommand(gdb.Command): else: recursion_level = 10 + is_gtk_main_running = False + try: window = ViewerWindow() window.connect("destroy", gtk.main_quit) @@ -324,9 +358,10 @@ class ViewerCommand(gdb.Command): nodes = create_viewer_nodes(value, recursion_level) window.viewer.nodes = nodes window.viewer.queue_draw() + is_gtk_main_running = True gtk.main() except: - window.destroy() + if is_gtk_main_running: window.destroy() raise #print print_node(value.dereference(), recursion_level) -- 2.34.1