Add dot-fn to gdbhooks.py

2016-02-18  Richard Biener  <rguenther@suse.de>

	* graph.c: Include dumpfile.h.
	(print_graph_cfg): Split into three overloads.
	* gdbhooks.py (dot-fn): New command.

---
 gcc/gdbhooks.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/graph.c     | 32 ++++++++++++++++++++++----
 2 files changed, 98 insertions(+), 4 deletions(-)

diff --git a/gcc/gdbhooks.py b/gcc/gdbhooks.py
index ed72016..1212312 100644
--- a/gcc/gdbhooks.py
+++ b/gcc/gdbhooks.py
@@ -680,4 +680,74 @@ class DumpFn(gdb.Command):
 
 DumpFn()
 
+class DotFn(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\"; rm \"%s\" ) &" % (filename, filename))
+
+DotFn()
+
 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);
 }
 
