mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-27 22:10:32 +00:00
2013-01-03 Pedro Alves <palves@redhat.com>
Tom Tromey <tromey@redhat.com> PR cli/7221: * NEWS: Add "catch signal". * breakpoint.c (base_breakpoint_ops): No longer static. (bpstat_explains_signal): New function. (init_catchpoint): No longer static. (base_breakpoint_explains_signal): New function. (base_breakpoint_ops): Initialize new field. * breakpoint.h (enum bpstat_signal_value): New. (struct breakpoint_ops) <explains_signal>: New field. (bpstat_explains_signal): Remove macro, declare as function. (base_breakpoint_ops, init_catchpoint): Declare. * break-catch-sig.c: New file. * inferior.h (signal_catch_update): Declare. * infrun.c (signal_catch): New global. (handle_syscall_event): Update for change to bpstat_explains_signal. (handle_inferior_event): Likewise. Always handle random signals via bpstats. (signal_cache_update): Check signal_catch. (signal_catch_update): New function. (_initialize_infrun): Initialize signal_catch. * Makefile.in (SFILES): Add break-catch-sig.c. (COMMON_OBS): Add break-catch-sig.o. gdb/doc * gdb.texinfo (Set Catchpoints): Document "catch signal". (Signals): Likewise. gdb/testsuite * gdb.base/catch-signal.c: New file. * gdb.base/catch-signal.exp: New file.
This commit is contained in:
parent
8ac3646fbb
commit
ab04a2af2b
@ -1,3 +1,30 @@
|
||||
2013-01-16 Pedro Alves <palves@redhat.com>
|
||||
Tom Tromey <tromey@redhat.com>
|
||||
|
||||
PR cli/7221:
|
||||
* NEWS: Add "catch signal".
|
||||
* breakpoint.c (base_breakpoint_ops): No longer static.
|
||||
(bpstat_explains_signal): New function.
|
||||
(init_catchpoint): No longer static.
|
||||
(base_breakpoint_explains_signal): New function.
|
||||
(base_breakpoint_ops): Initialize new field.
|
||||
* breakpoint.h (enum bpstat_signal_value): New.
|
||||
(struct breakpoint_ops) <explains_signal>: New field.
|
||||
(bpstat_explains_signal): Remove macro, declare as function.
|
||||
(base_breakpoint_ops, init_catchpoint): Declare.
|
||||
* break-catch-sig.c: New file.
|
||||
* inferior.h (signal_catch_update): Declare.
|
||||
* infrun.c (signal_catch): New global.
|
||||
(handle_syscall_event): Update for change to
|
||||
bpstat_explains_signal.
|
||||
(handle_inferior_event): Likewise. Always handle random signals
|
||||
via bpstats.
|
||||
(signal_cache_update): Check signal_catch.
|
||||
(signal_catch_update): New function.
|
||||
(_initialize_infrun): Initialize signal_catch.
|
||||
* Makefile.in (SFILES): Add break-catch-sig.c.
|
||||
(COMMON_OBS): Add break-catch-sig.o.
|
||||
|
||||
2013-01-16 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* breakpoint.c (print_one_catch_fork, print_one_catch_vfork)
|
||||
|
@ -699,7 +699,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
|
||||
agent.c \
|
||||
bcache.c \
|
||||
bfd-target.c \
|
||||
block.c blockframe.c breakpoint.c buildsym.c \
|
||||
block.c blockframe.c breakpoint.c break-catch-sig.c buildsym.c \
|
||||
c-exp.y c-lang.c c-typeprint.c c-valprint.c \
|
||||
charset.c cleanups.c cli-out.c coffread.c coff-pe-read.c \
|
||||
complaints.c completer.c continuations.c corefile.c corelow.c \
|
||||
@ -866,7 +866,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||
auto-load.o auxv.o \
|
||||
agent.o \
|
||||
bfd-target.o \
|
||||
blockframe.o breakpoint.o findvar.o regcache.o cleanups.o \
|
||||
blockframe.o breakpoint.o break-catch-sig.o \
|
||||
findvar.o regcache.o cleanups.o \
|
||||
charset.o continuations.o corelow.o disasm.o dummy-frame.o dfp.o \
|
||||
source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
|
||||
block.o symtab.o psymtab.o symfile.o symmisc.o linespec.o dictionary.o \
|
||||
|
4
gdb/NEWS
4
gdb/NEWS
@ -65,6 +65,10 @@ Lynx 178 PowerPC powerpc-*-lynx*178
|
||||
|
||||
* New commands (for set/show, see "New options" below)
|
||||
|
||||
catch signal
|
||||
Catch signals. This is similar to "handle", but allows commands and
|
||||
conditions to be attached.
|
||||
|
||||
maint info bfds
|
||||
List the BFDs known to GDB.
|
||||
|
||||
|
508
gdb/break-catch-sig.c
Normal file
508
gdb/break-catch-sig.c
Normal file
@ -0,0 +1,508 @@
|
||||
/* Everything about signal catchpoints, for GDB.
|
||||
|
||||
Copyright (C) 2011, 2012 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 "annotate.h"
|
||||
#include "valprint.h"
|
||||
#include "cli/cli-utils.h"
|
||||
#include "completer.h"
|
||||
#include "gdb_obstack.h"
|
||||
|
||||
#define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT)
|
||||
|
||||
typedef enum gdb_signal gdb_signal_type;
|
||||
|
||||
DEF_VEC_I (gdb_signal_type);
|
||||
|
||||
/* An instance of this type is used to represent a signal catchpoint.
|
||||
It includes a "struct breakpoint" as a kind of base class; users
|
||||
downcast to "struct breakpoint *" when needed. A breakpoint is
|
||||
really of this type iff its ops pointer points to
|
||||
SIGNAL_CATCHPOINT_OPS. */
|
||||
|
||||
struct signal_catchpoint
|
||||
{
|
||||
/* The base class. */
|
||||
|
||||
struct breakpoint base;
|
||||
|
||||
/* Signal numbers used for the 'catch signal' feature. If no signal
|
||||
has been specified for filtering, its value is NULL. Otherwise,
|
||||
it holds a list of all signals to be caught. */
|
||||
|
||||
VEC (gdb_signal_type) *signals_to_be_caught;
|
||||
|
||||
/* If SIGNALS_TO_BE_CAUGHT is NULL, then all "ordinary" signals are
|
||||
caught. If CATCH_ALL is non-zero, then internal signals are
|
||||
caught as well. If SIGNALS_TO_BE_CAUGHT is non-NULL, then this
|
||||
field is ignored. */
|
||||
|
||||
int catch_all;
|
||||
};
|
||||
|
||||
/* The breakpoint_ops structure to be used in signal catchpoints. */
|
||||
|
||||
static struct breakpoint_ops signal_catchpoint_ops;
|
||||
|
||||
/* Count of each signal. */
|
||||
|
||||
static unsigned int *signal_catch_counts;
|
||||
|
||||
|
||||
|
||||
/* 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 "dtor" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static void
|
||||
signal_catchpoint_dtor (struct breakpoint *b)
|
||||
{
|
||||
struct signal_catchpoint *c = (struct signal_catchpoint *) b;
|
||||
|
||||
VEC_free (gdb_signal_type, c->signals_to_be_caught);
|
||||
|
||||
base_breakpoint_ops.dtor (b);
|
||||
}
|
||||
|
||||
/* Implement the "insert_location" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static int
|
||||
signal_catchpoint_insert_location (struct bp_location *bl)
|
||||
{
|
||||
struct signal_catchpoint *c = (void *) bl->owner;
|
||||
int i;
|
||||
|
||||
if (c->signals_to_be_caught != NULL)
|
||||
{
|
||||
gdb_signal_type iter;
|
||||
|
||||
for (i = 0;
|
||||
VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
|
||||
i++)
|
||||
++signal_catch_counts[iter];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (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" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static int
|
||||
signal_catchpoint_remove_location (struct bp_location *bl)
|
||||
{
|
||||
struct signal_catchpoint *c = (void *) bl->owner;
|
||||
int i;
|
||||
|
||||
if (c->signals_to_be_caught != NULL)
|
||||
{
|
||||
gdb_signal_type iter;
|
||||
|
||||
for (i = 0;
|
||||
VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
|
||||
i++)
|
||||
{
|
||||
gdb_assert (signal_catch_counts[iter] > 0);
|
||||
--signal_catch_counts[iter];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (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" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static int
|
||||
signal_catchpoint_breakpoint_hit (const struct bp_location *bl,
|
||||
struct address_space *aspace,
|
||||
CORE_ADDR bp_addr,
|
||||
const struct target_waitstatus *ws)
|
||||
{
|
||||
const struct signal_catchpoint *c = (void *) bl->owner;
|
||||
gdb_signal_type signal_number;
|
||||
|
||||
if (ws->kind != TARGET_WAITKIND_STOPPED)
|
||||
return 0;
|
||||
|
||||
signal_number = ws->value.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)
|
||||
{
|
||||
int i;
|
||||
gdb_signal_type iter;
|
||||
|
||||
for (i = 0;
|
||||
VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
|
||||
i++)
|
||||
if (signal_number == iter)
|
||||
break;
|
||||
/* Not the same. */
|
||||
if (!iter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return c->catch_all || !INTERNAL_SIGNAL (signal_number);
|
||||
}
|
||||
|
||||
/* Implement the "print_it" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static enum print_stop_action
|
||||
signal_catchpoint_print_it (bpstat bs)
|
||||
{
|
||||
struct breakpoint *b = bs->breakpoint_at;
|
||||
ptid_t ptid;
|
||||
struct target_waitstatus last;
|
||||
const char *signal_name;
|
||||
|
||||
get_last_target_status (&ptid, &last);
|
||||
|
||||
signal_name = signal_to_name_or_int (last.value.sig);
|
||||
|
||||
annotate_catchpoint (b->number);
|
||||
|
||||
printf_filtered (_("\nCatchpoint %d (signal %s), "), b->number, signal_name);
|
||||
|
||||
return PRINT_SRC_AND_LOC;
|
||||
}
|
||||
|
||||
/* Implement the "print_one" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static void
|
||||
signal_catchpoint_print_one (struct breakpoint *b,
|
||||
struct bp_location **last_loc)
|
||||
{
|
||||
struct signal_catchpoint *c = (void *) b;
|
||||
struct value_print_options opts;
|
||||
struct ui_out *uiout = current_uiout;
|
||||
|
||||
get_user_print_options (&opts);
|
||||
|
||||
/* 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 (opts.addressprint)
|
||||
ui_out_field_skip (uiout, "addr");
|
||||
annotate_field (5);
|
||||
|
||||
if (c->signals_to_be_caught
|
||||
&& VEC_length (gdb_signal_type, c->signals_to_be_caught) > 1)
|
||||
ui_out_text (uiout, "signals \"");
|
||||
else
|
||||
ui_out_text (uiout, "signal \"");
|
||||
|
||||
if (c->signals_to_be_caught)
|
||||
{
|
||||
int i;
|
||||
gdb_signal_type iter;
|
||||
struct obstack text;
|
||||
struct cleanup *cleanup;
|
||||
|
||||
obstack_init (&text);
|
||||
cleanup = make_cleanup_obstack_free (&text);
|
||||
|
||||
for (i = 0;
|
||||
VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
|
||||
i++)
|
||||
{
|
||||
const char *name = signal_to_name_or_int (iter);
|
||||
|
||||
if (i > 0)
|
||||
obstack_grow (&text, " ", 1);
|
||||
obstack_grow (&text, name, strlen (name));
|
||||
}
|
||||
obstack_grow (&text, "", 1);
|
||||
ui_out_field_string (uiout, "what", obstack_base (&text));
|
||||
do_cleanups (cleanup);
|
||||
}
|
||||
else
|
||||
ui_out_field_string (uiout, "what",
|
||||
c->catch_all ? "<any signal>" : "<standard signals>");
|
||||
ui_out_text (uiout, "\" ");
|
||||
|
||||
if (ui_out_is_mi_like_p (uiout))
|
||||
ui_out_field_string (uiout, "catch-type", "signal");
|
||||
}
|
||||
|
||||
/* Implement the "print_mention" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static void
|
||||
signal_catchpoint_print_mention (struct breakpoint *b)
|
||||
{
|
||||
struct signal_catchpoint *c = (void *) b;
|
||||
|
||||
if (c->signals_to_be_caught)
|
||||
{
|
||||
int i;
|
||||
gdb_signal_type iter;
|
||||
|
||||
if (VEC_length (gdb_signal_type, c->signals_to_be_caught) > 1)
|
||||
printf_filtered (_("Catchpoint %d (signals"), b->number);
|
||||
else
|
||||
printf_filtered (_("Catchpoint %d (signal"), b->number);
|
||||
|
||||
for (i = 0;
|
||||
VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
|
||||
i++)
|
||||
{
|
||||
const char *name = signal_to_name_or_int (iter);
|
||||
|
||||
printf_filtered (" %s", name);
|
||||
}
|
||||
printf_filtered (")");
|
||||
}
|
||||
else if (c->catch_all)
|
||||
printf_filtered (_("Catchpoint %d (any signal)"), b->number);
|
||||
else
|
||||
printf_filtered (_("Catchpoint %d (standard signals)"), b->number);
|
||||
}
|
||||
|
||||
/* Implement the "print_recreate" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static void
|
||||
signal_catchpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
|
||||
{
|
||||
struct signal_catchpoint *c = (void *) b;
|
||||
|
||||
fprintf_unfiltered (fp, "catch signal");
|
||||
|
||||
if (c->signals_to_be_caught)
|
||||
{
|
||||
int i;
|
||||
gdb_signal_type iter;
|
||||
|
||||
for (i = 0;
|
||||
VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
|
||||
i++)
|
||||
fprintf_unfiltered (fp, " %s", signal_to_name_or_int (iter));
|
||||
}
|
||||
else if (c->catch_all)
|
||||
fprintf_unfiltered (fp, " all");
|
||||
}
|
||||
|
||||
/* Implement the "explains_signal" breakpoint_ops method for signal
|
||||
catchpoints. */
|
||||
|
||||
static enum bpstat_signal_value
|
||||
signal_catchpoint_explains_signal (struct breakpoint *b)
|
||||
{
|
||||
return BPSTAT_SIGNAL_PASS;
|
||||
}
|
||||
|
||||
/* 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 NULL, 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 NULL and CATCH_ALL is zero,
|
||||
then internal signals like SIGTRAP are not caught. */
|
||||
|
||||
static void
|
||||
create_signal_catchpoint (int tempflag, VEC (gdb_signal_type) *filter,
|
||||
int catch_all)
|
||||
{
|
||||
struct signal_catchpoint *c;
|
||||
struct gdbarch *gdbarch = get_current_arch ();
|
||||
|
||||
c = XNEW (struct signal_catchpoint);
|
||||
init_catchpoint (&c->base, gdbarch, tempflag, NULL, &signal_catchpoint_ops);
|
||||
c->signals_to_be_caught = filter;
|
||||
c->catch_all = catch_all;
|
||||
|
||||
install_breakpoint (0, &c->base, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Splits the argument using space as delimiter. Returns an xmalloc'd
|
||||
filter list, or NULL if no filtering is required. */
|
||||
|
||||
static VEC (gdb_signal_type) *
|
||||
catch_signal_split_args (char *arg, int *catch_all)
|
||||
{
|
||||
VEC (gdb_signal_type) *result = NULL;
|
||||
struct cleanup *cleanup = make_cleanup (VEC_cleanup (gdb_signal_type),
|
||||
&result);
|
||||
int first = 1;
|
||||
|
||||
while (*arg != '\0')
|
||||
{
|
||||
int num;
|
||||
gdb_signal_type signal_number;
|
||||
char *one_arg, *endptr;
|
||||
struct cleanup *inner_cleanup;
|
||||
|
||||
one_arg = extract_arg (&arg);
|
||||
if (one_arg == NULL)
|
||||
break;
|
||||
inner_cleanup = make_cleanup (xfree, one_arg);
|
||||
|
||||
/* Check for the special flag "all". */
|
||||
if (strcmp (one_arg, "all") == 0)
|
||||
{
|
||||
arg = skip_spaces (arg);
|
||||
if (*arg != '\0' || !first)
|
||||
error (_("'all' cannot be caught with other signals"));
|
||||
*catch_all = 1;
|
||||
gdb_assert (result == NULL);
|
||||
do_cleanups (inner_cleanup);
|
||||
discard_cleanups (cleanup);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
first = 0;
|
||||
|
||||
/* Check if the user provided a signal name or a number. */
|
||||
num = (int) strtol (one_arg, &endptr, 0);
|
||||
if (*endptr == '\0')
|
||||
signal_number = gdb_signal_from_command (num);
|
||||
else
|
||||
{
|
||||
signal_number = gdb_signal_from_name (one_arg);
|
||||
if (signal_number == GDB_SIGNAL_UNKNOWN)
|
||||
error (_("Unknown signal name '%s'."), one_arg);
|
||||
}
|
||||
|
||||
VEC_safe_push (gdb_signal_type, result, signal_number);
|
||||
do_cleanups (inner_cleanup);
|
||||
}
|
||||
|
||||
discard_cleanups (cleanup);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Implement the "catch signal" command. */
|
||||
|
||||
static void
|
||||
catch_signal_command (char *arg, int from_tty,
|
||||
struct cmd_list_element *command)
|
||||
{
|
||||
int tempflag, catch_all = 0;
|
||||
VEC (gdb_signal_type) *filter;
|
||||
struct gdbarch *gdbarch = get_current_arch ();
|
||||
|
||||
tempflag = get_cmd_context (command) == 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);
|
||||
else
|
||||
filter = NULL;
|
||||
|
||||
create_signal_catchpoint (tempflag, filter, catch_all);
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_signal_catchpoint_ops (void)
|
||||
{
|
||||
struct breakpoint_ops *ops;
|
||||
|
||||
initialize_breakpoint_ops ();
|
||||
|
||||
ops = &signal_catchpoint_ops;
|
||||
*ops = base_breakpoint_ops;
|
||||
ops->dtor = signal_catchpoint_dtor;
|
||||
ops->insert_location = signal_catchpoint_insert_location;
|
||||
ops->remove_location = signal_catchpoint_remove_location;
|
||||
ops->breakpoint_hit = signal_catchpoint_breakpoint_hit;
|
||||
ops->print_it = signal_catchpoint_print_it;
|
||||
ops->print_one = signal_catchpoint_print_one;
|
||||
ops->print_mention = signal_catchpoint_print_mention;
|
||||
ops->print_recreate = signal_catchpoint_print_recreate;
|
||||
ops->explains_signal = signal_catchpoint_explains_signal;
|
||||
}
|
||||
|
||||
initialize_file_ftype _initialize_break_catch_sig;
|
||||
|
||||
void
|
||||
_initialize_break_catch_sig (void)
|
||||
{
|
||||
initialize_signal_catchpoint_ops ();
|
||||
|
||||
signal_catch_counts = XCNEWVEC (unsigned int, GDB_SIGNAL_LAST);
|
||||
|
||||
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);
|
||||
}
|
@ -279,14 +279,9 @@ static struct bp_location **get_first_locp_gte_addr (CORE_ADDR address);
|
||||
|
||||
static int strace_marker_p (struct breakpoint *b);
|
||||
|
||||
static void init_catchpoint (struct breakpoint *b,
|
||||
struct gdbarch *gdbarch, int tempflag,
|
||||
char *cond_string,
|
||||
const struct breakpoint_ops *ops);
|
||||
|
||||
/* The abstract base class all breakpoint_ops structures inherit
|
||||
from. */
|
||||
static struct breakpoint_ops base_breakpoint_ops;
|
||||
struct breakpoint_ops base_breakpoint_ops;
|
||||
|
||||
/* The breakpoint_ops structure to be inherited by all breakpoint_ops
|
||||
that are implemented on top of software or hardware breakpoints
|
||||
@ -4152,6 +4147,29 @@ bpstat_find_breakpoint (bpstat bsp, struct breakpoint *breakpoint)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* See breakpoint.h. */
|
||||
|
||||
enum bpstat_signal_value
|
||||
bpstat_explains_signal (bpstat bsp)
|
||||
{
|
||||
enum bpstat_signal_value result = BPSTAT_SIGNAL_NO;
|
||||
|
||||
for (; bsp != NULL; bsp = bsp->next)
|
||||
{
|
||||
/* Ensure that, if we ever entered this loop, then we at least
|
||||
return BPSTAT_SIGNAL_HIDE. */
|
||||
enum bpstat_signal_value newval = BPSTAT_SIGNAL_HIDE;
|
||||
|
||||
if (bsp->breakpoint_at != NULL)
|
||||
newval = bsp->breakpoint_at->ops->explains_signal (bsp->breakpoint_at);
|
||||
|
||||
if (newval > result)
|
||||
result = newval;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Put in *NUM the breakpoint number of the first breakpoint we are
|
||||
stopped at. *BSP upon return is a bpstat which points to the
|
||||
remaining breakpoints stopped at (but which is not guaranteed to be
|
||||
@ -8349,7 +8367,7 @@ syscall_catchpoint_p (struct breakpoint *b)
|
||||
not NULL, then store it in the breakpoint. OPS, if not NULL, is
|
||||
the breakpoint_ops structure associated to the catchpoint. */
|
||||
|
||||
static void
|
||||
void
|
||||
init_catchpoint (struct breakpoint *b,
|
||||
struct gdbarch *gdbarch, int tempflag,
|
||||
char *cond_string,
|
||||
@ -12865,7 +12883,15 @@ base_breakpoint_decode_linespec (struct breakpoint *b, char **s,
|
||||
internal_error_pure_virtual_called ();
|
||||
}
|
||||
|
||||
static struct breakpoint_ops base_breakpoint_ops =
|
||||
/* The default 'explains_signal' method. */
|
||||
|
||||
static enum bpstat_signal_value
|
||||
base_breakpoint_explains_signal (struct breakpoint *b)
|
||||
{
|
||||
return BPSTAT_SIGNAL_HIDE;
|
||||
}
|
||||
|
||||
struct breakpoint_ops base_breakpoint_ops =
|
||||
{
|
||||
base_breakpoint_dtor,
|
||||
base_breakpoint_allocate_location,
|
||||
@ -12884,6 +12910,7 @@ static struct breakpoint_ops base_breakpoint_ops =
|
||||
base_breakpoint_create_sals_from_address,
|
||||
base_breakpoint_create_breakpoints_sal,
|
||||
base_breakpoint_decode_linespec,
|
||||
base_breakpoint_explains_signal
|
||||
};
|
||||
|
||||
/* Default breakpoint_ops methods. */
|
||||
|
@ -474,6 +474,22 @@ struct bp_location
|
||||
char *source_file;
|
||||
};
|
||||
|
||||
/* Return values for bpstat_explains_signal. Note that the order of
|
||||
the constants is important here; they are compared directly in
|
||||
bpstat_explains_signal. */
|
||||
|
||||
enum bpstat_signal_value
|
||||
{
|
||||
/* bpstat does not explain this signal. */
|
||||
BPSTAT_SIGNAL_NO = 0,
|
||||
|
||||
/* bpstat explains this signal; signal should not be delivered. */
|
||||
BPSTAT_SIGNAL_HIDE,
|
||||
|
||||
/* bpstat explains this signal; signal should be delivered. */
|
||||
BPSTAT_SIGNAL_PASS
|
||||
};
|
||||
|
||||
/* This structure is a collection of function pointers that, if available,
|
||||
will be called instead of the performing the default action for this
|
||||
bptype. */
|
||||
@ -588,6 +604,12 @@ struct breakpoint_ops
|
||||
This function is called inside `addr_string_to_sals'. */
|
||||
void (*decode_linespec) (struct breakpoint *, char **,
|
||||
struct symtabs_and_lines *);
|
||||
|
||||
/* Return true if this breakpoint explains a signal, but the signal
|
||||
should still be delivered to the inferior. This is used to make
|
||||
'catch signal' interact properly with 'handle'; see
|
||||
bpstat_explains_signal. */
|
||||
enum bpstat_signal_value (*explains_signal) (struct breakpoint *);
|
||||
};
|
||||
|
||||
/* Helper for breakpoint_ops->print_recreate implementations. Prints
|
||||
@ -980,10 +1002,9 @@ struct bpstat_what bpstat_what (bpstat);
|
||||
bpstat bpstat_find_breakpoint (bpstat, struct breakpoint *);
|
||||
|
||||
/* Nonzero if a signal that we got in wait() was due to circumstances
|
||||
explained by the BS. */
|
||||
/* Currently that is true if we have hit a breakpoint, or if there is
|
||||
a watchpoint enabled. */
|
||||
#define bpstat_explains_signal(bs) ((bs) != NULL)
|
||||
explained by the bpstat; and the signal should therefore not be
|
||||
delivered. */
|
||||
extern enum bpstat_signal_value bpstat_explains_signal (bpstat);
|
||||
|
||||
/* Nonzero is this bpstat causes a stop. */
|
||||
extern int bpstat_causes_stop (bpstat);
|
||||
@ -1183,6 +1204,7 @@ extern void awatch_command_wrapper (char *, int, int);
|
||||
extern void rwatch_command_wrapper (char *, int, int);
|
||||
extern void tbreak_command (char *, int);
|
||||
|
||||
extern struct breakpoint_ops base_breakpoint_ops;
|
||||
extern struct breakpoint_ops bkpt_breakpoint_ops;
|
||||
extern struct breakpoint_ops tracepoint_breakpoint_ops;
|
||||
|
||||
@ -1215,6 +1237,11 @@ extern void
|
||||
int tempflag,
|
||||
int from_tty);
|
||||
|
||||
extern void init_catchpoint (struct breakpoint *b,
|
||||
struct gdbarch *gdbarch, int tempflag,
|
||||
char *cond_string,
|
||||
const struct breakpoint_ops *ops);
|
||||
|
||||
/* Add breakpoint B on the breakpoint list, and notify the user, the
|
||||
target and breakpoint_created observers of its existence. If
|
||||
INTERNAL is non-zero, the breakpoint number will be allocated from
|
||||
|
@ -1,3 +1,8 @@
|
||||
2013-01-16 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.texinfo (Set Catchpoints): Document "catch signal".
|
||||
(Signals): Likewise.
|
||||
|
||||
2013-01-16 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.texinfo (GDB/MI Breakpoint Information): Document
|
||||
|
@ -4234,6 +4234,31 @@ The loading or unloading of a shared library. If @var{regexp} is
|
||||
given, then the catchpoint will stop only if the regular expression
|
||||
matches one of the affected libraries.
|
||||
|
||||
@item signal @r{[}@var{signal}@dots{} @r{|} @samp{all}@r{]}
|
||||
The delivery of a signal.
|
||||
|
||||
With no arguments, this catchpoint will catch any signal that is not
|
||||
used internally by @value{GDBN}, specifically, all signals except
|
||||
@samp{SIGTRAP} and @samp{SIGINT}.
|
||||
|
||||
With the argument @samp{all}, all signals, including those used by
|
||||
@value{GDBN}, will be caught. This argument cannot be used with other
|
||||
signal names.
|
||||
|
||||
Otherwise, the arguments are a list of signal names as given to
|
||||
@code{handle} (@pxref{Signals}). Only signals specified in this list
|
||||
will be caught.
|
||||
|
||||
One reason that @code{catch signal} can be more useful than
|
||||
@code{handle} is that you can attach commands and conditions to the
|
||||
catchpoint.
|
||||
|
||||
When a signal is caught by a catchpoint, the signal's @code{stop} and
|
||||
@code{print} settings, as specified by @code{handle}, are ignored.
|
||||
However, whether the signal is still delivered to the inferior depends
|
||||
on the @code{pass} setting; this can be changed in the catchpoint's
|
||||
commands.
|
||||
|
||||
@end table
|
||||
|
||||
@item tcatch @var{event}
|
||||
@ -5326,6 +5351,10 @@ Similar, but print information only about the specified signal number.
|
||||
|
||||
@code{info handle} is an alias for @code{info signals}.
|
||||
|
||||
@item catch signal @r{[}@var{signal}@dots{} @r{|} @samp{all}@r{]}
|
||||
Set a catchpoint for the indicated signals. @xref{Set Catchpoints},
|
||||
for details about this command.
|
||||
|
||||
@kindex handle
|
||||
@item handle @var{signal} @r{[}@var{keywords}@dots{}@r{]}
|
||||
Change the way @value{GDBN} handles signal @var{signal}. @var{signal}
|
||||
|
@ -632,6 +632,8 @@ extern void update_observer_mode (void);
|
||||
|
||||
extern void update_signals_program_target (void);
|
||||
|
||||
extern void signal_catch_update (const unsigned int *);
|
||||
|
||||
/* In some circumstances we allow a command to specify a numeric
|
||||
signal. The idea is to keep these circumstances limited so that
|
||||
users (and scripts) develop portable habits. For comparison,
|
||||
|
270
gdb/infrun.c
270
gdb/infrun.c
@ -318,6 +318,12 @@ static unsigned char *signal_stop;
|
||||
static unsigned char *signal_print;
|
||||
static unsigned char *signal_program;
|
||||
|
||||
/* Table of signals that are registered with "catch signal". A
|
||||
non-zero entry indicates that the signal is caught by some "catch
|
||||
signal" command. This has size GDB_SIGNAL_LAST, to accommodate all
|
||||
signals. */
|
||||
static unsigned char *signal_catch;
|
||||
|
||||
/* Table of signals that the target may silently handle.
|
||||
This is automatically determined from the flags above,
|
||||
and simply cached here. */
|
||||
@ -3079,6 +3085,8 @@ handle_syscall_event (struct execution_control_state *ecs)
|
||||
if (catch_syscall_enabled () > 0
|
||||
&& catching_syscall_number (syscall_number) > 0)
|
||||
{
|
||||
enum bpstat_signal_value sval;
|
||||
|
||||
if (debug_infrun)
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
|
||||
syscall_number);
|
||||
@ -3086,8 +3094,9 @@ handle_syscall_event (struct execution_control_state *ecs)
|
||||
ecs->event_thread->control.stop_bpstat
|
||||
= bpstat_stop_status (get_regcache_aspace (regcache),
|
||||
stop_pc, ecs->ptid, &ecs->ws);
|
||||
ecs->random_signal
|
||||
= !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
||||
|
||||
sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
||||
ecs->random_signal = sval == BPSTAT_SIGNAL_NO;
|
||||
|
||||
if (!ecs->random_signal)
|
||||
{
|
||||
@ -3319,6 +3328,7 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||
if (stop_soon == NO_STOP_QUIETLY)
|
||||
{
|
||||
struct regcache *regcache;
|
||||
enum bpstat_signal_value sval;
|
||||
|
||||
if (!ptid_equal (ecs->ptid, inferior_ptid))
|
||||
context_switch (ecs->ptid);
|
||||
@ -3329,8 +3339,10 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||
ecs->event_thread->control.stop_bpstat
|
||||
= bpstat_stop_status (get_regcache_aspace (regcache),
|
||||
stop_pc, ecs->ptid, &ecs->ws);
|
||||
ecs->random_signal
|
||||
= !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
||||
|
||||
sval
|
||||
= bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
||||
ecs->random_signal = sval == BPSTAT_SIGNAL_NO;
|
||||
|
||||
if (!ecs->random_signal)
|
||||
{
|
||||
@ -3628,7 +3640,8 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
|
||||
stop_pc, ecs->ptid, &ecs->ws);
|
||||
ecs->random_signal
|
||||
= !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
||||
= (bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
|
||||
== BPSTAT_SIGNAL_NO);
|
||||
|
||||
/* Note that this may be referenced from inside
|
||||
bpstat_stop_status above, through inferior_has_execd. */
|
||||
@ -4133,128 +4146,121 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||
will be made according to the signal handling tables. */
|
||||
|
||||
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
||||
|| stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
|
||||
|| stop_soon == STOP_QUIETLY_REMOTE)
|
||||
&& stop_after_trap)
|
||||
{
|
||||
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
||||
&& stop_after_trap)
|
||||
{
|
||||
if (debug_infrun)
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
|
||||
stop_print_frame = 0;
|
||||
stop_stepping (ecs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is originated from start_remote(), start_inferior() and
|
||||
shared libraries hook functions. */
|
||||
if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
|
||||
{
|
||||
if (debug_infrun)
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
|
||||
stop_stepping (ecs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This originates from attach_command(). We need to overwrite
|
||||
the stop_signal here, because some kernels don't ignore a
|
||||
SIGSTOP in a subsequent ptrace(PTRACE_CONT,SIGSTOP) call.
|
||||
See more comments in inferior.h. On the other hand, if we
|
||||
get a non-SIGSTOP, report it to the user - assume the backend
|
||||
will handle the SIGSTOP if it should show up later.
|
||||
|
||||
Also consider that the attach is complete when we see a
|
||||
SIGTRAP. Some systems (e.g. Windows), and stubs supporting
|
||||
target extended-remote report it instead of a SIGSTOP
|
||||
(e.g. gdbserver). We already rely on SIGTRAP being our
|
||||
signal, so this is no exception.
|
||||
|
||||
Also consider that the attach is complete when we see a
|
||||
GDB_SIGNAL_0. In non-stop mode, GDB will explicitly tell
|
||||
the target to stop all threads of the inferior, in case the
|
||||
low level attach operation doesn't stop them implicitly. If
|
||||
they weren't stopped implicitly, then the stub will report a
|
||||
GDB_SIGNAL_0, meaning: stopped for no particular reason
|
||||
other than GDB's request. */
|
||||
if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
|
||||
&& (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_STOP
|
||||
|| ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
||||
|| ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_0))
|
||||
{
|
||||
stop_stepping (ecs);
|
||||
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if there is a breakpoint/watchpoint/catchpoint/etc. that
|
||||
handles this event. */
|
||||
ecs->event_thread->control.stop_bpstat
|
||||
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
|
||||
stop_pc, ecs->ptid, &ecs->ws);
|
||||
|
||||
/* Following in case break condition called a
|
||||
function. */
|
||||
stop_print_frame = 1;
|
||||
|
||||
/* This is where we handle "moribund" watchpoints. Unlike
|
||||
software breakpoints traps, hardware watchpoint traps are
|
||||
always distinguishable from random traps. If no high-level
|
||||
watchpoint is associated with the reported stop data address
|
||||
anymore, then the bpstat does not explain the signal ---
|
||||
simply make sure to ignore it if `stopped_by_watchpoint' is
|
||||
set. */
|
||||
|
||||
if (debug_infrun
|
||||
&& ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
||||
&& !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
|
||||
&& stopped_by_watchpoint)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"infrun: no user watchpoint explains "
|
||||
"watchpoint SIGTRAP, ignoring\n");
|
||||
|
||||
/* NOTE: cagney/2003-03-29: These two checks for a random signal
|
||||
at one stage in the past included checks for an inferior
|
||||
function call's call dummy's return breakpoint. The original
|
||||
comment, that went with the test, read:
|
||||
|
||||
``End of a stack dummy. Some systems (e.g. Sony news) give
|
||||
another signal besides SIGTRAP, so check here as well as
|
||||
above.''
|
||||
|
||||
If someone ever tries to get call dummys on a
|
||||
non-executable stack to work (where the target would stop
|
||||
with something like a SIGSEGV), then those tests might need
|
||||
to be re-instated. Given, however, that the tests were only
|
||||
enabled when momentary breakpoints were not being used, I
|
||||
suspect that it won't be the case.
|
||||
|
||||
NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
|
||||
be necessary for call dummies on a non-executable stack on
|
||||
SPARC. */
|
||||
|
||||
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
|
||||
ecs->random_signal
|
||||
= !(bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
|
||||
|| stopped_by_watchpoint
|
||||
|| ecs->event_thread->control.trap_expected
|
||||
|| (ecs->event_thread->control.step_range_end
|
||||
&& (ecs->event_thread->control.step_resume_breakpoint
|
||||
== NULL)));
|
||||
else
|
||||
{
|
||||
ecs->random_signal = !bpstat_explains_signal
|
||||
(ecs->event_thread->control.stop_bpstat);
|
||||
if (!ecs->random_signal)
|
||||
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
|
||||
}
|
||||
if (debug_infrun)
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
|
||||
stop_print_frame = 0;
|
||||
stop_stepping (ecs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* When we reach this point, we've pretty much decided
|
||||
that the reason for stopping must've been a random
|
||||
(unexpected) signal. */
|
||||
/* This is originated from start_remote(), start_inferior() and
|
||||
shared libraries hook functions. */
|
||||
if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
|
||||
{
|
||||
if (debug_infrun)
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
|
||||
stop_stepping (ecs);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This originates from attach_command(). We need to overwrite
|
||||
the stop_signal here, because some kernels don't ignore a
|
||||
SIGSTOP in a subsequent ptrace(PTRACE_CONT,SIGSTOP) call.
|
||||
See more comments in inferior.h. On the other hand, if we
|
||||
get a non-SIGSTOP, report it to the user - assume the backend
|
||||
will handle the SIGSTOP if it should show up later.
|
||||
|
||||
Also consider that the attach is complete when we see a
|
||||
SIGTRAP. Some systems (e.g. Windows), and stubs supporting
|
||||
target extended-remote report it instead of a SIGSTOP
|
||||
(e.g. gdbserver). We already rely on SIGTRAP being our
|
||||
signal, so this is no exception.
|
||||
|
||||
Also consider that the attach is complete when we see a
|
||||
GDB_SIGNAL_0. In non-stop mode, GDB will explicitly tell
|
||||
the target to stop all threads of the inferior, in case the
|
||||
low level attach operation doesn't stop them implicitly. If
|
||||
they weren't stopped implicitly, then the stub will report a
|
||||
GDB_SIGNAL_0, meaning: stopped for no particular reason
|
||||
other than GDB's request. */
|
||||
if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
|
||||
&& (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_STOP
|
||||
|| ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
||||
|| ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_0))
|
||||
{
|
||||
stop_stepping (ecs);
|
||||
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* See if there is a breakpoint/watchpoint/catchpoint/etc. that
|
||||
handles this event. */
|
||||
ecs->event_thread->control.stop_bpstat
|
||||
= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
|
||||
stop_pc, ecs->ptid, &ecs->ws);
|
||||
|
||||
/* Following in case break condition called a
|
||||
function. */
|
||||
stop_print_frame = 1;
|
||||
|
||||
/* This is where we handle "moribund" watchpoints. Unlike
|
||||
software breakpoints traps, hardware watchpoint traps are
|
||||
always distinguishable from random traps. If no high-level
|
||||
watchpoint is associated with the reported stop data address
|
||||
anymore, then the bpstat does not explain the signal ---
|
||||
simply make sure to ignore it if `stopped_by_watchpoint' is
|
||||
set. */
|
||||
|
||||
if (debug_infrun
|
||||
&& ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP
|
||||
&& (bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
|
||||
== BPSTAT_SIGNAL_NO)
|
||||
&& stopped_by_watchpoint)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"infrun: no user watchpoint explains "
|
||||
"watchpoint SIGTRAP, ignoring\n");
|
||||
|
||||
/* NOTE: cagney/2003-03-29: These two checks for a random signal
|
||||
at one stage in the past included checks for an inferior
|
||||
function call's call dummy's return breakpoint. The original
|
||||
comment, that went with the test, read:
|
||||
|
||||
``End of a stack dummy. Some systems (e.g. Sony news) give
|
||||
another signal besides SIGTRAP, so check here as well as
|
||||
above.''
|
||||
|
||||
If someone ever tries to get call dummys on a
|
||||
non-executable stack to work (where the target would stop
|
||||
with something like a SIGSEGV), then those tests might need
|
||||
to be re-instated. Given, however, that the tests were only
|
||||
enabled when momentary breakpoints were not being used, I
|
||||
suspect that it won't be the case.
|
||||
|
||||
NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
|
||||
be necessary for call dummies on a non-executable stack on
|
||||
SPARC. */
|
||||
|
||||
if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP)
|
||||
ecs->random_signal
|
||||
= !((bpstat_explains_signal (ecs->event_thread->control.stop_bpstat)
|
||||
!= BPSTAT_SIGNAL_NO)
|
||||
|| stopped_by_watchpoint
|
||||
|| ecs->event_thread->control.trap_expected
|
||||
|| (ecs->event_thread->control.step_range_end
|
||||
&& (ecs->event_thread->control.step_resume_breakpoint
|
||||
== NULL)));
|
||||
else
|
||||
ecs->random_signal = 1;
|
||||
{
|
||||
enum bpstat_signal_value sval;
|
||||
|
||||
sval = bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
|
||||
ecs->random_signal = (sval == BPSTAT_SIGNAL_NO);
|
||||
|
||||
if (sval == BPSTAT_SIGNAL_HIDE)
|
||||
ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_TRAP;
|
||||
}
|
||||
|
||||
process_event_stop_test:
|
||||
|
||||
@ -6205,7 +6211,8 @@ signal_cache_update (int signo)
|
||||
|
||||
signal_pass[signo] = (signal_stop[signo] == 0
|
||||
&& signal_print[signo] == 0
|
||||
&& signal_program[signo] == 1);
|
||||
&& signal_program[signo] == 1
|
||||
&& signal_catch[signo] == 0);
|
||||
}
|
||||
|
||||
int
|
||||
@ -6238,6 +6245,20 @@ signal_pass_update (int signo, int state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update the global 'signal_catch' from INFO and notify the
|
||||
target. */
|
||||
|
||||
void
|
||||
signal_catch_update (const unsigned int *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GDB_SIGNAL_LAST; ++i)
|
||||
signal_catch[i] = info[i] > 0;
|
||||
signal_cache_update (-1);
|
||||
target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
|
||||
}
|
||||
|
||||
static void
|
||||
sig_print_header (void)
|
||||
{
|
||||
@ -7223,6 +7244,8 @@ leave it stopped or free to run as needed."),
|
||||
xmalloc (sizeof (signal_print[0]) * numsigs);
|
||||
signal_program = (unsigned char *)
|
||||
xmalloc (sizeof (signal_program[0]) * numsigs);
|
||||
signal_catch = (unsigned char *)
|
||||
xmalloc (sizeof (signal_catch[0]) * numsigs);
|
||||
signal_pass = (unsigned char *)
|
||||
xmalloc (sizeof (signal_program[0]) * numsigs);
|
||||
for (i = 0; i < numsigs; i++)
|
||||
@ -7230,6 +7253,7 @@ leave it stopped or free to run as needed."),
|
||||
signal_stop[i] = 1;
|
||||
signal_print[i] = 1;
|
||||
signal_program[i] = 1;
|
||||
signal_catch[i] = 0;
|
||||
}
|
||||
|
||||
/* Signals caused by debugger's own actions
|
||||
|
@ -1,3 +1,8 @@
|
||||
2013-01-16 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.base/catch-signal.c: New file.
|
||||
* gdb.base/catch-signal.exp: New file.
|
||||
|
||||
2013-01-16 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.mi/mi-catch-load.exp: Look for "catch-type".
|
||||
|
46
gdb/testsuite/gdb.base/catch-signal.c
Normal file
46
gdb/testsuite/gdb.base/catch-signal.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2012 Free Software Foundation, Inc.
|
||||
|
||||
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 <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void
|
||||
do_nothing (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
handle (int sig)
|
||||
{
|
||||
do_nothing (); /* handle marker */
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
signal (SIGHUP, handle);
|
||||
signal (SIGUSR1, SIG_IGN);
|
||||
|
||||
raise (SIGHUP); /* first HUP */
|
||||
|
||||
raise (SIGHUP); /* second HUP */
|
||||
|
||||
raise (SIGHUP); /* third HUP */
|
||||
|
||||
raise (SIGHUP); /* fourth HUP */
|
||||
}
|
||||
|
129
gdb/testsuite/gdb.base/catch-signal.exp
Normal file
129
gdb/testsuite/gdb.base/catch-signal.exp
Normal file
@ -0,0 +1,129 @@
|
||||
# Copyright 2012 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
if [target_info exists gdb,nosignals] {
|
||||
verbose "Skipping sigall.exp because of nosignals."
|
||||
continue
|
||||
}
|
||||
|
||||
standard_testfile
|
||||
|
||||
if {[prepare_for_testing $testfile.exp $testfile $srcfile debug]} {
|
||||
return -1
|
||||
}
|
||||
|
||||
proc test_catch_signal {signame} {
|
||||
global srcfile
|
||||
|
||||
with_test_prefix $signame {
|
||||
if {![runto_main]} {
|
||||
return -1
|
||||
}
|
||||
|
||||
# Test "catch signal" without arguments.
|
||||
# Don't let the signal be handled otherwise.
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "first HUP"]
|
||||
gdb_continue_to_breakpoint "first HUP"
|
||||
gdb_test "handle SIGHUP nostop noprint pass" \
|
||||
"SIGHUP.*No.*No.*Yes.*"
|
||||
gdb_test "catch signal" "Catchpoint .*"
|
||||
gdb_test "continue" "Catchpoint .*"
|
||||
|
||||
# Now ensure that the "pass" setting worked, and also that we did not
|
||||
# see gdb's SIGTRAP.
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "handle marker"]
|
||||
gdb_continue_to_breakpoint "handle marker"
|
||||
|
||||
delete_breakpoints
|
||||
|
||||
# Catch just $SIGNAME.
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "second HUP"]
|
||||
gdb_continue_to_breakpoint "second HUP"
|
||||
gdb_test "catch signal $signame" "Catchpoint .*"
|
||||
gdb_test "continue" "Catchpoint .*"
|
||||
delete_breakpoints
|
||||
|
||||
# Catch just SIGUSR1 -- but it isn't sent.
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "third HUP"]
|
||||
gdb_continue_to_breakpoint "third HUP"
|
||||
gdb_test "handle SIGUSR1 nostop noprint pass" \
|
||||
"SIGUSR1.*No.*No.*Yes.*"
|
||||
gdb_test "catch signal SIGUSR1" "Catchpoint .*"
|
||||
|
||||
# Also verify that if we set SIGHUP to "nopass", then it is
|
||||
# still not delivered.
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "handle marker"]
|
||||
gdb_test "handle SIGHUP nostop noprint nopass" \
|
||||
"SIGHUP.*No.*No.*No.*"
|
||||
|
||||
gdb_breakpoint ${srcfile}:[gdb_get_line_number "fourth HUP"]
|
||||
gdb_continue_to_breakpoint "fourth HUP"
|
||||
delete_breakpoints
|
||||
}
|
||||
}
|
||||
|
||||
# Test with symbolic signal.
|
||||
test_catch_signal SIGHUP
|
||||
|
||||
# Test with numeric signal.
|
||||
clean_restart $testfile
|
||||
test_catch_signal 1
|
||||
|
||||
# Test with two signals in catchpoint.
|
||||
clean_restart $testfile
|
||||
test_catch_signal "SIGHUP SIGUSR2"
|
||||
|
||||
#
|
||||
# Coverage tests.
|
||||
#
|
||||
|
||||
gdb_test "catch signal SIGZARDOZ" "Unknown signal name 'SIGZARDOZ'."
|
||||
gdb_test "catch signal all" "Catchpoint .*"
|
||||
gdb_test "catch signal all SIGHUP" "'all' cannot be caught with other signals"
|
||||
gdb_test "catch signal SIGHUP all" "'all' cannot be caught with other signals"
|
||||
|
||||
set i 0
|
||||
foreach {arg desc} {"" "standard signals" \
|
||||
SIGHUP SIGHUP \
|
||||
"SIGHUP SIGUSR2" "SIGHUP SIGUSR2" \
|
||||
all "any signal"} {
|
||||
delete_breakpoints
|
||||
gdb_test "catch signal $arg" "Catchpoint .*" \
|
||||
"set catchpoint '$arg' for printing"
|
||||
gdb_test "info break" "$decimal.*catchpoint.*signal.*$desc.*" \
|
||||
"info break for '$arg'"
|
||||
gdb_test "save breakpoints [standard_output_file bps.$i]" \
|
||||
"Saved to file .*bps.$i.*" \
|
||||
"save breakpoints for '$arg'"
|
||||
|
||||
set filename [remote_upload host [standard_output_file bps.$i] \
|
||||
[standard_output_file bps-local.$i]]
|
||||
set fd [open $filename]
|
||||
set contents [read -nonewline $fd]
|
||||
close $fd
|
||||
|
||||
if {$arg == ""} {
|
||||
set pattern "catch signal"
|
||||
} else {
|
||||
set pattern "catch signal $arg"
|
||||
}
|
||||
if {[string match $pattern $contents]} {
|
||||
pass "results of save breakpoints for '$arg'"
|
||||
} else {
|
||||
fail "results of save breakpoints for '$arg'"
|
||||
}
|
||||
|
||||
incr i
|
||||
}
|
Loading…
Reference in New Issue
Block a user