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 {}
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):
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)
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)
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
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:
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 = {}
# 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()
<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>
<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>
<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>
<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>
<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>