diff --git a/gdb/NEWS b/gdb/NEWS index 1073e38dfc6..94d1fd8ea8d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -38,6 +38,16 @@ set remote thread-options-packet show remote thread-options-packet Set/show the use of the thread options packet. +* New features in the GDB remote stub, GDBserver + + ** The --remote-debug and --event-loop-debug command line options + have been removed. + + ** The --debug command line option now takes an optional comma + separated list of components to emit debug for. The currently + supported components are: all, threads, event-loop, and remote. + If no components are given then threads is assumed. + * Python API ** New function gdb.notify_mi(NAME, DATA), that emits custom diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index d2428efdb63..6d20e4ca06d 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -23674,11 +23674,42 @@ program. For more information, @pxref{--multi Option in Types of Remote Connnections}. @cindex @option{--debug}, @code{gdbserver} option -The @option{--debug} option tells @code{gdbserver} to display extra -status information about the debugging process. -@cindex @option{--remote-debug}, @code{gdbserver} option -The @option{--remote-debug} option tells @code{gdbserver} to display -remote protocol debug output. +The @option{--debug[=option1,option2,@dots{}]} option tells +@code{gdbserver} to display extra diagnostic information about the +debugging process. The options (@var{option1}, @var{option2}, etc) +control for which areas of @code{gdbserver} additional information +will be displayed, possible values are: + +@table @code +@item all +This enables all available diagnostic output. +@item threads +This enables diagnostic output related to threading. Currently other +general diagnostic output is included in this category, but this could +change in future releases of @code{gdbserver}. +@item event-loop +This enables event-loop specific diagnostic output. +@item remote +This enables diagnostic output related to the transfer of remote +protocol packets too and from the debugger. +@end table + +@noindent +If no options are passed to @option{--debug} then this is treated as +equivalent to @option{--debug=threads}. This could change in future +releases of @code{gdbserver}. The options passed to @option{--debug} +are processed left to right, and individual options can be prefixed +with the @kbd{-} (minus) character to disable diagnostic output from +this area, so it is possible to use: + +@smallexample + target> gdbserver --debug=all,-event-loop +@end smallexample + +@noindent +In order to enable all diagnostic output except that for the +event-loop. + @cindex @option{--debug-file}, @code{gdbserver} option @cindex @code{gdbserver}, send all debug output to a single file The @option{--debug-file=@var{filename}} option tells @code{gdbserver} to @@ -50671,16 +50702,27 @@ the program you want to debug. The syntax is: target> gdbserver --multi @var{comm} @end smallexample -@item --debug -Instruct @code{gdbserver} to display extra status information about the debugging -process. -This option is intended for @code{gdbserver} development and for bug reports to -the developers. +@item --debug@r{[}=option1,option2,@dots{}@r{]} +Instruct @code{gdbserver} to display extra status information about +the debugging process. This option is intended for @code{gdbserver} +development and for bug reports to the developers. -@item --remote-debug -Instruct @code{gdbserver} to display remote protocol debug output. -This option is intended for @code{gdbserver} development and for bug reports to -the developers. +Each @var{option} is the name of a component for which debugging +should be enabled. The list of possible options is @option{all}, +@option{threads}, @option{event-loop}, @option{remote}. The special +option @option{all} enables all components. The option list is +processed left to right, and an option can be prefixed with the +@kbd{-} character to disable output for that component, so you could write: + +@smallexample +target> gdbserver --debug=all,-event-loop +@end smallexample + +@noindent +to turn on debug output for all components except @option{event-loop}. +If no options are passed to @option{--debug} then this is treated as +equivalent to @option{--debug=threads}. This could change in future +releases of @code{gdbserver}. @item --debug-file=@var{filename} Instruct @code{gdbserver} to send any debug output to the given @var{filename}. diff --git a/gdbserver/server.cc b/gdbserver/server.cc index d73d637e0fe..ea5d28c4c25 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -1457,6 +1457,124 @@ parse_debug_format_options (const char *arg, int is_monitor) return std::string (); } +/* A wrapper to enable, or disable a debug flag. These are debug flags + that control the debug output from gdbserver, that developers might + want, this is not something most end users will need. */ + +struct debug_opt +{ + /* NAME is the name of this debug option, this should be a simple string + containing no whitespace, starting with a letter from isalpha(), and + contain only isalnum() characters and '_' underscore and '-' hyphen. + + SETTER is a callback function used to set the debug variable. This + callback will be passed true to enable the debug setting, or false to + disable the debug setting. */ + debug_opt (const char *name, std::function setter) + : m_name (name), + m_setter (setter) + { + gdb_assert (isalpha (*name)); + } + + /* Called to enable or disable the debug setting. */ + void set (bool enable) const + { + m_setter (enable); + } + + /* Return the name of this debug option. */ + const char *name () const + { return m_name; } + +private: + /* The name of this debug option. */ + const char *m_name; + + /* The callback to update the debug setting. */ + std::function m_setter; +}; + +/* The set of all debug options that gdbserver supports. These are the + options that can be passed to the command line '--debug=...' flag, or to + the monitor command 'monitor set debug ...'. */ + +static std::vector all_debug_opt { + {"threads", [] (bool enable) + { + debug_threads = enable; + }}, + {"remote", [] (bool enable) + { + remote_debug = enable; + }}, + {"event-loop", [] (bool enable) + { + debug_event_loop = (enable ? debug_event_loop_kind::ALL + : debug_event_loop_kind::OFF); + }} +}; + +/* Parse the options to --debug=... + + OPTIONS is the string of debug components which should be enabled (or + disabled), and must not be nullptr. An empty OPTIONS string is valid, + in which case a default set of debug components will be enabled. + + An unknown, or otherwise invalid debug component will result in an + exception being thrown. + + OPTIONS can consist of multiple debug component names separated by a + comma. Debugging for each component will be turned on. The special + component 'all' can be used to enable debugging for all components. + + A component can also be prefixed with '-' to disable debugging of that + component, so a user might use: '--debug=all,-remote', to enable all + debugging, except for the remote (protocol) component. Components are + processed left to write in the OPTIONS list. */ + +static void +parse_debug_options (const char *options) +{ + gdb_assert (options != nullptr); + + /* Empty options means the "default" set. This exists mostly for + backwards compatibility with gdbserver's legacy behaviour. */ + if (*options == '\0') + options = "+threads"; + + while (*options != '\0') + { + const char *end = strchrnul (options, ','); + + bool enable = *options != '-'; + if (*options == '-' || *options == '+') + ++options; + + std::string opt (options, end - options); + + if (opt.size () == 0) + error ("invalid empty debug option"); + + bool is_opt_all = opt == "all"; + + bool found = false; + for (const auto &debug_opt : all_debug_opt) + if (is_opt_all || opt == debug_opt.name ()) + { + debug_opt.set (enable); + found = true; + if (!is_opt_all) + break; + } + + if (!found) + error ("unknown debug option '%s'", opt.c_str ()); + + options = (*end == ',') ? end + 1 : end; + } +} + /* Handle monitor commands not handled by target-specific handlers. */ static void @@ -3583,15 +3701,19 @@ gdbserver_usage (FILE *stream) "\n" "Debug options:\n" "\n" - " --debug Enable general debugging output.\n" + " --debug[=OPT1,OPT2,...]\n" + " Enable debugging output.\n" + " Options:\n" + " all, threads, event-loop, remote\n" + " With no options, 'threads' is assumed.\n" + " Prefix an option with '-' to disable\n" + " debugging of that component.\n" " --debug-format=OPT1[,OPT2,...]\n" " Specify extra content in debugging output.\n" " Options:\n" " all\n" " none\n" " timestamp\n" - " --remote-debug Enable remote protocol debugging output.\n" - " --event-loop-debug Enable event loop debugging output.\n" " --disable-packet=OPT1[,OPT2,...]\n" " Disable support for RSP packets or features.\n" " Options:\n" @@ -3870,8 +3992,32 @@ captured_main (int argc, char *argv[]) /* Consume the "--". */ *next_arg = NULL; } + else if (startswith (*next_arg, "--debug=")) + { + try + { + parse_debug_options ((*next_arg) + sizeof ("--debug=") - 1); + } + catch (const gdb_exception_error &exception) + { + fflush (stdout); + fprintf (stderr, "gdbserver: %s\n", exception.what ()); + exit (1); + } + } else if (strcmp (*next_arg, "--debug") == 0) - debug_threads = true; + { + try + { + parse_debug_options (""); + } + catch (const gdb_exception_error &exception) + { + fflush (stdout); + fprintf (stderr, "gdbserver: %s\n", exception.what ()); + exit (1); + } + } else if (startswith (*next_arg, "--debug-format=")) { std::string error_msg @@ -3884,10 +4030,6 @@ captured_main (int argc, char *argv[]) exit (1); } } - else if (strcmp (*next_arg, "--remote-debug") == 0) - remote_debug = true; - else if (strcmp (*next_arg, "--event-loop-debug") == 0) - debug_event_loop = debug_event_loop_kind::ALL; else if (startswith (*next_arg, "--debug-file=")) debug_set_output ((*next_arg) + sizeof ("--debug-file=") -1); else if (strcmp (*next_arg, "--disable-packet") == 0)