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]

Re: [PATCH] command trace / source verbose mode


Eli Zaretskii wrote:
-  if (file == NULL)
+  if (file == NULL || strlen (file) == 0)
                         ^^^^^^^^^^^^^^^^^^
Nitpicking: isn't it better to use *file == 0 instead?

Ok.


error (_("source command requires pathname of file to source."));

Another nit: the GNU project does not like to use ``pathname''; please use ``file name'' (yes, two words) instead.

This is the original text. I have taken the opportunity to change it.


+Optional -v switch (before the filename) causes each command in\n\
+FILE to be echo as it is executed.\n\
        ^^^^^^^^^^
You meant "to be echoed", right?

Quite so.


 Note that the file \"%s\" is read automatically in this way\n\
 when gdb is started."), gdbinit);

I think "gdb" should be up-cased.

Again, this is the original text, but I have changed it as suggested.


+If you need to debug user-defined commands or sourced files you may find it
+useful to enable command tracing.

This paragraph could benefit from two small changes:


 . enclose "command tracing" in the above sentence in @dfn{}, to make
   it stand out--this is a new term you are introducing here
 . add "@cindex command tracing" before the paragraph

Fixed.


Otherwise, the patch is okay with me. Thanks.

Thanks, I have committed the attached.


I suppose I ought to write a test case for this. Is there any existing test file where this sort of thing belongs, or should I just create a new file?

Andrew
2006-07-21  Andrew Stubbs  <andrew.stubbs@st.com>

	* cli/cli-cmds.c (source_verbose, trace_commands): New variables.
	(source_script): New function.
	(source_verbose_cleanup): New function.
	(source_command): Move old contents to source_script.
	Make function static. Parse -v option and call source_script.
	(init_cli_cmds): Update source command help.
	Add 'set trace-commands' command.
	* cli/cli-script.c (command_next_depth): New static variable.
	(suppress_next_print_command_trace): New static variable.
	(reset_command_nest_depth): New function.
	(print_command_trace): New function.
	(execute_control_command): Split the continue_control and break_control
	cases, add calls to print_command_trace and count the nest depth.
	(while_command): Set suppress_next_print_command_trace.
	(if_command): Likewise.
	* top.c (execute_command): Call print_command_trace.
	* cli/cli-cmds.h (source_verbose, trace_commands): New extern variables.
	(source_command): Change to source_script.
	* main.c (captued_main): Use source_script instead of source_command.
	* top.h (source_command): Change to source_script.
	* event-top.c (display_gdb_prompt): Call reset_command_nest_depth.
	* cli/cli-script.h (print_command_trace): Export.
	(reset_command_nest_depth): Likewise.

docs/
	* gdb.texinfo (Optional warnings and messages): Add
	'set/show trace-commands'.
	(Command files): Add '-v' to source command.

testsuite/
	* gdb.base/default.exp: Update source command error message.
	* gdb.base/help.exp: Update 'help source' message.

Index: src/gdb/cli/cli-cmds.c
===================================================================
--- src.orig/gdb/cli/cli-cmds.c	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/cli/cli-cmds.c	2006-07-21 10:39:22.000000000 +0100
@@ -173,6 +173,11 @@ struct cmd_list_element *showdebuglist;
 struct cmd_list_element *setchecklist;
 
 struct cmd_list_element *showchecklist;
+
+/* Command tracing state.  */
+
+int source_verbose = 0;
+int trace_commands = 0;
 
 /* Utility used everywhere when at least one argument is needed and
    none is supplied. */
@@ -424,17 +429,16 @@ cd_command (char *dir, int from_tty)
 }
 
 void
