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
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
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, ("<value>", str(value)))
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)])
else:
recursion_level = 10
+ is_gtk_main_running = False
+
try:
window = ViewerWindow()
window.connect("destroy", gtk.main_quit)
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)