diff mbox

Add debug_function_to_file

Message ID 56C70D2F.4040907@mentor.com
State New
Headers show

Commit Message

Tom de Vries Feb. 19, 2016, 12:40 p.m. UTC
On 19/02/16 10:44, Richard Biener wrote:
> On Fri, Feb 19, 2016 at 1:37 AM, Tom de Vries <Tom_deVries@mentor.com> wrote:
>> 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
>
> I used popen

It was suggested in the other thread ( 
https://gcc.gnu.org/ml/gcc-patches/2016-02/msg01172.html ) that there 
were portability issues with popen, so I tried to avoid it.

Anyway, I guess it's probably best to try to minimize interaction with 
the inferior, if we can handle it in python instead.

> specifically to allow you continue debugging while keeping the dot
> process open and functional.

Ah, I see.

> That would be restored with adding a '&' after
> the command but then we race with the file removal ...
>
> The following works for me though:
>
>          # Show graph in temp file
>          os.system("( dot -Tx11 %s; rm %s ) &" % (filename, filename) )
>
> dot_fn()
>

Yep, that works for me too.

[ Btw, I prefer generating dot graps in pdf format. In the pdf viewer, 
you can search for variable names, bb numbers, etc.

It's easy enough to generate the pdf file, but I'm not sure how in 
python we can open the pdf viewer, and wait for it to finish in a 
portable way. xdg-open is linux-only and doesn't seem to wait-on 
-finish. And pythons webbrowser.open_new does wait-on-finish in some 
cases, but not in others, and I don't understand the documentation well 
enough to know if that's going to affect this use-case. ]

> ok for trunk with that change and thanks for the help!
>

You're welcome :) . [ I used to use python regularly (though at a basic 
level) about 6 years ago, but haven't used it since, so it was good to 
revive that skill a bit. ]

I'll commit as attached, unless David has further review comments on 
dot-fn (or comments on dump-fn which would also apply for dot-fn).

Thanks,
- Tom
diff mbox

Patch

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);
 }