-source_command (char *args, int from_tty)
+source_script (char *file, int from_tty)
 {
   FILE *stream;
   struct cleanup *old_cleanups;
-  char *file = args;
   char *full_pathname = NULL;
   int fd;
 
-  if (file == NULL)
+  if (file == NULL || *file == 0)
     {
-      error (_("source command requires pathname of file to source."));
+      error (_("source command requires file name of file to source."));
     }
 
   file = tilde_expand (file);
@@ -465,6 +469,51 @@ source_command (char *args, int from_tty
   do_cleanups (old_cleanups);
 }
 
+/* Return the source_verbose global variable to its previous state
+   on exit from the source command, by whatever means.  */
+static void
+source_verbose_cleanup (void *old_value)
+{
+  source_verbose = *(int *)old_value;
+  xfree (old_value);
+}
+
+static void
+source_command (char *args, int from_tty)
+{
+  struct cleanup *old_cleanups;
+  char *file = args;
+  int *old_source_verbose = xmalloc (sizeof(int));
+
+  *old_source_verbose = source_verbose;
+  old_cleanups = make_cleanup (source_verbose_cleanup, old_source_verbose);
+
+  /* -v causes the source command to run in verbose mode.
+     We still have to be able to handle filenames with spaces in a
+     backward compatible way, so buildargv is not appropriate.  */
+
+  if (args)
+    {
+      /* Make sure leading white space does not break the comparisons.  */
+      while (isspace(args[0]))
+	args++;
+
+      /* Is -v the first thing in the string?  */
+      if (args[0] == '-' && args[1] == 'v' && isspace (args[2]))
+	{
+	  source_verbose = 1;
+
+	  /* Trim -v and whitespace from the filename.  */
+	  file = &args[3];
+	  while (isspace (file[0]))
+	    file++;
+	}
+    }
+
+  return source_script (file, from_tty);
+}
+
+
 static void
 echo_command (char *text, int from_tty)
 {
@@ -1182,8 +1231,10 @@ Commands defined in this way may have up
 
   source_help_text = xstrprintf (_("\
 Read commands from a file named FILE.\n\
+Optional -v switch (before the filename) causes each command in\n\
+FILE to be echoed as it is executed.\n\
 Note that the file \"%s\" is read automatically in this way\n\
-when gdb is started."), gdbinit);
+when GDB is started."), gdbinit);
   c = add_cmd ("source", class_support, source_command,
 	       source_help_text, &cmdlist);
   set_cmd_completer (c, filename_completer);
@@ -1364,4 +1415,12 @@ Show the max call depth for user-defined
 			   NULL,
 			   show_max_user_call_depth,
 			   &setlist, &showlist);
+
+  add_setshow_boolean_cmd ("trace-commands", no_class, &trace_commands, _("\
+Set tracing of GDB CLI commands."), _("\
+Show state of GDB CLI command tracing."), _("\
+When 'on', each command is displayed as it is executed."),
+			   NULL,
+			   NULL,
+			   &setlist, &showlist);
 }
Index: src/gdb/cli/cli-script.c
===================================================================
--- src.orig/gdb/cli/cli-script.c	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/cli/cli-script.c	2006-07-20 15:52:22.000000000 +0100
@@ -46,9 +46,15 @@ static struct cleanup * setup_user_args 
 
 static void validate_comname (char *);
 
-/* Level of control structure.  */
+/* Level of control structure when reading.  */
 static int control_level;
 
+/* Level of control structure when executing.  */
+static int command_nest_depth = 1;
+
+/* This is to prevent certain commands being printed twice.  */
+static int suppress_next_print_command_trace = 0;
+
 /* Structure for arguments to user defined functions.  */
 #define MAXUSERARGS 10
 struct user_args
@@ -293,6 +299,46 @@ execute_user_command (struct cmd_list_el
   do_cleanups (old_chain);
 }
 
