This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] gdb output pipelining to shell


At present, there is no way to pass the output of a gdb command
directly to the shell for further processing. For example, something
similar is not permitted:
    (gdb) thread apply all bt | less

This kind of feature is quite helpful in a scenario where a program
under debugger has hundreds of threads running and one wants to
examine the stack-trace of all the threads at once. The current
behaviour of gdb makes it somewhat difficult since the entire output
of gdb command (sometimes more than a number of pages) is dumped onto
the screen. One can always redirect the output of gdb using logging
mechanism, but that requires offline analysis of the log-file which
may not be acceptable in certain situations. Another option is to get
a shell using gdb's shell command, but that forces one every time to
source the shell profile. Furthermore, the log-file contains entire
debug information, parsing that huge file is resource and time
consuming.

I have implemented a feature which will allow one to pass the output
of any gdb command to the shell for further processing.

2011-07-09 Abhijit Halder <abhijit.k.halder@symantec.com>

   * top.c (execute_command_to_pipe): New function.
    (parse_for_shell_command): New function
    (execute_command): Update.
   * ui-file.c (gdb_modify_io): New function.
   * ui-file.h (gdb_modify_io): Prototype.

 top.c     |   74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 ui-file.c |   15 ++++++++++++
 ui-file.h |    3 ++
 3 files changed, 91 insertions(+), 1 deletion(-)

Regards,
Abhijit Halder
diff -rup src//gdb/top.c dst//gdb/top.c
--- src//gdb/top.c	2011-06-28 00:51:50.000000000 +0530
+++ dst//gdb/top.c	2011-07-15 13:48:19.943911979 +0530
@@ -48,6 +48,7 @@
 #include "event-loop.h"
 #include "gdbthread.h"
 #include "python/python.h"
+#include "ui-file.h"
 
 /* readline include files.  */
 #include "readline/readline.h"
@@ -358,6 +359,68 @@ prepare_execute_command (void)
   return cleanup;
 }
 
+char *
+parse_for_shell_command (char *p)
+{
+  char *sh_cmd, *cpos, *spos, *epos;
+  int quote_cnt = 0;
+
+  if ((sh_cmd = strchr (p, '|')) != NULL)
+    {
+      spos = p;
+      epos = p + strlen (p) - 1;
+
+      for (;;)
+    {
+      for (cpos = spos; (cpos = memchr (cpos, '"', (sh_cmd-cpos))) != NULL; cpos++)
+        quote_cnt++;
+      spos = (sh_cmd + 1);
+      if ((quote_cnt % 2) == 0 || (sh_cmd = strchr (spos, '|')) == NULL)
+        break;
+    }
+
+    if (sh_cmd == NULL)
+      return NULL;
+
+    cpos = spos;
+    while (isspace(*cpos))
+      cpos++;
+
+    if (*cpos != '{')
+      return NULL;
+
+    *cpos = ' ';
+
+    cpos = epos;
+    while (isspace(*cpos))
+      cpos--;
+
+    if (*cpos != '}')
+      return NULL;
+
+    *cpos = ' ';
+    }
+
+  if (sh_cmd)
+    *sh_cmd++ = '\0';
+
+  return sh_cmd;
+}
+
+/* Run execute_command for P and FROM_TTY. Write output in pipe, 
+   do not display it to the screen.  */
+
+void
+execute_command_to_pipe (char *p, int from_tty, FILE *pipe)
+{
+  FILE *file;
+
+  file = gdb_modify_io (gdb_stdout, pipe);
+  execute_command (p, from_tty);
+  pipe = gdb_modify_io (gdb_stdout, file);
+  pclose (pipe);
+}
+
 /* Execute the line P as a command, in the current user context.
    Pass FROM_TTY as second argument to the defining function.  */
 
@@ -368,7 +431,16 @@ execute_command (char *p, int from_tty)
   struct cmd_list_element *c;
   enum language flang;
   static int warned = 0;
-  char *line;
+  char *line, *sh_cmd;
+
+  if ((sh_cmd = parse_for_shell_command (p)) != NULL) 
+    {
+      FILE *pipe;
+
+      pipe = popen (sh_cmd, "w");
+      execute_command_to_pipe (p, from_tty, pipe);
+      return;
+    }
 
   cleanup = prepare_execute_command ();
 
diff -rup src//gdb/ui-file.c dst//gdb/ui-file.c
--- src//gdb/ui-file.c	2011-05-14 11:14:36.000000000 +0530
+++ dst//gdb/ui-file.c	2011-07-15 13:49:34.999910332 +0530
@@ -617,6 +617,21 @@ struct ui_file *
 stdio_fileopen (FILE *file)
 {
   return stdio_file_new (file, 0);
+
+}
+
+FILE *
+gdb_modify_io (struct ui_file *file, FILE *iostream_new)
+{
+  FILE *iostream_old;
+  struct stdio_file *stdio = ui_file_data (file);
+
+  if (stdio->magic != &stdio_file_magic)
+    internal_error (__FILE__, __LINE__,
+		    _("gdb_modify_io: bad magic number"));
+  iostream_old = stdio->file;
+  stdio->file = iostream_new;
+  return iostream_old;
 }
 
 struct ui_file *
diff -rup src//gdb/ui-file.h dst//gdb/ui-file.h
--- src//gdb/ui-file.h	2011-05-13 22:58:20.000000000 +0530
+++ dst//gdb/ui-file.h	2011-07-15 13:48:54.603912199 +0530
@@ -126,6 +126,9 @@ extern struct ui_file *stdio_fileopen (F
 /* Open NAME returning an STDIO based UI_FILE.  */
 extern struct ui_file *gdb_fopen (char *name, char *mode);
 
+/* Modify the file pointer of an STDIO based UI_FILE. */
+FILE *gdb_modify_io (struct ui_file *file, FILE *iostream_new);
+
 /* Create a file which writes to both ONE and TWO.  CLOSE_ONE
    and CLOSE_TWO indicate whether the original files should be
    closed when the new file is closed.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]