On 18/02/16 16:27, Richard Biener wrote:
Attached is what I have for now, it works if you call it like
(gdb) dot-fn cfun
(gdb) dot-fn cfun, 1<<6
w/o that arg parsing;)
I'll play with it some more tomorrow.
This version:
- uses arg parsing
- adds error handling
- uses a temp file instead of a pipe
- uses python os.system to call dot
- adds documentation
Thanks,
- Tom
Add dot-fn to gdbhooks.py
2016-02-18 Richard Biener <rguent...@suse.de>
* graph.c: Include dumpfile.h.
(print_graph_cfg): Split into three overloads.
* gdbhooks.py (dot-fn): New command.
---
gcc/gdbhooks.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gcc/graph.c | 32 +++++++++++++++++++++----
2 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/gcc/gdbhooks.py b/gcc/gdbhooks.py
index cffac2a..bc2407f 100644
--- a/gcc/gdbhooks.py
+++ b/gcc/gdbhooks.py
@@ -133,6 +133,7 @@ Instead (for now) you must access m_vecdata:
import os.path
import re
import sys
+import tempfile
import gdb
import gdb.printing
@@ -653,4 +654,77 @@ class debug_function_to_file(gdb.Command):
debug_function_to_file()
+class dot_fn(gdb.Command):
+ """
+ A custom command to show a gimple/rtl function control flow graph.
+ By default, it show the current function, but the function can also be
+ specified.
+
+ Examples of use:
+ (gdb) dot-fn
+ (gdb) dot-fn cfun
+ (gdb) dot-fn cfun 0
+ (gdb) dot-fn cfun dump_flags
+ """
+ def __init__(self):
+ gdb.Command.__init__(self, 'dot-fn', gdb.COMMAND_USER)
+
+ def invoke(self, arg, from_tty):
+ # Parse args, check number of args
+ args = gdb.string_to_argv(arg)
+ if len(args) > 2:
+ print("Too many arguments")
+ return
+
+ # Set func
+ if len(args) >= 1:
+ funcname = args[0]
+ printfuncname = "function %s" % funcname
+ else:
+ funcname = "cfun"
+ printfuncname = "current function"
+ func = gdb.parse_and_eval(funcname)
+ if func == 0:
+ print("Could not find %s" % printfuncname)
+ return
+ func = "(struct function *)%s" % func
+
+ # Set flags
+ if len(args) >= 2:
+ flags = gdb.parse_and_eval(args[1])
+ else:
+ flags = 0
+
+ # Get temp file
+ f = tempfile.NamedTemporaryFile(delete=False)
+ filename = f.name
+
+ # Close and reopen temp file to get C FILE*
+ f.close()
+ fp = gdb.parse_and_eval("fopen (\"%s\", \"w\")" % filename)
+ if fp == 0:
+ print("Cannot open temp file")
+ return
+ fp = "(FILE *)%u" % fp
+
+ # Write graph to temp file
+ _ = gdb.parse_and_eval("start_graph_dump (%s, \"<debug>\")" % fp)
+ _ = gdb.parse_and_eval("print_graph_cfg (%s, %s, %u)"
+ % (fp, func, flags))
+ _ = gdb.parse_and_eval("end_graph_dump (%s)" % fp)
+
+ # Close temp file
+ ret = gdb.parse_and_eval("fclose (%s)" % fp)
+ if ret != 0:
+ print("Could not close temp file: %s" % filename)
+ return
+
+ # Show graph in temp file
+ os.system("dot -Tx11 %s" % filename)
+
+ # Remove temp file
+ os.remove(filename)
+
+dot_fn()
+
print('Successfully loaded GDB hooks for GCC')
diff --git a/gcc/graph.c b/gcc/graph.c
index 1b28c67..dd5bc4e 100644
--- a/gcc/graph.c
+++ b/gcc/graph.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfganal.h"
#include "cfgloop.h"
#include "graph.h"
+#include "dumpfile.h"
/* DOT files with the .dot extension are recognized as document templates
by a well-known piece of word processing software out of Redmond, WA.
@@ -272,14 +273,13 @@ draw_cfg_edges (pretty_printer *pp, struct function *fun)
subgraphs right for GraphViz, which requires nodes to be defined
before edges to cluster nodes properly. */
-void
-print_graph_cfg (const char *base, struct function *fun)
+void DEBUG_FUNCTION
+print_graph_cfg (FILE *fp, struct function *fun)
{
- const char *funcname = function_name (fun);
- FILE *fp = open_graph_file (base, "a");
pretty_printer graph_slim_pp;
graph_slim_pp.buffer->stream = fp;
pretty_printer *const pp = &graph_slim_pp;
+ const char *funcname = function_name (fun);
pp_printf (pp, "subgraph \"cluster_%s\" {\n"
"\tstyle=\"dashed\";\n"
"\tcolor=\"black\";\n"
@@ -289,6 +289,30 @@ print_graph_cfg (const char *base, struct function *fun)
draw_cfg_edges (pp, fun);
pp_printf (pp, "}\n");
pp_flush (pp);
+}
+
+/* Overload with additional flag argument. */
+
+void DEBUG_FUNCTION
+print_graph_cfg (FILE *fp, struct function *fun, int flags)
+{
+ int saved_dump_flags = dump_flags;
+ dump_flags = flags;
+ print_graph_cfg (fp, fun);
+ dump_flags = saved_dump_flags;
+}
+
+
+/* Print a graphical representation of the CFG of function FUN.
+ First print all basic blocks. Draw all edges at the end to get
+ subgraphs right for GraphViz, which requires nodes to be defined
+ before edges to cluster nodes properly. */
+
+void
+print_graph_cfg (const char *base, struct function *fun)
+{
+ FILE *fp = open_graph_file (base, "a");
+ print_graph_cfg (fp, fun);
fclose (fp);
}