Files
binutils-gdb/gdb/break-catch-sig.c
Pedro Alves 205bb562e7 Introduce "info breakpoints -hide-locations"
This commit adds a new option to "info breakpoints",
"-hide-locations".  It's purpose is to tell GDB to skip printing
breakpoint locations, printing only the breakpoint header rows.

And then, since only code breakpoint locations print anything in the
"Address" column, "-hide-breakpoints" also disables the "Address"
column.

For example, when debugging GDB, you can use the new options to get
this:

 (top-gdb) i b -h
 Num     Type           Disp Enb What
 1       breakpoint     keep y   internal_error
 2       breakpoint     keep y   info_command
	 silent
	 return
 3       breakpoint     keep y   main
	 breakpoint already hit 1 time
 4       breakpoint     keep y   error
 (top-gdb)

instead of:

 (top-gdb) i b
 Num     Type           Disp Enb Address            What
 1       breakpoint     keep y                      internal_error
  1.1                        y   0x0000555555f81d12 in internal_error(char const*, int, char const*, ...) at /home/pedro/gdb/binutils-gdb/src/gdbsupport/errors.cc:51
 2       breakpoint     keep y                      info_command
	 silent
	 return
  2.1                        y   0x00005555557b3097 in info_command(char const*, int) at /home/pedro/gdb/binutils-gdb/src/gdb/cli/cli-cmds.c:217
 3       breakpoint     keep y                      main
	 breakpoint already hit 1 time
  3.1                        y   0x000055555564106c in main(int, char**) at /home/pedro/gdb/binutils-gdb/src/gdb/gdb.c:25
  3.2                        y   0x0000555555dba524 in selftests::string_view::capacity_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/capacity/1.cc:167
  3.3                        y   0x0000555555dba943 in selftests::string_view::cons_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/cons/char/1.cc:62
  3.4                        y   0x0000555555dbaa34 in selftests::string_view::cons_2::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/cons/char/2.cc:41
  3.5                        y   0x0000555555dbaa9a in selftests::string_view::cons_3::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/cons/char/3.cc:34
  3.6                        y   0x0000555555dbac6b in selftests::string_view::element_access_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/element_access/char/1.cc:66
  3.7                        y   0x0000555555dbac83 in selftests::string_view::element_access_empty::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/element_access/char/empty.cc:25
  3.8                        y   0x0000555555dbae91 in selftests::string_view::element_access_front_back::main()
						    at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/element_access/char/front_back.cc:38
  3.9                        y   0x0000555555dbb2bd in selftests::string_view::inserters_2::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/inserters/char/2.cc:84
  3.10                       y   0x0000555555dbb429 in selftests::string_view::modifiers_remove_prefix::main()
						    at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/modifiers/remove_prefix/char/1.cc:58
  3.11                       y   0x0000555555dbb575 in selftests::string_view::modifiers_remove_suffix::main()
						    at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/modifiers/remove_suffix/char/1.cc:58
  3.12                       y   0x0000555555dbbd38 in selftests::string_view::operations_compare_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/compare/char/1.cc:127
  3.13                       y   0x0000555555dbbe7b in selftests::string_view::operations_compare_13650::main()
						    at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/compare/char/13650.cc:45
  3.14                       y   0x0000555555dbbf6a in selftests::string_view::operations_copy_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/copy/char/1.cc:41
  3.15                       y   0x0000555555dbc03b in selftests::string_view::operations_data_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/data/char/1.cc:39
  3.16                       y   0x0000555555dbc5fe in selftests::string_view::operations_find_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/find/char/1.cc:160
  3.17                       y   0x0000555555dbcb60 in selftests::string_view::operations_find_2::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/find/char/2.cc:158
  3.18                       y   0x0000555555dbd1c1 in selftests::string_view::operations_find_3::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/find/char/3.cc:158
  3.19                       y   0x0000555555dbd26c in selftests::string_view::operations_find_4::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/find/char/4.cc:40
  3.20                       y   0x0000555555dbd83f in selftests::string_view::operations_rfind_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/rfind/char/1.cc:90
  3.21                       y   0x0000555555dbda98 in selftests::string_view::operations_rfind_2::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/rfind/char/2.cc:48
  3.22                       y   0x0000555555dbde4c in selftests::string_view::operations_rfind_3::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/rfind/char/3.cc:63
  3.23                       y   0x0000555555dbe189 in selftests::string_view::operations_substr_1::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operations/substr/char/1.cc:74
  3.24                       y   0x0000555555dbffdb in selftests::string_view::operators_2::main() at /home/pedro/gdb/binutils-gdb/src/gdb/unittests/basic_string_view/operators/char/2.cc:366
 4       breakpoint     keep y                      error
  4.1                        y   0x00005555557f5142 in gcc_c_plugin::error(char const*) const at /home/pedro/gdb/binutils-gdb/src/gdb/../include/gcc-c-fe.def:198
  4.2                        y   0x00005555557fe1f4 in gcc_cp_plugin::error(char const*) const at /home/pedro/gdb/binutils-gdb/src/gdb/../include/gcc-cp-fe.def:983
  4.3                        y   0x0000555555f81c5e in error(char const*, ...) at /home/pedro/gdb/binutils-gdb/src/gdbsupport/errors.cc:39
  4.4                        y   0x00007ffff65ee4e0 <icu_66::RBBIRuleScanner::error(UErrorCode)>
  4.5                        y   0x00007ffff685e070 <icu_66::RegexCompile::error(UErrorCode)>
  4.6                        y   0x00007ffff6cd4e86 in error at /usr/include/x86_64-linux-gnu/bits/error.h:40
  4.7                        y   0x00007ffff71c2190 in __error at error.c:274