+/* This function is called every time GDB prints a prompt.
+   It ensures that errors and the like to not confuse the command tracing.  */
+
+void
+reset_command_nest_depth (void)
+{
+  command_nest_depth = 1;
+
+  /* Just in case.  */
+  suppress_next_print_command_trace = 0;
+}
+
+/* Print the command, prefixed with '+' to represent the call depth.
+   This is slightly complicated because this function may be called
+   from execute_command and execute_control_command.  Unfortunately
+   execute_command also prints the top level control commands.
+   In these cases execute_command will call execute_control_command
+   via while_command or if_command.  Inner levels of 'if' and 'while'
+   are dealt with directly.  Therefore we can use these functions
+   to determine whether the command has been printed already or not.  */
+void
+print_command_trace (const char *cmd)
+{
+  int i;
+
+  if (suppress_next_print_command_trace)
+    {
+      suppress_next_print_command_trace = 0;
+      return;
+    }
+
+  if (!source_verbose && !trace_commands)
+    return;
+
+  for (i=0; i < command_nest_depth; i++)
+    printf_filtered ("+");
+
+  printf_filtered ("%s\n", cmd);
+}
+
 enum command_control_type
 execute_control_command (struct command_line *cmd)
 {
@@ -322,7 +368,16 @@ execute_control_command (struct command_
       break;
 
     case continue_control:
+      print_command_trace ("loop_continue");
+
+      /* Return for "continue", and "break" so we can either
+         continue the loop at the top, or break out.  */
+      ret = cmd->control_type;
+      break;
+
     case break_control:
+      print_command_trace ("loop_break");
+
       /* Return for "continue", and "break" so we can either
          continue the loop at the top, or break out.  */
       ret = cmd->control_type;
@@ -330,6 +385,10 @@ execute_control_command (struct command_
 
     case while_control:
       {
+	char *buffer = alloca (strlen (cmd->line) + 7);
+	sprintf (buffer, "while %s", cmd->line);
+	print_command_trace (buffer);
+
 	/* Parse the loop control expression for the while statement.  */
 	new_line = insert_args (cmd->line);
 	if (!new_line)
@@ -362,7 +421,9 @@ execute_control_command (struct command_
 	    current = *cmd->body_list;
 	    while (current)
 	      {
+		command_nest_depth++;
 		ret = execute_control_command (current);
+		command_nest_depth--;
 
 		/* If we got an error, or a "break" command, then stop
 		   looping.  */
@@ -391,6 +452,10 @@ execute_control_command (struct command_
 
     case if_control:
       {
+	char *buffer = alloca (strlen (cmd->line) + 4);
+	sprintf (buffer, "if %s", cmd->line);
+	print_command_trace (buffer);
+
 	new_line = insert_args (cmd->line);
 	if (!new_line)
 	  break;
@@ -417,7 +482,9 @@ execute_control_command (struct command_
 	/* Execute commands in the given arm.  */
 	while (current)
 	  {
+	    command_nest_depth++;
 	    ret = execute_control_command (current);
+	    command_nest_depth--;
 
 	    /* If we got an error, get out.  */
 	    if (ret != simple_control)
@@ -454,6 +521,7 @@ while_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
+  suppress_next_print_command_trace = 1;
   execute_control_command (command);
   free_command_lines (&command);
 }
@@ -472,6 +540,7 @@ if_command (char *arg, int from_tty)
   if (command == NULL)
     return;
 
+  suppress_next_print_command_trace = 1;
   execute_control_command (command);
   free_command_lines (&command);
 }
Index: src/gdb/top.c
===================================================================
--- src.orig/gdb/top.c	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/top.c	2006-07-20 15:52:30.000000000 +0100
@@ -400,6 +400,9 @@ execute_command (char *p, int from_tty)
       char *arg;
       line = p;
 
+      /* If trace-commands is set then this will print this command.  */
+      print_command_trace (p);
+
       c = lookup_cmd (&p, cmdlist, "", 0, 1);
 
       /* If the target is running, we allow only a limited set of
Index: src/gdb/testsuite/gdb.base/help.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/help.exp	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/testsuite/gdb.base/help.exp	2006-07-21 10:44:33.000000000 +0100
@@ -533,7 +533,7 @@ gdb_test "help stepi" "Step one instruct
 gdb_test "help signal" "Continue program giving it signal.*" "help signal"
 # test help source
 # vxgdb reads .vxgdbinit
-gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when gdb is started\." "help source"
+gdb_test "help source" "Read commands from a file named FILE\.\[\r\n\]+Optional -v switch \\(before the filename\\) causes each command in\[\r\n\]+FILE to be echoed as it is executed\.\[\r\n\]+Note that the file \"\[^\"\]*\" is read automatically in this way\[\r\n\]+when GDB is started\." "help source"
 # test help stack
 gdb_test "help stack" "Examining the stack\..*\[\r\n\]+When the program being debugged stops, gdb selects the innermost frame\.\[\r\n\]+The commands below can be used to select other frames by number or address\.\[\r\n\]+List of commands:\[\r\n\]+backtrace -- Print backtrace of all stack frames\[\r\n\]+bt -- Print backtrace of all stack frames\[\r\n\]+down -- Select and print stack frame called by this one\[\r\n\]+frame -- Select and print a stack frame\[\r\n\]+return -- Make selected stack frame return to its caller\[\r\n\]+select-frame -- Select a stack frame without printing anything\[\r\n\]+up -- Select and print stack frame that called this one\[\r\n\]+Type \"help\" followed by command name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help stack"
 # test help status
Index: src/gdb/cli/cli-cmds.h
===================================================================
--- src.orig/gdb/cli/cli-cmds.h	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/cli/cli-cmds.h	2006-07-20 15:52:22.000000000 +0100
@@ -115,11 +115,16 @@ extern void cd_command (char *, int);
 
 extern void quit_command (char *, int);
 
-extern void source_command (char *, int);
+extern void source_script (char *, int);
 
 /* Used everywhere whenever at least one parameter is required and
   none is specified. */
 
 extern NORETURN void error_no_arg (char *) ATTR_NORETURN;
 
+/* Command tracing state.  */
+
+extern int source_verbose;
+extern int trace_commands;
+
 #endif /* !defined (CLI_CMDS_H) */
Index: src/gdb/doc/gdb.texinfo
===================================================================
--- src.orig/gdb/doc/gdb.texinfo	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/doc/gdb.texinfo	2006-07-21 10:42:11.000000000 +0100
@@ -15999,6 +15999,23 @@ Displays state of confirmation requests.
 
 @end table
 
+@cindex command tracing
+If you need to debug user-defined commands or sourced files you may find it
+useful to enable @dfn{command tracing}.  In this mode each command will be
+printed as it is executed, prefixed with one or more @samp{+} symbols, the
+quantity denoting the call depth of each command.
+
+@table @code
+@kindex set trace-commands
+@cindex command scripts, debugging
+@item set trace-commands on
+Enable command tracing.
+@item set trace-commands off
+Disable command tracing.
+@item show trace-commands
+Display the current state of command tracing.
+@end table
+
 @node Debugging Output
 @section Optional messages about internal happenings
 @cindex optional debugging messages
@@ -16347,7 +16364,7 @@ command:
 @table @code
 @kindex source
 @cindex execute commands from a file
-@item source @var{filename}
+@item source [@code{-v}] @var{filename}
 Execute the command file @var{filename}.
 @end table
 
@@ -16360,6 +16377,10 @@ execution of the command file and contro
 @value{GDBN} searches for @var{filename} in the current directory and then
 on the search path (specified with the @samp{directory} command).
 
+If @code{-v}, for verbose mode, is given then @value{GDBN} displays
+each command as it is executed.  The option must be given before
+@var{filename}, and is interpreted as part of the filename anywhere else.
+
 Commands that would ask for confirmation if used interactively proceed
 without asking when used in a command file.  Many @value{GDBN} commands that
 normally print messages to say what they are doing omit the messages
Index: src/gdb/main.c
===================================================================
--- src.orig/gdb/main.c	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/main.c	2006-07-20 15:52:22.000000000 +0100
@@ -643,7 +643,7 @@ extern int gdbtk_test (char *);
 
       if (!inhibit_gdbinit)
 	{
-	  catch_command_errors (source_command, homeinit, 0, RETURN_MASK_ALL);
+	  catch_command_errors (source_script, homeinit, 0, RETURN_MASK_ALL);
 	}
 
       /* Do stats; no need to do them elsewhere since we'll only
@@ -730,7 +730,7 @@ extern int gdbtk_test (char *);
       || memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat)))
     if (!inhibit_gdbinit)
       {
-	catch_command_errors (source_command, gdbinit, 0, RETURN_MASK_ALL);
+	catch_command_errors (source_script, gdbinit, 0, RETURN_MASK_ALL);
       }
 
   for (i = 0; i < ncmd; i++)
@@ -748,12 +748,12 @@ extern int gdbtk_test (char *);
 	    read_command_file (stdin);
 	  else
 #endif
-	    source_command (cmdarg[i], !batch);
+	    source_script (cmdarg[i], !batch);
 	  do_cleanups (ALL_CLEANUPS);
 	}
 #endif
       if (cmdarg[i].type == CMDARG_FILE)
-        catch_command_errors (source_command, cmdarg[i].string,
+        catch_command_errors (source_script, cmdarg[i].string,
 			      !batch, RETURN_MASK_ALL);
       else  /* cmdarg[i].type == CMDARG_COMMAND */
         catch_command_errors (execute_command, cmdarg[i].string,
Index: src/gdb/top.h
===================================================================
--- src.orig/gdb/top.h	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/top.h	2006-07-20 15:52:22.000000000 +0100
@@ -36,7 +36,7 @@ extern char gdbinit[];
 
 extern void print_gdb_version (struct ui_file *);
 
-extern void source_command (char *, int);
+extern void source_script (char *, int);
 extern void cd_command (char *, int);
 extern void read_command_file (FILE *);
 extern void init_history (void);
Index: src/gdb/event-top.c
===================================================================
--- src.orig/gdb/event-top.c	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/event-top.c	2006-07-20 15:52:22.000000000 +0100
@@ -32,6 +32,7 @@
 #include "interps.h"
 #include <signal.h>
 #include "exceptions.h"
+#include "cli/cli-script.h"     /* for reset_command_nest_depth */
 
 /* For dont_repeat() */
 #include "gdbcmd.h"
@@ -260,6 +261,9 @@ display_gdb_prompt (char *new_prompt)
   int prompt_length = 0;
   char *gdb_prompt = get_prompt ();
 
+  /* Reset the nesting depth used when trace-commands is set.  */
+  reset_command_nest_depth ();
+
   /* Each interpreter has its own rules on displaying the command
      prompt.  */
   if (!current_interp_display_prompt_p ())
Index: src/gdb/cli/cli-script.h
===================================================================
--- src.orig/gdb/cli/cli-script.h	2006-07-20 15:41:13.000000000 +0100
+++ src/gdb/cli/cli-script.h	2006-07-20 15:52:22.000000000 +0100
@@ -53,4 +53,12 @@ struct cleanup *make_cleanup_free_comman
 
 extern void execute_user_command (struct cmd_list_element *c, char *args);
 
+/* Exported to top.c */
+
+extern void print_command_trace (const char *cmd);
+
+/* Exported to event-top.c */
+
+extern void reset_command_nest_depth (void);
+
 #endif /* !defined (CLI_SCRIPT_H) */
Index: src/gdb/testsuite/gdb.base/default.exp
===================================================================
--- src.orig/gdb/testsuite/gdb.base/default.exp	2006-02-23 18:24:34.000000000 +0000
+++ src/gdb/testsuite/gdb.base/default.exp	2006-07-21 10:46:31.000000000 +0100
@@ -682,7 +682,7 @@ gdb_test "stepi" "The program is not bei
 #test signal
 gdb_test "signal" "The program is not being run." "signal"
 #test source
-gdb_test "source" "source command requires pathname of file to source..*|No such file or directory.*" "source"
+gdb_test "source" "source command requires file name of file to source..*|No such file or directory.*" "source"
 #test step "s" abbreviation
 gdb_test "s" "The program is not being run." "step \"s\" abbreviation #2"
 #test step

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