From 0def6db21ed386beae5c7a09288ae8997d778fb2 Mon Sep 17 00:00:00 2001 From: Oliver Wu Date: Wed, 17 Mar 2021 13:59:14 +0800 Subject: [PATCH 1/2] Quote the node name Graphviz doesn't like some special characters in node names. --- ufgraph.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ufgraph.py b/ufgraph.py index 642d9c3..8133871 100644 --- a/ufgraph.py +++ b/ufgraph.py @@ -106,14 +106,13 @@ def build_nodes(): #break out at the end of a frame if line.startswith("_ _ _ _") and not firstline: - break; + break elif line.startswith("_ _ _ _"): - continue; + continue elif line.endswith(":"): #get the new node name - # graphviz doesn't like "!" or "+".. in node names so strip them #new_name = line.split(":")[0].split()[0].replace("!","").replace("+","") - new_name = line.rsplit(":",1)[0].split()[0].replace("!","").replace("+","") + new_name = quoteNodeName(line.rsplit(":",1)[0].split()[0]) #make the connection to the new node if necessary if None != last_node: @@ -148,8 +147,7 @@ def build_nodes(): label_remainder = "" if len(labels) > 4: label_remainder = labels[4].rstrip() - # graphviz doesn't like "!" or "+".. in node names so strip them - jmp_target = label_remainder.split()[0].replace("!","").replace("+","") + jmp_target = quoteNodeName(label_remainder.split()[0]) #public symbols don't.. else: labels = line.split(None,3) @@ -159,8 +157,7 @@ def build_nodes(): label_remainder = "" if len(labels) > 3: label_remainder = labels[3].rstrip() - # graphviz doesn't like "!" or "+".. in node names so strip them - jmp_target = label_remainder.split()[0].replace("!","").replace("+","") + jmp_target = quoteNodeName(label_remainder.split()[0]) new_node.add_label_text(label_addr + " " + label_inst + " " + label_remainder) if ipaddr and label_addr.replace("`","").startswith(ipaddr): @@ -196,6 +193,7 @@ def create_dot_file(nodes, filename): for node in nodes: f.write(node.get_dotformat_connections()) f.write("\n}") + f.close() #launch 'dot' from graphviz and then use the default png viewer via the shell @@ -205,11 +203,10 @@ def render_dot_file(filename): dotproc.wait() os.unlink(filename) return graph_file_path - + #use graphviz package def render_graph(nodes, filename): dot = Digraph(name='windbg_graph', node_attr={'shape': 'box', 'fontname' : 'Lucida Console'}, graph_attr={'splines':'polyline'}) - for anode in nodes: if(anode.has_color()): dot.node(anode.get_nodeName(),anode.get_dotformat_label(), _attributes={'style':'filled', 'fillcolor':'gray'}) @@ -321,6 +318,11 @@ def build_html(graph_images): return html_page +# graphviz doesn't like "!" or "+".. in node names so strip them +# quote the name resolves the issue +def quoteNodeName(name): + return "\"" + name + "\"" + if __name__ == "__main__": parseArgs() From f5218f652084541cd75f8ace8a26d9a0658f4cd1 Mon Sep 17 00:00:00 2001 From: Oliver Wu Date: Wed, 17 Mar 2021 16:23:11 +0800 Subject: [PATCH 2/2] Remove the source path when parsing the frame line The frame may or may not contain the source path if pdb is available. For example: "module!Class::method+0x1fd [C:\src\HelloWorld.cpp @ 2075]" --- ufgraph.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ufgraph.py b/ufgraph.py index 8133871..468cd99 100644 --- a/ufgraph.py +++ b/ufgraph.py @@ -26,6 +26,7 @@ import uuid import subprocess import argparse +import re outputformat = 'png' stackwalkhtml = False @@ -134,6 +135,8 @@ def build_nodes(): elif not new_node: #.. skip lines that fall outside of a node if firstline: + #remvoe source path + line = re.sub(r'\[.*\]','', line) tokens = line.split() #if tokens[len(tokens) - 1] not in frames: frames += [ tokens[len(tokens) - 1] ]