Documentation change included.  No testsuite changes yet until there's
agreement on the previous patch.

Change-Id: Ic42ad8565e79ca67bfebb22cbb4794ea816fd08b
2022-05-23 20:31:44 +01:00

426 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Everything about signal catchpoints, for GDB.
Copyright (C) 2011-2022 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "arch-utils.h"
#include <ctype.h>
#include "breakpoint.h"
#include "gdbcmd.h"
#include "inferior.h"
#include "infrun.h"
#include "annotate.h"
#include "valprint.h"
#include "cli/cli-utils.h"
#include "completer.h"
#include "cli/cli-style.h"
#include "cli/cli-decode.h"
#include <string>
#define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT)
/* An instance of this type is used to represent a signal
catchpoint. */
struct signal_catchpoint : public catchpoint
{
signal_catchpoint (struct gdbarch *gdbarch, bool temp,
std::vector<gdb_signal> &&sigs,
bool catch_all_)
: catchpoint (gdbarch, temp, nullptr),
signals_to_be_caught (std::move (sigs)),
catch_all (catch_all_)
{
}
int insert_location (struct bp_location *) override;
int remove_location (struct bp_location *,
enum remove_bp_reason reason) override;
int breakpoint_hit (const struct bp_location *bl,
const address_space *aspace,
CORE_ADDR bp_addr,
const target_waitstatus &ws) override;
enum print_stop_action print_it (const bpstat *bs) const override;
bool print_one (bp_location **, bool) const override;
void print_mention () const override;
void print_recreate (struct ui_file *fp) const override;
bool explains_signal (enum gdb_signal) override;
/* Signal numbers used for the 'catch signal' feature. If no signal
has been specified for filtering, it is empty. Otherwise,
it holds a list of all signals to be caught. */
std::vector<gdb_signal> signals_to_be_caught;
/* If SIGNALS_TO_BE_CAUGHT is empty, then all "ordinary" signals are
caught. If CATCH_ALL is true, then internal signals are caught
as well. If SIGNALS_TO_BE_CAUGHT is not empty, then this field
is ignored. */
bool catch_all;
};
/* Count of each signal. */
static unsigned int signal_catch_counts[GDB_SIGNAL_LAST];
/* A convenience wrapper for gdb_signal_to_name that returns the
integer value if the name is not known. */
static const char *
signal_to_name_or_int (enum gdb_signal sig)
{
const char *result = gdb_signal_to_name (sig);
if (strcmp (result, "?") == 0)
result = plongest (sig);
return result;
}
/* Implement the "insert_location" method for signal catchpoints. */
int
signal_catchpoint::insert_location (struct bp_location *bl)
{
struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner;
if (!c->signals_to_be_caught.empty ())
{
for (gdb_signal iter : c->signals_to_be_caught)
++signal_catch_counts[iter];
}
else
{
for (int i = 0; i < GDB_SIGNAL_LAST; ++i)
{
if (c->catch_all || !INTERNAL_SIGNAL (i))
++signal_catch_counts[i];
}
}
signal_catch_update (signal_catch_counts);
return 0;
}
/* Implement the "remove_location" method for signal catchpoints. */
int
signal_catchpoint::remove_location (struct bp_location *bl,
enum remove_bp_reason reason)
{
struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner;
if (!c->signals_to_be_caught.empty ())
{
for (gdb_signal iter : c->signals_to_be_caught)
{
gdb_assert (signal_catch_counts[iter] > 0);
--signal_catch_counts[iter];
}
}
else
{
for (int i = 0; i < GDB_SIGNAL_LAST; ++i)
{
if (c->catch_all || !INTERNAL_SIGNAL (i))
{
gdb_assert (signal_catch_counts[i] > 0);
--signal_catch_counts[i];
}
}
}
signal_catch_update (signal_catch_counts);
return 0;
}
/* Implement the "breakpoint_hit" method for signal catchpoints. */
int
signal_catchpoint::breakpoint_hit (const struct bp_location *bl,
const address_space *aspace,
CORE_ADDR bp_addr,
const target_waitstatus &ws)
{
const struct signal_catchpoint *c
= (const struct signal_catchpoint *) bl->owner;
gdb_signal signal_number;
if (ws.kind () != TARGET_WAITKIND_STOPPED)
return 0;
signal_number = ws.sig ();
/* If we are catching specific signals in this breakpoint, then we
must guarantee that the called signal is the same signal we are
catching. */
if (!c->signals_to_be_caught.empty ())
{
for (gdb_signal iter : c->signals_to_be_caught)
if (signal_number == iter)
return 1;
/* Not the same. */
return 0;
}
else
return c->catch_all || !INTERNAL_SIGNAL (signal_number);
}
/* Implement the "print_it" method for signal catchpoints. */
enum print_stop_action
signal_catchpoint::print_it (const bpstat *bs) const
{
struct target_waitstatus last;
const char *signal_name;
struct ui_out *uiout = current_uiout;
get_last_target_status (nullptr, nullptr, &last);
signal_name = signal_to_name_or_int (last.sig ());
annotate_catchpoint (number);
maybe_print_thread_hit_breakpoint (uiout);
gdb_printf (_("Catchpoint %d (signal %s), "), number, signal_name);
return PRINT_SRC_AND_LOC;
}
/* Implement the "print_one" method for signal catchpoints. */
bool
signal_catchpoint::print_one (bp_location **last_loc,
bool print_address_col) const
{
struct ui_out *uiout = current_uiout;
/* Field 4, the address, is omitted (which makes the columns
not line up too nicely with the headers, but the effect
is relatively readable). */
if (print_address_col)
uiout->field_skip ("addr");
annotate_field (5);
if (signals_to_be_caught.size () > 1)
uiout->text ("signals \"");
else
uiout->text ("signal \"");
if (!signals_to_be_caught.empty ())
{
std::string text;
bool first = true;
for (gdb_signal iter : signals_to_be_caught)
{
const char *name = signal_to_name_or_int (iter);
if (!first)
text += " ";
first = false;
text += name;
}
uiout->field_string ("what", text);
}
else
uiout->field_string ("what",
catch_all ? "<any signal>" : "<standard signals>",
metadata_style.style ());
uiout->text ("\" ");
if (uiout->is_mi_like_p ())
uiout->field_string ("catch-type", "signal");
return true;
}
/* Implement the "print_mention" method for signal catchpoints. */
void
signal_catchpoint::print_mention () const
{
if (!signals_to_be_caught.empty ())
{
if (signals_to_be_caught.size () > 1)
gdb_printf (_("Catchpoint %d (signals"), number);
else
gdb_printf (_("Catchpoint %d (signal"), number);
for (gdb_signal iter : signals_to_be_caught)
{
const char *name = signal_to_name_or_int (iter);
gdb_printf (" %s", name);
}
gdb_printf (")");
}
else if (catch_all)
gdb_printf (_("Catchpoint %d (any signal)"), number);
else
gdb_printf (_("Catchpoint %d (standard signals)"), number);
}
/* Implement the "print_recreate" method for signal catchpoints. */
void
signal_catchpoint::print_recreate (struct ui_file *fp) const
{
gdb_printf (fp, "catch signal");
if (!signals_to_be_caught.empty ())
{
for (gdb_signal iter : signals_to_be_caught)
gdb_printf (fp, " %s", signal_to_name_or_int (iter));
}
else if (catch_all)
gdb_printf (fp, " all");
gdb_putc ('\n', fp);
}
/* Implement the "explains_signal" method for signal catchpoints. */
bool
signal_catchpoint::explains_signal (enum gdb_signal sig)
{
return true;
}
/* Create a new signal catchpoint. TEMPFLAG is true if this should be
a temporary catchpoint. FILTER is the list of signals to catch; it
can be empty, meaning all signals. CATCH_ALL is a flag indicating
whether signals used internally by gdb should be caught; it is only
valid if FILTER is NULL. If FILTER is empty and CATCH_ALL is zero,
then internal signals like SIGTRAP are not caught. */
static void
create_signal_catchpoint (int tempflag, std::vector<gdb_signal> &&filter,
bool catch_all)
{
struct gdbarch *gdbarch = get_current_arch ();
std::unique_ptr<signal_catchpoint> c
(new signal_catchpoint (gdbarch, tempflag, std::move (filter), catch_all));
install_breakpoint (0, std::move (c), 1);
}
/* Splits the argument using space as delimiter. Returns a filter
list, which is empty if no filtering is required. */
static std::vector<gdb_signal>
catch_signal_split_args (const char *arg, bool *catch_all)
{
std::vector<gdb_signal> result;
bool first = true;
while (*arg != '\0')
{
int num;
gdb_signal signal_number;
char *endptr;
std::string one_arg = extract_arg (&arg);
if (one_arg.empty ())
break;
/* Check for the special flag "all". */
if (one_arg == "all")
{
arg = skip_spaces (arg);
if (*arg != '\0' || !first)
error (_("'all' cannot be caught with other signals"));
*catch_all = true;
gdb_assert (result.empty ());
return result;
}
first = false;
/* Check if the user provided a signal name or a number. */
num = (int) strtol (one_arg.c_str (), &endptr, 0);
if (*endptr == '\0')
signal_number = gdb_signal_from_command (num);
else
{
signal_number = gdb_signal_from_name (one_arg.c_str ());
if (signal_number == GDB_SIGNAL_UNKNOWN)
error (_("Unknown signal name '%s'."), one_arg.c_str ());
}
result.push_back (signal_number);
}
result.shrink_to_fit ();
return result;
}
/* Implement the "catch signal" command. */
static void
catch_signal_command (const char *arg, int from_tty,
struct cmd_list_element *command)
{
int tempflag;
bool catch_all = false;
std::vector<gdb_signal> filter;
tempflag = command->context () == CATCH_TEMPORARY;
arg = skip_spaces (arg);
/* The allowed syntax is:
catch signal
catch signal <name | number> [<name | number> ... <name | number>]
Let's check if there's a signal name. */
if (arg != NULL)
filter = catch_signal_split_args (arg, &catch_all);
create_signal_catchpoint (tempflag, std::move (filter), catch_all);
}
void _initialize_break_catch_sig ();
void
_initialize_break_catch_sig ()
{
add_catch_command ("signal", _("\
Catch signals by their names and/or numbers.\n\
Usage: catch signal [[NAME|NUMBER] [NAME|NUMBER]...|all]\n\
Arguments say which signals to catch. If no arguments\n\
are given, every \"normal\" signal will be caught.\n\
The argument \"all\" means to also catch signals used by GDB.\n\
Arguments, if given, should be one or more signal names\n\
(if your system supports that), or signal numbers."),
catch_signal_command,
signal_completer,
CATCH_PERMANENT,
CATCH_TEMPORARY);
}