diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 768c7822f7..177a63a18d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,29 @@ +2006-07-21 Andrew Stubbs + + * 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. + 2006-07-20 Daniel Jacobowitz * eval.c (evaluate_struct_tuple): Skip static fields. diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index f66abdeb07..fdff3942cf 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -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 to ten arguments.")); 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 commands."), NULL, 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); } diff --git a/gdb/cli/cli-cmds.h b/gdb/cli/cli-cmds.h index 1aad034120..228e6aaf16 100644 --- a/gdb/cli/cli-cmds.h +++ b/gdb/cli/cli-cmds.h @@ -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) */ diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c index 643eb74933..1b5d342b3a 100644 --- a/gdb/cli/cli-script.c +++ b/gdb/cli/cli-script.c @@ -46,9 +46,15 @@ static struct cleanup * setup_user_args (char *p); 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_element *c, char *args) 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_line *cmd) 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_line *cmd) 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_line *cmd) 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_line *cmd) 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_line *cmd) /* 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); } diff --git a/gdb/cli/cli-script.h b/gdb/cli/cli-script.h index 21a5f26548..6f0fc9c2c5 100644 --- a/gdb/cli/cli-script.h +++ b/gdb/cli/cli-script.h @@ -53,4 +53,12 @@ struct cleanup *make_cleanup_free_command_lines (struct command_line **arg); 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) */ diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 5d8a02a824..77c14dc765 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,9 @@ +2006-07-21 Andrew Stubbs + + * gdb.texinfo (Optional warnings and messages): Add + 'set/show trace-commands'. + (Command files): Add '-v' to source command. + 2006-07-12 Daniel Jacobowitz * gdb.texinfo (OS Information): Update qPart reference to diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a16e4d017f..1bac2b86f2 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -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 control is returned to the console. @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 diff --git a/gdb/event-top.c b/gdb/event-top.c index 635ce0fdc5..6e26002dca 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -32,6 +32,7 @@ #include "interps.h" #include #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 ()) diff --git a/gdb/main.c b/gdb/main.c index 8a11f176b7..b6599727f6 100644 --- a/gdb/main.c +++ b/gdb/main.c @@ -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, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 4371abe416..c4f4e8a088 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-07-21 Andrew Stubbs + + * gdb.base/default.exp: Update source command error message. + * gdb.base/help.exp: Update 'help source' message. + 2006-07-20 Daniel Jacobowitz * gdb.cp/bs15503.exp: Update comment for no longer crashing diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp index 1ecf1f7dbe..6027cfe1b6 100644 --- a/gdb/testsuite/gdb.base/default.exp +++ b/gdb/testsuite/gdb.base/default.exp @@ -682,7 +682,7 @@ gdb_test "stepi" "The program is not being run." "stepi" #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 diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/help.exp index 74d3f1ad7e..e9a1c21d93 100644 --- a/gdb/testsuite/gdb.base/help.exp +++ b/gdb/testsuite/gdb.base/help.exp @@ -533,7 +533,7 @@ gdb_test "help stepi" "Step one instruction exactly\.\[\r\n\]+Argument N means d 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 diff --git a/gdb/top.c b/gdb/top.c index e129722ea7..155f2c5176 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -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 diff --git a/gdb/top.h b/gdb/top.h index 591bfa34e3..100ec0cb75 100644 --- a/gdb/top.h +++ b/gdb/top.h @@ -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);