mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 04:24:43 +00:00
gdb: add "essential" command class
Currently, there is no way for a new user to have an idea of common useful commands and behaviors from the GDB interface itself, without checking the example session in the documentation. This command class aims to close that gap by providing a set of quickstart commands that allows for any simple debug session to happen without anything too egregious missing. The set of commands was chosen somewhat arbitrarily, based on what I used or missed the most. The one overarching important thing, however, is that the list is kept short, so as to not overwhelm new users. This is confirmed by the newly introduced selftest, essential_command_count, which ensures there are 20 or fewer essential commands. Here's the reasoning for some of the choices: * The command "start" was picked over "run" because combining it with "continue" achieves the same effect, and I prefer it over needing to set a breakpoint on main to stop at the start of the inferior. * The command "ptype" is chosen because I believe it is important to provide a way for the user to check a variable's type from inside GDB, and ptype is a more complete command than the alternative, "whatis". Reviewed-By: Eli Zaretskii <eliz@gnu.org> Approved-By: Tom Tromey <tom@tromey.com>
This commit is contained in:
5
gdb/NEWS
5
gdb/NEWS
@@ -55,6 +55,11 @@ info inferiors
|
||||
as an additional line under the inferior's table entry in the
|
||||
output.
|
||||
|
||||
New command class for help
|
||||
The new command class "essential" has been added, which is a set of
|
||||
commands that we, as developers, believe would be close to a minimal
|
||||
set of commands for a new user of GDB.
|
||||
|
||||
* Changed remote packets
|
||||
|
||||
single-inf-arg in qSupported
|
||||
|
||||
@@ -14916,7 +14916,8 @@ This command may be abbreviated \"disable\"."),
|
||||
&disablelist);
|
||||
|
||||
cmd_list_element *delete_cmd
|
||||
= add_prefix_cmd ("delete", class_breakpoint, delete_command, _("\
|
||||
= add_prefix_cmd ("delete", class_breakpoint | class_essential,
|
||||
delete_command, _("\
|
||||
Delete all or some breakpoints.\n\
|
||||
Usage: delete [BREAKPOINTNUM]...\n\
|
||||
Arguments are breakpoint numbers with spaces in between.\n\
|
||||
@@ -14949,7 +14950,7 @@ See also the \"delete\" command which clears breakpoints by number."));
|
||||
add_com_alias ("cl", clear_cmd, class_breakpoint, 1);
|
||||
|
||||
cmd_list_element *break_cmd
|
||||
= add_com ("break", class_breakpoint, break_command, _("\
|
||||
= add_com ("break", class_breakpoint | class_essential, break_command, _("\
|
||||
Set breakpoint at specified location.\n"
|
||||
BREAK_ARGS_HELP ("break")));
|
||||
set_cmd_completer (break_cmd, location_completer);
|
||||
@@ -15020,7 +15021,7 @@ Options:\n\
|
||||
\n\
|
||||
A watchpoint stops execution of your program whenever the value of\n\
|
||||
an expression changes."), opts);
|
||||
c = add_com ("watch", class_breakpoint, watch_command,
|
||||
c = add_com ("watch", class_breakpoint | class_essential, watch_command,
|
||||
watch_help.c_str ());
|
||||
set_cmd_completer_handle_brkchars (c, watch_command_completer);
|
||||
|
||||
|
||||
@@ -2628,6 +2628,20 @@ INIT_GDB_FILE (cli_cmds)
|
||||
/* Define the classes of commands.
|
||||
They will appear in the help list in alphabetical order. */
|
||||
|
||||
add_cmd ("essential", class_essential, _("\
|
||||
GDB essential commands.\n\
|
||||
Welcome to GDB! This help text aims to provide a quickstart explanation\n\
|
||||
that will allow you to start using GDB. Feel free to use \"help <cmd>\"\n\
|
||||
to get further explanations for any command <cmd>, and check the online\n\
|
||||
documentation for in-depth explanations.\n\
|
||||
Here are some common GDB behaviors that you can expect, which are\n\
|
||||
not tied to any specific command but rather GDB functionality itself:\n\
|
||||
\n\
|
||||
EXPR is any arbitrary expression valid for the current programming language.\n\
|
||||
Pressing <return> with an empty prompt executes the last command again.\n\
|
||||
You can use <tab> to complete commands and symbols. Pressing it twice lists\n\
|
||||
all possible completions if more than one is available."),
|
||||
&cmdlist);
|
||||
add_cmd ("internals", class_maintenance, _("\
|
||||
Maintenance commands.\n\
|
||||
Some gdb commands are provided just for use by gdb maintainers.\n\
|
||||
@@ -2880,7 +2894,7 @@ and send its output to SHELL_COMMAND."));
|
||||
add_com_alias ("|", pipe_cmd, class_support, 0);
|
||||
|
||||
cmd_list_element *list_cmd
|
||||
= add_com ("list", class_files, list_command, _("\
|
||||
= add_com ("list", class_files | class_essential, list_command, _("\
|
||||
List specified function or line.\n\
|
||||
With no argument, lists ten more lines after or around previous listing.\n\
|
||||
\"list +\" lists the ten lines following a previous ten-line listing.\n\
|
||||
@@ -2941,7 +2955,7 @@ Show definitions of non-python/scheme user defined commands.\n\
|
||||
Argument is the name of the user defined command.\n\
|
||||
With no argument, show definitions of all user defined commands."), &showlist);
|
||||
set_cmd_completer (c, show_user_completer);
|
||||
add_com ("apropos", class_support, apropos_command, _("\
|
||||
add_com ("apropos", class_support | class_essential, apropos_command, _("\
|
||||
Search for commands matching a REGEXP.\n\
|
||||
Usage: apropos [-v] REGEXP\n\
|
||||
Flag -v indicates to produce a verbose output, showing full documentation\n\
|
||||
|
||||
@@ -1954,7 +1954,10 @@ help_list (struct cmd_list_element *list, const char *cmdtype,
|
||||
styled_string (command_style.style (), cmdtype),
|
||||
prefix);
|
||||
|
||||
bool recurse = (theclass != all_commands) && (theclass != all_classes);
|
||||
/* Don't recurse if theclass is beginner, since the quickstart
|
||||
help is meant to be direct and not include prefix commands. */
|
||||
bool recurse = (theclass != all_commands) && (theclass != all_classes)
|
||||
&& (theclass != class_essential);
|
||||
help_cmd_list (list, theclass, recurse, stream);
|
||||
|
||||
if (theclass == all_classes)
|
||||
|
||||
@@ -102,6 +102,9 @@ struct cmd_list_element
|
||||
bool is_prefix () const
|
||||
{ return this->subcommands != nullptr; }
|
||||
|
||||
bool is_essential () const
|
||||
{ return (this->theclass & class_essential) != 0; }
|
||||
|
||||
/* Return true if this command is a "command class help" command. For
|
||||
instance, a "stack" dummy command is registered so that one can do
|
||||
"help stack" and show help for all commands of the "stack" class. */
|
||||
|
||||
@@ -64,9 +64,10 @@ enum command_class
|
||||
class_maintenance = 1 << 12, /* internals */
|
||||
class_tui = 1 << 13, /* text-user-interface */
|
||||
class_user = 1 << 14, /* user-defined */
|
||||
class_essential = 1 << 15, /* essential */
|
||||
|
||||
/* Used for "show" commands that have no corresponding "set" command. */
|
||||
no_set_class = 1 << 15
|
||||
no_set_class = 1 << 16
|
||||
};
|
||||
DEF_ENUM_FLAGS_TYPE (enum command_class, command_classes);
|
||||
|
||||
|
||||
@@ -564,6 +564,7 @@ static const scheme_integer_constant command_classes[] =
|
||||
{ "COMMAND_OBSCURE", class_obscure },
|
||||
{ "COMMAND_MAINTENANCE", class_maintenance },
|
||||
{ "COMMAND_USER", class_user },
|
||||
{ "COMMAND_ESSENTIAL", class_essential },
|
||||
|
||||
END_INTEGER_CONSTANTS
|
||||
};
|
||||
|
||||
@@ -3248,7 +3248,7 @@ Upon return, the value returned is printed and put in the value history."));
|
||||
add_com_alias ("fin", finish_cmd, class_run, 1);
|
||||
|
||||
cmd_list_element *next_cmd
|
||||
= add_com ("next", class_run, next_command, _("\
|
||||
= add_com ("next", class_run | class_essential, next_command, _("\
|
||||
Step program, proceeding through subroutine calls.\n\
|
||||
Usage: next [N]\n\
|
||||
Unlike \"step\", if the current source line calls a subroutine,\n\
|
||||
@@ -3257,7 +3257,7 @@ the call, in effect treating it as a single source line."));
|
||||
add_com_alias ("n", next_cmd, class_run, 1);
|
||||
|
||||
cmd_list_element *step_cmd
|
||||
= add_com ("step", class_run, step_command, _("\
|
||||
= add_com ("step", class_run | class_essential, step_command, _("\
|
||||
Step program until it reaches a different source line.\n\
|
||||
Usage: step [N]\n\
|
||||
Argument N means step N times (or till program stops for another \
|
||||
@@ -3291,7 +3291,7 @@ for an address to start at."));
|
||||
add_com_alias ("j", jump_cmd, class_run, 1);
|
||||
|
||||
cmd_list_element *continue_cmd
|
||||
= add_com ("continue", class_run, continue_command, _("\
|
||||
= add_com ("continue", class_run | class_essential, continue_command, _("\
|
||||
Continue program being debugged, after signal or breakpoint.\n\
|
||||
Usage: continue [N]\n\
|
||||
If proceeding from breakpoint, a number N may be used as an argument,\n\
|
||||
@@ -3312,7 +3312,7 @@ RUN_ARGS_HELP));
|
||||
set_cmd_completer (run_cmd, deprecated_filename_completer);
|
||||
add_com_alias ("r", run_cmd, class_run, 1);
|
||||
|
||||
c = add_com ("start", class_run, start_command, _("\
|
||||
c = add_com ("start", class_run | class_essential, start_command, _("\
|
||||
Start the debugged program stopping at the beginning of the main procedure.\n"
|
||||
RUN_ARGS_HELP));
|
||||
set_cmd_completer (c, deprecated_filename_completer);
|
||||
|
||||
@@ -3231,7 +3231,7 @@ No argument means cancel all automatic-display expressions.\n\
|
||||
Do \"info display\" to see current list of code numbers."),
|
||||
&cmdlist);
|
||||
|
||||
c = add_com ("display", class_vars, display_command, _("\
|
||||
c = add_com ("display", class_vars | class_essential, display_command, _("\
|
||||
Print value of expression EXP each time the program stops.\n\
|
||||
Usage: display[/FMT] EXP\n\
|
||||
/FMT may be used before EXP as in the \"print\" command.\n\
|
||||
@@ -3345,7 +3345,8 @@ but no count or size letter (see \"x\" command)."),
|
||||
print_opts);
|
||||
|
||||
cmd_list_element *print_cmd
|
||||
= add_com ("print", class_vars, print_command, print_help.c_str ());
|
||||
= add_com ("print", class_vars | class_essential, print_command,
|
||||
print_help.c_str ());
|
||||
set_cmd_completer_handle_brkchars (print_cmd, print_command_completer);
|
||||
add_com_alias ("p", print_cmd, class_vars, 1);
|
||||
add_com_alias ("inspect", print_cmd, class_vars, 1);
|
||||
|
||||
@@ -460,7 +460,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw)
|
||||
&& cmdtype != class_info && cmdtype != class_breakpoint
|
||||
&& cmdtype != class_trace && cmdtype != class_obscure
|
||||
&& cmdtype != class_maintenance && cmdtype != class_user
|
||||
&& cmdtype != class_tui)
|
||||
&& cmdtype != class_tui && cmdtype != class_essential)
|
||||
{
|
||||
PyErr_Format (PyExc_RuntimeError, _("Invalid command class argument."));
|
||||
return -1;
|
||||
@@ -621,6 +621,8 @@ gdbpy_initialize_commands ()
|
||||
|| PyModule_AddIntConstant (gdb_module, "COMMAND_MAINTENANCE",
|
||||
class_maintenance) < 0
|
||||
|| PyModule_AddIntConstant (gdb_module, "COMMAND_USER", class_user) < 0
|
||||
|| PyModule_AddIntConstant (gdb_module, "COMMAND_ESSENTIAL",
|
||||
class_essential) < 0
|
||||
|| PyModule_AddIntConstant (gdb_module, "COMMAND_TUI", class_tui) < 0)
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -3270,7 +3270,7 @@ Control remains in the debugger, but when you continue\n\
|
||||
execution will resume in the frame above the one now selected.\n\
|
||||
If an argument is given, it is an expression for the value to return."));
|
||||
|
||||
add_com ("up", class_stack, up_command, _("\
|
||||
add_com ("up", class_stack | class_essential, up_command, _("\
|
||||
Select and print stack frame that called this one.\n\
|
||||
An argument says how many frames up to go."));
|
||||
add_com ("up-silently", class_support, up_silently_command, _("\
|
||||
@@ -3278,7 +3278,7 @@ Same as the `up' command, but does not print anything.\n\
|
||||
This is useful in command scripts."));
|
||||
|
||||
cmd_list_element *down_cmd
|
||||
= add_com ("down", class_stack, down_command, _("\
|
||||
= add_com ("down", class_stack | class_essential, down_command, _("\
|
||||
Select and print stack frame called by this one.\n\
|
||||
An argument says how many frames down to go."));
|
||||
add_com_alias ("do", down_cmd, class_stack, 1);
|
||||
@@ -3449,7 +3449,7 @@ With a negative COUNT, print outermost -COUNT frames."),
|
||||
backtrace_opts);
|
||||
|
||||
cmd_list_element *backtrace_cmd
|
||||
= add_com ("backtrace", class_stack, backtrace_command,
|
||||
= add_com ("backtrace", class_stack | class_essential, backtrace_command,
|
||||
backtrace_help.c_str ());
|
||||
set_cmd_completer_handle_brkchars (backtrace_cmd, backtrace_command_completer);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ gdb_test_sequence "help" "unpaged help" {
|
||||
"aliases -- User-defined aliases of other commands"
|
||||
"breakpoints -- Making program stop at certain points"
|
||||
"data -- Examining data"
|
||||
"essential -- GDB essential commands"
|
||||
"files -- Specifying and examining files"
|
||||
"internals -- Maintenance commands"
|
||||
"obscure -- Obscure features"
|
||||
@@ -53,10 +54,10 @@ gdb_expect_list "paged help" \
|
||||
"aliases -- User-defined aliases of other commands"
|
||||
"breakpoints -- Making program stop at certain points"
|
||||
"data -- Examining data"
|
||||
"essential -- GDB essential commands"
|
||||
"files -- Specifying and examining files"
|
||||
"internals -- Maintenance commands"
|
||||
"obscure -- Obscure features"
|
||||
"running -- Running the program"
|
||||
}
|
||||
gdb_test "q"
|
||||
|
||||
|
||||
@@ -738,7 +738,7 @@ INIT_GDB_FILE (typeprint)
|
||||
{
|
||||
struct cmd_list_element *c;
|
||||
|
||||
c = add_com ("ptype", class_vars, ptype_command, _("\
|
||||
c = add_com ("ptype", class_vars | class_essential, ptype_command, _("\
|
||||
Print definition of type TYPE.\n\
|
||||
Usage: ptype[/FLAGS] TYPE | EXPRESSION\n\
|
||||
Argument may be any type (for example a type name defined by typedef,\n\
|
||||
|
||||
@@ -217,6 +217,29 @@ command_structure_invariants_tests ()
|
||||
|
||||
}
|
||||
|
||||
namespace essential_command_tests {
|
||||
|
||||
/* The maximum number of commands that can be considered
|
||||
essential by GDB. This value was chosen arbitrarily,
|
||||
but it must be kept low, so as to not overwhelm new
|
||||
users. */
|
||||
static constexpr int max_essential_cmds = 20;
|
||||
|
||||
static void
|
||||
essential_command_count_tests ()
|
||||
{
|
||||
int nr_essential_cmds = 0;
|
||||
|
||||
for (struct cmd_list_element *c = cmdlist; c != nullptr; c = c->next)
|
||||
{
|
||||
if (c->is_essential ())
|
||||
nr_essential_cmds ++;
|
||||
}
|
||||
|
||||
SELF_CHECK (nr_essential_cmds <= max_essential_cmds);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace selftests */
|
||||
|
||||
INIT_GDB_FILE (command_def_selftests)
|
||||
@@ -228,4 +251,8 @@ INIT_GDB_FILE (command_def_selftests)
|
||||
selftests::register_test
|
||||
("command_structure_invariants",
|
||||
selftests::command_structure_tests::command_structure_invariants_tests);
|
||||
|
||||
selftests::register_test
|
||||
("essential_command_count",
|
||||
selftests::essential_command_tests::essential_command_count_tests);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user