Re: [RFA v3 01/13] Rationalize "backtrace" command line parsing

Tom Tromey
2018-03-26T20:45:00Z

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

Eli> I expected to see something like this, before the description of
Eli> arguments:

Eli> @table @code
Eli> @item backtrace [@var{args}@dots{}]
Eli> @itemx bt [@var{args}@dots{}]
Eli> Print the backtrace of the entire stack. The optional @var{args} can
Eli> be one of the following:

Eli> followed by your table of arguments.

Like this?

Tom

commit f8f0cf13d9a8c66a85b287b533c231a44d18c516
Author: Tom Tromey <tom@tromey.com>
Date: Sun Apr 23 10:54:33 2017 -0600

Rationalize "backtrace" command line parsing

The backtrace command has peculiar command-line parsing. In
particular, it splits the command line, then loops over the arguments.
If it sees a word it recognizes, like "full", it effectively drops
this word from the argument vector. Then, it pastes together the
remaining arguments, passing them on to backtrace_command_1, which in
turn passes the resulting string to parse_and_eval_long.

The documentation doesn't mention the parse_and_eval_long at all, so
it is a bit of a hidden feature that you can "bt 3*2". The strange
algorithm above also means you can "bt 3 * no-filters 2" and get 6
frames...

This patch changes backtrace's command line parsing to be a bit more
rational. Now, special words like "full" are only recognized at the
start of the command.

This also updates the documentation to describe the various bt options
individually.

gdb/ChangeLog
2018-03-23 Tom Tromey <tom@tromey.com>

* stack.c (backtrace_command): Rewrite command line parsing.

gdb/doc/ChangeLog
2018-03-23 Tom Tromey <tom@tromey.com>

* gdb.texinfo (Backtrace): Describe options individually.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 47e6cff43d..90c66e3955 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,7 @@
+2018-03-23 Tom Tromey <tom@tromey.com>
+
+ * stack.c (backtrace_command): Rewrite command line parsing.
+
2018-03-26 Simon Marchi <simon.marchi@ericsson.com>

* dwarf2read.c (DEF_VEC_I(offset_type)): Remove.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 2441f15431..339f1d51ad 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2018-03-23 Tom Tromey <tom@tromey.com>
+
+ * gdb.texinfo (Backtrace): Describe options individually.
+
2018-03-19 Tom Tromey <tom@tromey.com>

* observer.texi: Remove.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 74e0fdb4a4..28254c9e68 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -7307,45 +7307,43 @@ frame (frame zero), followed by its caller (frame one), and on up the
stack.

@anchor{backtrace-command}
-@table @code
@kindex backtrace
@kindex bt @r{(@code{backtrace})}
-@item backtrace
-@itemx bt
-Print a backtrace of the entire stack: one line per frame for all
-frames in the stack.
-
-You can stop the backtrace at any time by typing the system interrupt
-character, normally @kbd{Ctrl-c}.
-
-@item backtrace @var{n}
-@itemx bt @var{n}
-Similar, but print only the innermost @var{n} frames.
-
-@item backtrace -@var{n}
-@itemx bt -@var{n}
-Similar, but print only the outermost @var{n} frames.
-
-@item backtrace full
-@itemx bt full
-@itemx bt full @var{n}
-@itemx bt full -@var{n}
-Print the values of the local variables also. As described above,
-@var{n} specifies the number of frames to print.
-
-@item backtrace no-filters
-@itemx bt no-filters
-@itemx bt no-filters @var{n}
-@itemx bt no-filters -@var{n}
-@itemx bt no-filters full
-@itemx bt no-filters full @var{n}
-@itemx bt no-filters full -@var{n}
+To print a backtrace of the entire stack, use the @code{backtrace}
+command, or its alias @code{bt}. This command will print one line per
+frame for frames in the stack. By default, all stack frames are
+printed. You can stop the backtrace at any time by typing the system
+interrupt character, normally @kbd{Ctrl-c}.
+
+@table @code
+@item backtrace [@var{args}@dots{}]
+@itemx bt [@var{args}@dots{}]
+Print the backtrace of the entire stack. The optional @var{args} can
+be one of the following:
+
+@table @code
+@item @var{n}
+@itemx @var{n}
+Print only the innermost @var{n} frames, where @var{n} is a positive
+number.
+
+@item -@var{n}
+@itemx -@var{n}
+Print only the outermost @var{n} frames, where @var{n} is a positive
+number.
+
+@item full
+Print the values of the local variables also. This can be combined
+with a number to limit the number of frames shown.
+
+@item no-filters
Do not run Python frame filters on this backtrace. @xref{Frame
Filter API}, for more information. Additionally use @ref{disable
frame-filter all} to turn off all frame filters. This is only
relevant when @value{GDBN} has been configured with @code{Python}
support.
@end table
+@end table

@kindex where
@kindex info stack
diff --git a/gdb/stack.c b/gdb/stack.c
index aad8fcd987..13af6594a9 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1850,61 +1850,39 @@ backtrace_command_1 (const char *count_exp, int show_locals, int no_filters,
static void
backtrace_command (const char *arg, int from_tty)
{
- int fulltrace_arg = -1, arglen = 0, argc = 0, no_filters = -1;
- int user_arg = 0;
+ bool fulltrace = false;
+ bool filters = true;

- std::string reconstructed_arg;
if (arg)
{
- char **argv;
- int i;
+ bool done = false;

- gdb_argv built_argv (arg);
- argv = built_argv.get ();
- argc = 0;
- for (i = 0; argv[i]; i++)
+ while (!done)
{
- unsigned int j;
+ const char *save_arg = arg;
+ std::string this_arg = extract_arg (&arg);

- for (j = 0; j < strlen (argv[i]); j++)
- argv[i][j] = TOLOWER (argv[i][j]);
+ if (this_arg.empty ())
+ break;

- if (no_filters < 0 && subset_compare (argv[i], "no-filters"))
- no_filters = argc;
+ if (subset_compare (this_arg.c_str (), "no-filters"))
+ filters = false;
+ else if (subset_compare (this_arg.c_str (), "full"))
+ fulltrace = true;
else
{
- if (fulltrace_arg < 0 && subset_compare (argv[i], "full"))
- fulltrace_arg = argc;
- else
- {
- user_arg++;
- arglen += strlen (argv[i]);
- }
- }
- argc++;
- }
- arglen += user_arg;
- if (fulltrace_arg >= 0 || no_filters >= 0)
- {
- if (arglen > 0)
- {
- for (i = 0; i < argc; i++)
- {
- if (i != fulltrace_arg && i != no_filters)
- {
- reconstructed_arg += argv[i];
- reconstructed_arg += " ";
- }
- }
- arg = reconstructed_arg.c_str ();
+ /* Not a recognized argument, so stop. */
+ arg = save_arg;
+ done = true;
}
- else
- arg = NULL;
}
+
+ if (*arg == '\0')
+ arg = NULL;
}

- backtrace_command_1 (arg, fulltrace_arg >= 0 /* show_locals */,
- no_filters >= 0 /* no frame-filters */, from_tty);
+ backtrace_command_1 (arg, fulltrace /* show_locals */,
+ !filters /* no frame-filters */, from_tty);
}

/* Iterate over the local variables of a block B, calling CB with