* RFC: implement "catch signal"
@ 2012-11-16 19:07 Tom Tromey
2012-11-16 19:49 ` Eli Zaretskii
` (2 more replies)
0 siblings, 3 replies; 27+ messages in thread
From: Tom Tromey @ 2012-11-16 19:07 UTC (permalink / raw)
To: gdb-patches
This patch implements "catch signal". I took Pedro's unfinished "catch
signal" patch and worked on it a bit.
This needs a doc review at least.
I think a lot of the patch is straightforward, but a few areas deserve
some notes.
break-catch-sig.c keeps count of all the signals caught by any
catchpoint and transmits this to infrun via signal_catch_update. This
in turn is how changes are communicated the target.
The main change to inferior control is that handle_inferior_event now
always uses the 'bpstat' branch to see what should be done with a
signal. This necessitated some reindentation, so part of the patch is
hard to read.
This in turn needed a change to bpstat_explains_signal. Previously,
signals handled via some bpstat were turned into GDB_SIGNAL_TRAP -- but
this is not correct for "catch signal", as we want to (possibly) deliver
the signal when the inferior is resumed.
For this I added a new breakpoint_ops method and a new enum.
One question while developing this is how the catchpoint should interact
with "handle". The approach implemented here is:
* If a signal is caught by a catchpoint, then the "handle stop" and
"handle print" settings for that signal are ignored.
These are easily dealt with by the catchpoint itself, and this
approach allows better scripting control.
* However, the "handle pass" setting is still respected. A catchpoint's
commands can still override this, either by invoking "handle" or by
explicitly continuing with "signal 0".
I chose to have "catch signal" ignore signals that are used internally
by gdb. Instead, users can use "catch signal all" to catch even those.
I think this is a more useful default.
Built and regtested on x86-64 Fedora 16.
There's a new test case included. I ran this through gcov and
break-catch-sig.c has good coverage -- 98.3% of lines and 87.7% of
branches (some of which come from vec.h, and so "don't count").
Tom
2012-11-16 Pedro Alves <palves@redhat.com>
Tom Tromey <tromey@redhat.com>
* 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.
2012-11-16 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Set Catchpoints): Document "catch signal".
(Signals): Likewise.
2012-11-16 Tom Tromey <tromey@redhat.com>
* gdb.base/catch-signal.c: New file.
* gdb.base/catch-signal.exp: New file.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9e7702d..48e9a9c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -692,7 +692,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 \
diff --git a/gdb/NEWS b/gdb/NEWS
index 739a7b3..5533174 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -42,6 +42,10 @@
* 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.
diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
new file mode 100644
index 0000000..cd5f1bf
--- /dev/null
+++ b/gdb/break-catch-sig.c
@@ -0,0 +1,496 @@
+/* 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"
+
+#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. The list elements
+ are allocated with xmalloc. */
+ VEC (gdb_signal_type) *signals_to_be_caught;
+
+ int catch_all;
+};
+
+/* The breakpoint_ops structure to be used in signal catchpoints. */
+
+static struct breakpoint_ops signal_catchpoint_ops;
+
+/* An object of this type holds global information about all signal
+ catchpoints. */
+
+struct signal_catch_info
+{
+ /* Count of each signal. */
+
+ unsigned int *counts;
+};
+
+/* Global information about all signal catchpoints. */
+
+static struct signal_catch_info signal_catch_info;
+
+\f
+
+/* 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;
+}
+
+\f
+
+/* 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;
+ struct signal_catch_info *info = &signal_catch_info;
+ int i;
+ gdb_signal_type iter;
+
+ if (c->signals_to_be_caught != NULL)
+ {
+ for (i = 0;
+ VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
+ i++)
+ ++info->counts[iter];
+ }
+ else
+ {
+ for (i = 0; i < GDB_SIGNAL_LAST; ++i)
+ {
+ if (c->catch_all || !INTERNAL_SIGNAL (i))
+ ++info->counts[i];
+ }
+ }
+
+ signal_catch_update (info->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;
+ struct signal_catch_info *info = &signal_catch_info;
+ int i;
+ gdb_signal_type iter;
+
+ if (c->signals_to_be_caught != NULL)
+ {
+ for (i = 0;
+ VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
+ i++)
+ --info->counts[iter];
+ }
+ else
+ {
+ for (i = 0; i < GDB_SIGNAL_LAST; ++i)
+ {
+ if (c->catch_all || !INTERNAL_SIGNAL (i))
+ ++info->counts[i];
+ }
+ }
+
+ signal_catch_update (info->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 = gdb_signal_to_name (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;
+ char *text = xstrdup ("");
+
+ for (i = 0;
+ VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
+ i++)
+ {
+ char *x = text;
+ const char *name = signal_to_name_or_int (iter);
+
+ text = xstrprintf (i > 0 ? "%s, %s" : "%s%s", text, name);
+ xfree (x);
+ }
+ ui_out_field_string (uiout, "what", text);
+ xfree (text);
+ }
+ else
+ ui_out_field_string (uiout, "what",
+ c->catch_all ? "<any signal>" : "<standard signals>");
+ ui_out_text (uiout, "\" ");
+}
+
+/* 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_info.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]...|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);
+}
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ccf7ee1..894f1ae 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -272,14 +272,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
@@ -4144,6 +4139,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
@@ -8299,7 +8317,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,
@@ -12803,7 +12821,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,
@@ -12822,6 +12848,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. */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 8b1bcb7..11c4b36 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 86cfe8e..ca0734e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4244,6 +4244,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}
@@ -5336,6 +5361,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}
diff --git a/gdb/inferior.h b/gdb/inferior.h
index e1e7d29..7104dc1 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -649,6 +649,8 @@ extern void update_observer_mode (void);
extern void update_signals_program_target (void);
+extern void signal_catch_update (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,
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 4efc2af..61c7735 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -318,6 +318,9 @@ static unsigned char *signal_stop;
static unsigned char *signal_print;
static unsigned char *signal_program;
+/* Table of signals that are registered with "catch signal". */
+static unsigned int *signal_catch;
+
/* Table of signals that the target may silently handle.
This is automatically determined from the flags above,
and simply cached here. */
@@ -3093,6 +3096,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);
@@ -3100,8 +3105,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)
{
@@ -3333,6 +3339,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);
@@ -3343,8 +3350,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)
{
@@ -3642,7 +3651,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. */
@@ -4147,128 +4157,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;
- }
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
+ stop_print_frame = 0;
+ 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;
- }
+ /* 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;
+ }
- /* 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);
+ /* 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;
+ }
- /* 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");
+ /* 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);
- /* 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:
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
- ``End of a stack dummy. Some systems (e.g. Sony news) give
- another signal besides SIGTRAP, so check here as well as
- above.''
+ /* 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");
- 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: 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:
- NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
- be necessary for call dummies on a non-executable stack on
- SPARC. */
+ ``End of a stack dummy. Some systems (e.g. Sony news) give
+ another signal besides SIGTRAP, so check here as well as
+ above.''
- 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 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.
- /* When we reach this point, we've pretty much decided
- that the reason for stopping must've been a random
- (unexpected) signal. */
+ 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:
@@ -6218,7 +6221,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
@@ -6251,6 +6255,18 @@ signal_pass_update (int signo, int state)
return ret;
}
+/* Update the global 'signal_catch' from INFO and notify the
+ target. */
+
+void
+signal_catch_update (unsigned int *info)
+{
+ memcpy (signal_catch, info, GDB_SIGNAL_LAST * sizeof (unsigned int));
+ signal_cache_update (-1);
+ target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
+ target_program_signals ((int) GDB_SIGNAL_LAST, signal_program);
+}
+
static void
sig_print_header (void)
{
@@ -7236,6 +7252,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 int *)
+ xmalloc (sizeof (signal_catch[0]) * numsigs);
signal_pass = (unsigned char *)
xmalloc (sizeof (signal_program[0]) * numsigs);
for (i = 0; i < numsigs; i++)
@@ -7243,6 +7261,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
diff --git a/gdb/testsuite/gdb.base/catch-signal.c b/gdb/testsuite/gdb.base/catch-signal.c
new file mode 100644
index 0000000..68690e9
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-signal.c
@@ -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);
+
+ kill (getpid (), SIGHUP); /* first HUP */
+
+ kill (getpid (), SIGHUP); /* second HUP */
+
+ kill (getpid (), SIGHUP); /* third HUP */
+
+ kill (getpid (), SIGHUP); /* fourth HUP */
+}
+
diff --git a/gdb/testsuite/gdb.base/catch-signal.exp b/gdb/testsuite/gdb.base/catch-signal.exp
new file mode 100644
index 0000000..f956b51
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-signal.exp
@@ -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
+}
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-11-16 19:07 RFC: implement "catch signal" Tom Tromey
@ 2012-11-16 19:49 ` Eli Zaretskii
2012-11-17 2:22 ` Yao Qi
2012-12-02 9:38 ` Jan Kratochvil
2 siblings, 0 replies; 27+ messages in thread
From: Eli Zaretskii @ 2012-11-16 19:49 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tromey@redhat.com>
> Date: Fri, 16 Nov 2012 12:06:40 -0700
>
> This patch implements "catch signal". I took Pedro's unfinished "catch
> signal" patch and worked on it a bit.
>
> This needs a doc review at least.
Thanks. The doc is OK, with the exception of one comment:
> +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.
I suggest to make the last part of this less vague, by saying _how_
that can be changed.
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-11-16 19:07 RFC: implement "catch signal" Tom Tromey
2012-11-16 19:49 ` Eli Zaretskii
@ 2012-11-17 2:22 ` Yao Qi
2012-12-02 9:38 ` Jan Kratochvil
2 siblings, 0 replies; 27+ messages in thread
From: Yao Qi @ 2012-11-17 2:22 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 11/17/2012 03:06 AM, Tom Tromey wrote:
> * 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.
FWIW, I am happy to see that some interfaces are exposed from
breakpoint.c, and this new feature is implemented in a new file instead
of in already-too-long breakpoint.c.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-11-16 19:07 RFC: implement "catch signal" Tom Tromey
2012-11-16 19:49 ` Eli Zaretskii
2012-11-17 2:22 ` Yao Qi
@ 2012-12-02 9:38 ` Jan Kratochvil
2012-12-03 18:59 ` Tom Tromey
2 siblings, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-12-02 9:38 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Fri, 16 Nov 2012 20:06:40 +0100, Tom Tromey wrote:
[...]
> --- /dev/null
> +++ b/gdb/break-catch-sig.c
> @@ -0,0 +1,496 @@
> +/* 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"
> +
> +#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. The list elements
> + are allocated with xmalloc. */
> + VEC (gdb_signal_type) *signals_to_be_caught;
> +
Missing comment
/* If SIGNALS_TO_BE_CAUGHT is NULL then all the signals are caught,
INTERNAL_SIGNAL are additionally caught only iff CATCH_ALL. If
SIGNALS_TO_BE_CAUGHT is not NULL then CATCH_ALL is undefined. */
> + int catch_all;
> +};
> +
> +/* The breakpoint_ops structure to be used in signal catchpoints. */
> +
> +static struct breakpoint_ops signal_catchpoint_ops;
> +
> +/* An object of this type holds global information about all signal
> + catchpoints. */
> +
> +struct signal_catch_info
> +{
> + /* Count of each signal. */
> +
> + unsigned int *counts;
> +};
> +
> +/* Global information about all signal catchpoints. */
> +
> +static struct signal_catch_info signal_catch_info;
It is a single global variable, I find it overengineered.
[...]
> +/* 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;
> + struct signal_catch_info *info = &signal_catch_info;
> + int i;
> + gdb_signal_type iter;
> +
> + if (c->signals_to_be_caught != NULL)
> + {
> + for (i = 0;
> + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
> + i++)
Here could be > 0 assert.
> + --info->counts[iter];
> + }
> + else
> + {
> + for (i = 0; i < GDB_SIGNAL_LAST; ++i)
> + {
> + if (c->catch_all || !INTERNAL_SIGNAL (i))
> + ++info->counts[i];
Here should be --. And possibly an assert.
> + }
> + }
> +
> + signal_catch_update (info->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 = gdb_signal_to_name (last.value.sig);
Here could be signal_to_name_or_int as signal number is not separately printed
here.
> +
> + 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);
Empty line before comment.
> + /* 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;
> + char *text = xstrdup ("");
> +
> + for (i = 0;
> + VEC_iterate (gdb_signal_type, c->signals_to_be_caught, i, iter);
> + i++)
> + {
> + char *x = text;
> + const char *name = signal_to_name_or_int (iter);
> +
> + text = xstrprintf (i > 0 ? "%s, %s" : "%s%s", text, name);
> + xfree (x);
> + }
> + ui_out_field_string (uiout, "what", text);
From the MI point of view ", " delimited signal names in a single field are
ugly.
> + xfree (text);
> + }
> + else
> + ui_out_field_string (uiout, "what",
> + c->catch_all ? "<any signal>" : "<standard signals>");
> + ui_out_text (uiout, "\" ");
> +}
> +
> +/* 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);
Sometimes the delimited is " " and sometimes ", ", it may be for example less
convenient for copy-pastes.
(gdb) catch signal SIGQUIT SIGCHLD SIGINT
Catchpoint 1 (signals SIGQUIT SIGCHLD SIGINT)
(gdb) info breakpoints
Num Type Disp Enb Address What
1 catchpoint keep y signals "SIGQUIT, SIGCHLD, SIGINT"
> + }
> + 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");
> +}
[...]
> +void
> +_initialize_break_catch_sig (void)
> +{
> + initialize_signal_catchpoint_ops ();
> +
> + signal_catch_info.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]...|all]\n\
For example:
Usage: catch signal [[NAME|NUMBER] [NAME|NUMBER]...|all]\n\
to see there the delimiter is " " and not ", ". Maybe not needed.
> +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);
> +}
[...]
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -318,6 +318,9 @@ static unsigned char *signal_stop;
> static unsigned char *signal_print;
> static unsigned char *signal_program;
>
> +/* Table of signals that are registered with "catch signal". */
Not descriptive enough:
/* Array of GDB_SIGNAL_LAST size with the count how many each signal is
registered by "catch signal". */
Although then also for signal_stop+signal_print+signal_program above:
/* Tables of how to react to signals; the user sets them. */
->
/* Array of GDB_SIGNAL_LAST size with boolean value whether to "handle stop",
"handle print" or "handle pass" respectively. */
> +static unsigned int *signal_catch;
> +
> /* Table of signals that the target may silently handle.
> This is automatically determined from the flags above,
> and simply cached here. */
[...]
> @@ -6251,6 +6255,18 @@ signal_pass_update (int signo, int state)
> return ret;
> }
>
> +/* Update the global 'signal_catch' from INFO and notify the
> + target. */
> +
> +void
> +signal_catch_update (unsigned int *info)
> +{
> + memcpy (signal_catch, info, GDB_SIGNAL_LAST * sizeof (unsigned int));
> + signal_cache_update (-1);
> + target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass);
I do not see why to call target_program_signals here.
> + target_program_signals ((int) GDB_SIGNAL_LAST, signal_program);
> +}
> +
> static void
> sig_print_header (void)
> {
[...]
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/catch-signal.c
[...]
> +int
> +main ()
> +{
> + signal (SIGHUP, handle);
> + signal (SIGUSR1, SIG_IGN);
> +
> + kill (getpid (), SIGHUP); /* first HUP */
Why not raise ().
> +
> + kill (getpid (), SIGHUP); /* second HUP */
> +
> + kill (getpid (), SIGHUP); /* third HUP */
> +
> + kill (getpid (), SIGHUP); /* fourth HUP */
> +}
> +
[...]
Thanks,
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-02 9:38 ` Jan Kratochvil
@ 2012-12-03 18:59 ` Tom Tromey
2012-12-03 19:37 ` Jan Kratochvil
` (2 more replies)
0 siblings, 3 replies; 27+ messages in thread
From: Tom Tromey @ 2012-12-03 18:59 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
[...]
Here's a new version that addresses all your comments.
Tom
2012-12-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.
2012-12-03 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Set Catchpoints): Document "catch signal".
(Signals): Likewise.
2012-12-03 Tom Tromey <tromey@redhat.com>
* gdb.base/catch-signal.c: New file.
* gdb.base/catch-signal.exp: New file.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3dd7b85..1043653 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -695,7 +695,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 \
@@ -869,7 +869,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 \
diff --git a/gdb/NEWS b/gdb/NEWS
index 3b09e5f..99e9a0c 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -49,6 +49,10 @@
* 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.
diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
new file mode 100644
index 0000000..661720a
--- /dev/null
+++ b/gdb/break-catch-sig.c
@@ -0,0 +1,503 @@
+/* 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"
+
+#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;
+
+\f
+
+/* 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;
+}
+
+\f
+
+/* 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 cleanup *cleanup;
+
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "what");
+
+ 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)
+ ui_out_text (uiout, " ");
+ ui_out_field_string (uiout, "signal", name);
+ }
+ do_cleanups (cleanup);
+ }
+ else if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "what", c->catch_all ? "all" : "");
+ else
+ ui_out_field_string (uiout, "what",
+ (c->catch_all ? _("<any signal>")
+ : _("<standard signals>")));
+ ui_out_text (uiout, "\" ");
+}
+
+/* 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);
+}
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 59b7bf3..acaffab 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -272,14 +272,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
@@ -4145,6 +4140,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
@@ -8303,7 +8321,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,
@@ -12807,7 +12825,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,
@@ -12826,6 +12852,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. */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 8b1bcb7..11c4b36 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9ffdb77..b0782a7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4244,6 +4244,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}
@@ -5336,6 +5361,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}
diff --git a/gdb/inferior.h b/gdb/inferior.h
index f7236e7..d715a6b 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -643,6 +643,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,
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b036682..515b9a8 100644
--- a/gdb/infrun.c
+++ b/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;
- }
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
+ stop_print_frame = 0;
+ 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;
- }
+ /* 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;
+ }
- /* 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);
+ /* 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;
+ }
- /* 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");
+ /* 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);
- /* 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:
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
- ``End of a stack dummy. Some systems (e.g. Sony news) give
- another signal besides SIGTRAP, so check here as well as
- above.''
+ /* 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");
- 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: 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:
- NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
- be necessary for call dummies on a non-executable stack on
- SPARC. */
+ ``End of a stack dummy. Some systems (e.g. Sony news) give
+ another signal besides SIGTRAP, so check here as well as
+ above.''
- 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 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.
- /* When we reach this point, we've pretty much decided
- that the reason for stopping must've been a random
- (unexpected) signal. */
+ 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:
@@ -6204,7 +6210,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
@@ -6237,6 +6244,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)
{
@@ -7222,6 +7243,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++)
@@ -7229,6 +7252,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
diff --git a/gdb/testsuite/gdb.base/catch-signal.c b/gdb/testsuite/gdb.base/catch-signal.c
new file mode 100644
index 0000000..9c68185
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-signal.c
@@ -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 */
+}
+
diff --git a/gdb/testsuite/gdb.base/catch-signal.exp b/gdb/testsuite/gdb.base/catch-signal.exp
new file mode 100644
index 0000000..6c103af
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-signal.exp
@@ -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
+}
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-03 18:59 ` Tom Tromey
@ 2012-12-03 19:37 ` Jan Kratochvil
2012-12-03 19:39 ` Tom Tromey
2013-01-03 18:16 ` RFA: [1/2] add "catch-type" to all catchpoints Tom Tromey
2013-01-03 18:23 ` RFA: [2/2] catch signal Tom Tromey
2 siblings, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-12-03 19:37 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On Mon, 03 Dec 2012 19:59:24 +0100, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
>
> [...]
> Here's a new version that addresses all your comments.
That MI output is now:
body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",what=[signal="SIGINT",signal="SIGTRAP"],times="0"}]
vs. for example existing:
body=[bkpt={number="3",type="catchpoint",disp="keep",enabled="y",what="<any syscall>",times="0"}]
but maybe it is OK this way, MI parsing has never been easy.
Thanks,
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-03 19:37 ` Jan Kratochvil
@ 2012-12-03 19:39 ` Tom Tromey
2012-12-03 20:22 ` André Pönitz
0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-12-03 19:39 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> That MI output is now:
Jan> body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",what=[signal="SIGINT",signal="SIGTRAP"],times="0"}]
Jan> vs. for example existing:
Jan> body=[bkpt={number="3",type="catchpoint",disp="keep",enabled="y",what="<any
syscall> ",times="0"}]
Jan> but maybe it is OK this way, MI parsing has never been easy.
Yes, I think it is clearly better this way: we use MI constructs for
representing lists and such.
The "type" of the "what" field is now a bit variable.
That is, it can either be a list or a string, depending on the signal
catchpoint.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-03 19:39 ` Tom Tromey
@ 2012-12-03 20:22 ` André Pönitz
2012-12-03 20:31 ` Jan Kratochvil
2012-12-07 18:41 ` Tom Tromey
0 siblings, 2 replies; 27+ messages in thread
From: André Pönitz @ 2012-12-03 20:22 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jan Kratochvil, gdb-patches
On Mon, Dec 03, 2012 at 12:39:30PM -0700, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
>
> Jan> That MI output is now:
>
> Jan> body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",what=[signal="SIGINT",signal="SIGTRAP"],times="0"}]
>
> Jan> vs. for example existing:
>
> Jan> body=[bkpt={number="3",type="catchpoint",disp="keep",enabled="y",what="<any
> syscall> ",times="0"}]
>
> Jan> but maybe it is OK this way, MI parsing has never been easy.
>
> Yes, I think it is clearly better this way: we use MI constructs for
> representing lists and such.
>
> The "type" of the "what" field is now a bit variable.
> That is, it can either be a list or a string, depending on the signal
> catchpoint.
As a more general remark from a MI consumer's perspective: It's nicer to not
change existing fields, but instead add new ones.
I understand that changing values is formally covered by the "guarantees" in
sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Development-and-Front-Ends.html,
as this is covered by "The range of values for fields with specified values
[...] may be extended" but I would like to think that the basic idea behind
writing those rules was to not break consumers of existing MI output when
extending that output. A preference of adding new fields over changing
contents (or even "type" of existing fields) should increase the chance
that frontends don't break, and can adjust to the change at their own pace.
Andre'
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-03 20:22 ` André Pönitz
@ 2012-12-03 20:31 ` Jan Kratochvil
2012-12-07 18:42 ` Tom Tromey
2012-12-07 18:41 ` Tom Tromey
1 sibling, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-12-03 20:31 UTC (permalink / raw)
To: André Pönitz; +Cc: Tom Tromey, gdb-patches
On Mon, 03 Dec 2012 21:22:33 +0100, André Pönitz wrote:
> As a more general remark from a MI consumer's perspective: It's nicer to not
> change existing fields, but instead add new ones.
>
> I understand that changing values is formally covered by the "guarantees" in
> sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Development-and-Front-Ends.html,
> as this is covered by "The range of values for fields with specified values
> [...] may be extended" but I would like to think that the basic idea behind
> writing those rules was to not break consumers of existing MI output when
> extending that output. A preference of adding new fields over changing
> contents (or even "type" of existing fields) should increase the chance
> that frontends don't break, and can adjust to the change at their own pace.
In such case maybe the original behavior was most compatible, just ", " -> " ".
Or there could be:
body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",what="<signal>",signal=["SIGINT","SIGTRAP"],times="0"}]
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-03 20:31 ` Jan Kratochvil
@ 2012-12-07 18:42 ` Tom Tromey
2012-12-07 19:28 ` Jan Kratochvil
0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-12-07 18:42 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: André Pönitz, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",what="<signal>",signal=["SIGINT","SIGTRAP"],times="0"}]
I see now that the "type" field for catchpoints is not very useful.
I think we should make that change depending on the particular type of
catchpoint that is installed. Thoughts on this?
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-07 18:42 ` Tom Tromey
@ 2012-12-07 19:28 ` Jan Kratochvil
2012-12-07 19:47 ` Tom Tromey
0 siblings, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-12-07 19:28 UTC (permalink / raw)
To: Tom Tromey; +Cc: André Pönitz, gdb-patches
On Fri, 07 Dec 2012 19:42:05 +0100, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
>
> Jan> body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",what="<signal>",signal=["SIGINT","SIGTRAP"],times="0"}]
>
> I see now that the "type" field for catchpoints is not very useful.
>
> I think we should make that change depending on the particular type of
> catchpoint that is installed. Thoughts on this?
I proposed the scheme above so that 'what' can remain still a string while it
also differentiates the various sub-kinds of the 'catchpoint' type.
Thanks,
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-07 19:28 ` Jan Kratochvil
@ 2012-12-07 19:47 ` Tom Tromey
2012-12-07 20:04 ` Jan Kratochvil
0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-12-07 19:47 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: André Pönitz, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> I proposed the scheme above so that 'what' can remain still a
Jan> string while it also differentiates the various sub-kinds of the
Jan> 'catchpoint' type.
Yeah, but why?
The "type" field is clearly intended for this.
It seems strange to overload an existing field and then add new fields.
Furthermore I don't think that the current situation was done
intentionally. It must be an oversight.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-12-07 19:47 ` Tom Tromey
@ 2012-12-07 20:04 ` Jan Kratochvil
2012-12-17 21:43 ` Tom Tromey
0 siblings, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-12-07 20:04 UTC (permalink / raw)
To: Tom Tromey; +Cc: André Pönitz, gdb-patches
On Fri, 07 Dec 2012 20:47:12 +0100, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
>
> Jan> I proposed the scheme above so that 'what' can remain still a
> Jan> string while it also differentiates the various sub-kinds of the
> Jan> 'catchpoint' type.
>
> Yeah, but why?
For backward compatibility, any change is usually rejected as valid only in
MI3.
I do not know how serious is the backward compatibility of type="catchpoint".
Regards,
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-12-07 20:04 ` Jan Kratochvil
@ 2012-12-17 21:43 ` Tom Tromey
2012-12-18 16:39 ` Jan Kratochvil
2012-12-19 19:32 ` Tom Tromey
0 siblings, 2 replies; 27+ messages in thread
From: Tom Tromey @ 2012-12-17 21:43 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: André Pönitz, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> I do not know how serious is the backward compatibility of
Jan> type="catchpoint".
Me neither.
I went through all the catchpoints and added a new "catch-type" field
that lists the type of catchpoint. I think this is a bit absurd, in the
sense that nobody would come up with this approach from scratch -- but
on the other hand it is clearly compatible.
I'll send a patch after testing, fixing up the test suite, etc.
Let me know what you think of this.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-12-17 21:43 ` Tom Tromey
@ 2012-12-18 16:39 ` Jan Kratochvil
2012-12-18 16:45 ` Tom Tromey
2012-12-19 19:32 ` Tom Tromey
1 sibling, 1 reply; 27+ messages in thread
From: Jan Kratochvil @ 2012-12-18 16:39 UTC (permalink / raw)
To: Tom Tromey; +Cc: André Pönitz, gdb-patches
On Mon, 17 Dec 2012 22:25:06 +0100, Tom Tromey wrote:
> I went through all the catchpoints and added a new "catch-type" field
> that lists the type of catchpoint.
Therefore it looks this way?
body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",catch-type="signal",what=[signal="SIGINT",signal="SIGTRAP"],times="0"}]
I believe it still may break existing MI clients according to André.
This one would be safer:
body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",catch-type="signal",what="<signal>",signal=["SIGINT","SIGTRAP"],times="0"}]
Although it is becoming very "unusual".
> Let me know what you think of this.
I find more safe the latter choice but I would prefer to leave the choice on
André with better MI real world experience.
Thanks,
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-18 16:39 ` Jan Kratochvil
@ 2012-12-18 16:45 ` Tom Tromey
2012-12-18 16:50 ` Jan Kratochvil
0 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2012-12-18 16:45 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: André Pönitz, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> Therefore it looks this way?
Jan> body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",catch-type="signal",what=[signal="SIGINT",signal="SIGTRAP"],times="0"}]
Jan> I believe it still may break existing MI clients according to André.
I also reverted how 'what' is handled, so now it is:
body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",catch-type="signal",what="SIGINT SIGTRAP",times="0"}]
Jan> Although it is becoming very "unusual".
Yeah.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread* Re: RFC: implement "catch signal"
2012-12-18 16:45 ` Tom Tromey
@ 2012-12-18 16:50 ` Jan Kratochvil
0 siblings, 0 replies; 27+ messages in thread
From: Jan Kratochvil @ 2012-12-18 16:50 UTC (permalink / raw)
To: Tom Tromey; +Cc: André Pönitz, gdb-patches
On Tue, 18 Dec 2012 17:44:54 +0100, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
> I also reverted how 'what' is handled, so now it is:
>
> body=[bkpt={number="1",type="catchpoint",disp="keep",enabled="y",catch-type="signal",what="SIGINT SIGTRAP",times="0"}]
BTW I do not see issues with this one.
(I see I repeatedly pushed MI into something which is no longer the MI style.)
Jan
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-12-17 21:43 ` Tom Tromey
2012-12-18 16:39 ` Jan Kratochvil
@ 2012-12-19 19:32 ` Tom Tromey
2012-12-19 20:11 ` Marc Khouzam
2012-12-20 8:58 ` Dodji Seketeli
1 sibling, 2 replies; 27+ messages in thread
From: Tom Tromey @ 2012-12-19 19:32 UTC (permalink / raw)
To: Jan Kratochvil
Cc: André Pönitz, gdb-patches, marc.khouzam, Dodji Seketeli
Jan> I do not know how serious is the backward compatibility of
Jan> type="catchpoint".
Tom> Me neither.
On irc, André said that at least his front end isn't handling catchpoint
at all. So I would guess that changing this, at least for him, would be
fine.
CCing Marc Khouzam, to get the Eclipse perspective, and Dodji for
nemiver.
The background is that right now all catchpoints report
type="catchpoint" in MI; but it seems better to me to make this report
the real catchpoint type, e.g., type="catch-load" or something like
that.
The alternative is something like type="catchpoint",catch-type="load".
I sometimes think we should have a special "MI discuss" list just so we
can work these things out without requiring all the MI consumer authors
to filter through the main lists. Just CCing a couple people whose
names I remember isn't very good... :)
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* RE: RFC: implement "catch signal"
2012-12-19 19:32 ` Tom Tromey
@ 2012-12-19 20:11 ` Marc Khouzam
2012-12-20 8:58 ` Dodji Seketeli
1 sibling, 0 replies; 27+ messages in thread
From: Marc Khouzam @ 2012-12-19 20:11 UTC (permalink / raw)
To: 'Tom Tromey', 'Jan Kratochvil',
'Mikhail Khodjaiants'
Cc: 'André Pönitz',
'gdb-patches@sourceware.org', 'Dodji Seketeli'
> -----Original Message-----
> From: Tom Tromey [mailto:tromey@redhat.com]
> Sent: Wednesday, December 19, 2012 2:32 PM
> To: Jan Kratochvil
> Cc: André Pönitz; gdb-patches@sourceware.org; Marc Khouzam;
> Dodji Seketeli
> Subject: Re: RFC: implement "catch signal"
>
> Jan> I do not know how serious is the backward compatibility of
> Jan> type="catchpoint".
>
> Tom> Me neither.
>
> On irc, André said that at least his front end isn't handling
> catchpoint
> at all. So I would guess that changing this, at least for
> him, would be
> fine.
>
> CCing Marc Khouzam, to get the Eclipse perspective, and Dodji for
> nemiver.
>
> The background is that right now all catchpoints report
> type="catchpoint" in MI; but it seems better to me to make this report
> the real catchpoint type, e.g., type="catch-load" or something like
> that.
>
> The alternative is something like type="catchpoint",catch-type="load".
Eclipse looks for 'type' to start with "catchpoint", so having something
like type="catchpoint-load" would be backwards-compatible in our case.
I've added Mikhail Khodjainants who has recently worked on synchronizing
Eclipse and GDB 'breakpoints' but ran into serious problems for catchpoints.
> I sometimes think we should have a special "MI discuss" list
> just so we
> can work these things out without requiring all the MI
> consumer authors
> to filter through the main lists. Just CCing a couple people whose
> names I remember isn't very good... :)
gdb-mi@source...
could be a good thing to have.
>
> Tom
>
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-12-19 19:32 ` Tom Tromey
2012-12-19 20:11 ` Marc Khouzam
@ 2012-12-20 8:58 ` Dodji Seketeli
2013-01-03 18:06 ` Tom Tromey
1 sibling, 1 reply; 27+ messages in thread
From: Dodji Seketeli @ 2012-12-20 8:58 UTC (permalink / raw)
To: Tom Tromey
Cc: Jan Kratochvil, André Pönitz, gdb-patches, marc.khouzam
Tom Tromey <tromey@redhat.com> writes:
> Jan> I do not know how serious is the backward compatibility of
> Jan> type="catchpoint".
>
> Tom> Me neither.
>
> On irc, André said that at least his front end isn't handling catchpoint
> at all. So I would guess that changing this, at least for him, would be
> fine.
>
> CCing Marc Khouzam, to get the Eclipse perspective, and Dodji for
> nemiver.
Actually, Nemiver doesn't handle catchpoint either. It's on my todo
list.
> The background is that right now all catchpoints report
> type="catchpoint" in MI; but it seems better to me to make this report
> the real catchpoint type, e.g., type="catch-load" or something like
> that.
>
> The alternative is something like type="catchpoint",catch-type="load".
I tend to prefer this alternative, but really, I don't have any strong
opinion about this. I'd say that if the information about the different
types of catchpoints is present, it's fine.
Just curious, what would be the drawback of this alternative, compared
to, say, type='catch-load'?
> I sometimes think we should have a special "MI discuss" list just so we
> can work these things out without requiring all the MI consumer authors
> to filter through the main lists. Just CCing a couple people whose
> names I remember isn't very good... :)
Hehe, yeah, i'd welcome such a list.
Thanks.
--
Dodji
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-12-20 8:58 ` Dodji Seketeli
@ 2013-01-03 18:06 ` Tom Tromey
0 siblings, 0 replies; 27+ messages in thread
From: Tom Tromey @ 2013-01-03 18:06 UTC (permalink / raw)
To: Dodji Seketeli
Cc: Jan Kratochvil, André Pönitz, gdb-patches, marc.khouzam
>>>>> "Dodji" == Dodji Seketeli <dodji@redhat.com> writes:
Tom> The alternative is something like type="catchpoint",catch-type="load".
Dodji> I tend to prefer this alternative, but really, I don't have any strong
Dodji> opinion about this. I'd say that if the information about the different
Dodji> types of catchpoints is present, it's fine.
Dodji> Just curious, what would be the drawback of this alternative, compared
Dodji> to, say, type='catch-load'?
Just that it is wordier, and it seems odd to have two "type" fields.
I went ahead and did it this way.
I'll send new patches momentarily.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: RFC: implement "catch signal"
2012-12-03 20:22 ` André Pönitz
2012-12-03 20:31 ` Jan Kratochvil
@ 2012-12-07 18:41 ` Tom Tromey
1 sibling, 0 replies; 27+ messages in thread
From: Tom Tromey @ 2012-12-07 18:41 UTC (permalink / raw)
To: André Pönitz; +Cc: Jan Kratochvil, gdb-patches
>>>>> "André" == André Pönitz <andre.poenitz@mathematik.tu-chemnitz.de> writes:
André> As a more general remark from a MI consumer's perspective: It's
André> nicer to not change existing fields, but instead add new ones.
Fair enough. I'll change this somehow.
Tom
^ permalink raw reply [flat|nested] 27+ messages in thread
* RFA: [1/2] add "catch-type" to all catchpoints
2012-12-03 18:59 ` Tom Tromey
2012-12-03 19:37 ` Jan Kratochvil
@ 2013-01-03 18:16 ` Tom Tromey
2013-01-03 18:39 ` Eli Zaretskii
2013-01-16 17:23 ` Tom Tromey
2013-01-03 18:23 ` RFA: [2/2] catch signal Tom Tromey
2 siblings, 2 replies; 27+ messages in thread
From: Tom Tromey @ 2013-01-03 18:16 UTC (permalink / raw)
To: gdb-patches
[ re-sending since something went weird ]
This patch adds the "catch-type" field to the description of all
catchpoints in gdb. This was agreed upon in the "catch signal" thread.
It needs at least a doc review.
Any comments?
Built and regtested on x86-64 Fedora 16.
Tom
2013-01-03 Tom Tromey <tromey@redhat.com>
* breakpoint.c (print_one_catch_fork, print_one_catch_vfork)
(print_one_catch_solib, print_one_catch_syscall)
(print_one_catch_exec, print_one_exception_catchpoint): Emit
"catch-type".
2013-01-03 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (GDB/MI Breakpoint Information): Document
"catch-type" field.
(GDB/MI Catchpoint Commands): Add "catch-type" to examples.
2013-01-03 Tom Tromey <tromey@redhat.com>
* gdb.mi/mi-catch-load.exp: Look for "catch-type".
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index e56d9df..81271c8 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7538,6 +7538,9 @@ print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
ptid_get_pid (c->forked_inferior_pid));
ui_out_spaces (uiout, 1);
}
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "fork");
}
/* Implement the "print_mention" breakpoint_ops method for fork
@@ -7651,6 +7654,9 @@ print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
ptid_get_pid (c->forked_inferior_pid));
ui_out_spaces (uiout, 1);
}
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "vfork");
}
/* Implement the "print_mention" breakpoint_ops method for vfork
@@ -7849,6 +7855,10 @@ print_one_catch_solib (struct breakpoint *b, struct bp_location **locs)
}
ui_out_field_string (uiout, "what", msg);
xfree (msg);
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type",
+ self->is_load ? "load" : "unload");
}
static void
@@ -8260,6 +8270,9 @@ print_one_catch_syscall (struct breakpoint *b,
else
ui_out_field_string (uiout, "what", "<any syscall>");
ui_out_text (uiout, "\" ");
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "syscall");
}
/* Implement the "print_mention" breakpoint_ops method for syscall
@@ -8497,6 +8510,9 @@ print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
ui_out_field_string (uiout, "what", c->exec_pathname);
ui_out_text (uiout, "\" ");
}
+
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "exec");
}
static void
@@ -11545,9 +11561,17 @@ print_one_exception_catchpoint (struct breakpoint *b,
if (b->loc)
*last_loc = b->loc;
if (strstr (b->addr_string, "throw") != NULL)
- ui_out_field_string (uiout, "what", "exception throw");
+ {
+ ui_out_field_string (uiout, "what", "exception throw");
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "throw");
+ }
else
- ui_out_field_string (uiout, "what", "exception catch");
+ {
+ ui_out_field_string (uiout, "what", "exception catch");
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string (uiout, "catch-type", "catch");
+ }
}
static void
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index dbd0c77..fd8e58e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -27982,6 +27982,10 @@ of a multi-location breakpoint, this will be a dotted pair, like
The type of the breakpoint. For ordinary breakpoints this will be
@samp{breakpoint}, but many values are possible.
+@item catch-type
+If the type of the breakpoint is @samp{catchpoint}, then this
+indicates the exact type of catchpoint.
+
@item disp
This is the breakpoint disposition---either @samp{del}, meaning that
the breakpoint will be deleted at the next stop, or @samp{keep},
@@ -28892,7 +28896,7 @@ The corresponding @value{GDBN} command is @samp{catch load}.
@smallexample
-catch-load -t foo.so
^done,bkpt=@{number="1",type="catchpoint",disp="del",enabled="y",
-what="load of library matching foo.so",times="0"@}
+what="load of library matching foo.so",catch-type="load",times="0"@}
(gdb)
@end smallexample
@@ -28921,7 +28925,7 @@ The corresponding @value{GDBN} command is @samp{catch unload}.
@smallexample
-catch-unload -d bar.so
^done,bkpt=@{number="2",type="catchpoint",disp="keep",enabled="n",
-what="load of library matching bar.so",times="0"@}
+what="load of library matching bar.so",catch-type="unload",times="0"@}
(gdb)
@end smallexample
diff --git a/gdb/testsuite/gdb.mi/mi-catch-load.exp b/gdb/testsuite/gdb.mi/mi-catch-load.exp
index 34494a2..7ebf225 100644
--- a/gdb/testsuite/gdb.mi/mi-catch-load.exp
+++ b/gdb/testsuite/gdb.mi/mi-catch-load.exp
@@ -49,7 +49,7 @@ mi_run_to_main
# test -catch-load
mi_gdb_test "111-gdb-set auto-solib-add on" "111\\^done" "catch-load: auto-solib-add on"
mi_gdb_test "222-catch-load -t mi-catch-load-so.so*" \
- "222\\^done,bkpt=\{number=\"2\",type=\"catchpoint\",disp=\"del\",enabled=\"y\",what=\"load of library matching mi-catch-load-so\.so\\*\",times=\"0\"\}" \
+ "222\\^done,bkpt=\{number=\"2\",type=\"catchpoint\",disp=\"del\",enabled=\"y\",what=\"load of library matching mi-catch-load-so\.so\\*\",catch-type=\"load\",times=\"0\"\}" \
"catch-load: catch load"
mi_send_resuming_command "exec-continue" "catch-load: continue"
@@ -76,7 +76,7 @@ mi_run_to_main
# test -catch-unload
mi_gdb_test "111-gdb-set auto-solib-add on" "111\\^done" "catch-unload: auto-solib-add on"
mi_gdb_test "222-catch-unload -t mi-catch-load-so.so*" \
- "222\\^done,bkpt=\{number=\"2\",type=\"catchpoint\",disp=\"del\",enabled=\"y\",what=\"unload of library matching mi-catch-load-so\.so\\*\",times=\"0\"\}" \
+ "222\\^done,bkpt=\{number=\"2\",type=\"catchpoint\",disp=\"del\",enabled=\"y\",what=\"unload of library matching mi-catch-load-so\.so\\*\",catch-type=\"unload\",times=\"0\"\}" \
"catch-unload: catch unload"
mi_send_resuming_command "exec-continue" "catch-unload: continue"
^ permalink raw reply [flat|nested] 27+ messages in thread* RFA: [2/2] catch signal
2012-12-03 18:59 ` Tom Tromey
2012-12-03 19:37 ` Jan Kratochvil
2013-01-03 18:16 ` RFA: [1/2] add "catch-type" to all catchpoints Tom Tromey
@ 2013-01-03 18:23 ` Tom Tromey
2013-01-16 17:28 ` Tom Tromey
2 siblings, 1 reply; 27+ messages in thread
From: Tom Tromey @ 2013-01-03 18:23 UTC (permalink / raw)
To: gdb-patches
This rebases the "catch signal" patch on top of the previous
"catch-type" patch. It addresses all the earlier comments.
Built and regtested on x86-64 Fedora 16.
Tom
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.
2013-01-03 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Set Catchpoints): Document "catch signal".
(Signals): Likewise.
2013-01-03 Tom Tromey <tromey@redhat.com>
* gdb.base/catch-signal.c: New file.
* gdb.base/catch-signal.exp: New file.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index b065d41..beb5bcb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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 \
diff --git a/gdb/NEWS b/gdb/NEWS
index 75a2119..5f93d07 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -60,6 +60,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.
diff --git a/gdb/break-catch-sig.c b/gdb/break-catch-sig.c
new file mode 100644
index 0000000..89783b0
--- /dev/null
+++ b/gdb/break-catch-sig.c
@@ -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;
+
+\f
+
+/* 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;
+}
+
+\f
+
+/* 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);
+}
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 81271c8..8961558 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -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
@@ -8358,7 +8376,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,
@@ -12874,7 +12892,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,
@@ -12893,6 +12919,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. */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 52864f5..df9d366 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fd8e58e..ddb4244 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4241,6 +4241,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}
@@ -5333,6 +5358,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}
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 0260e53..196d033 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -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,
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9105016..c0fbf0b 100644
--- a/gdb/infrun.c
+++ b/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;
- }
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
+ stop_print_frame = 0;
+ 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;
- }
+ /* 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;
+ }
- /* 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);
+ /* 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;
+ }
- /* 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");
+ /* 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);
- /* 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:
+ /* Following in case break condition called a
+ function. */
+ stop_print_frame = 1;
- ``End of a stack dummy. Some systems (e.g. Sony news) give
- another signal besides SIGTRAP, so check here as well as
- above.''
+ /* 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");
- 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: 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:
- NOTE: kettenis/2004-02-05: Indeed such checks don't seem to
- be necessary for call dummies on a non-executable stack on
- SPARC. */
+ ``End of a stack dummy. Some systems (e.g. Sony news) give
+ another signal besides SIGTRAP, so check here as well as
+ above.''
- 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 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.
- /* When we reach this point, we've pretty much decided
- that the reason for stopping must've been a random
- (unexpected) signal. */
+ 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
diff --git a/gdb/testsuite/gdb.base/catch-signal.c b/gdb/testsuite/gdb.base/catch-signal.c
new file mode 100644
index 0000000..9c68185
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-signal.c
@@ -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 */
+}
+
diff --git a/gdb/testsuite/gdb.base/catch-signal.exp b/gdb/testsuite/gdb.base/catch-signal.exp
new file mode 100644
index 0000000..6c103af
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-signal.exp
@@ -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
+}
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2013-01-16 17:28 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-16 19:07 RFC: implement "catch signal" Tom Tromey
2012-11-16 19:49 ` Eli Zaretskii
2012-11-17 2:22 ` Yao Qi
2012-12-02 9:38 ` Jan Kratochvil
2012-12-03 18:59 ` Tom Tromey
2012-12-03 19:37 ` Jan Kratochvil
2012-12-03 19:39 ` Tom Tromey
2012-12-03 20:22 ` André Pönitz
2012-12-03 20:31 ` Jan Kratochvil
2012-12-07 18:42 ` Tom Tromey
2012-12-07 19:28 ` Jan Kratochvil
2012-12-07 19:47 ` Tom Tromey
2012-12-07 20:04 ` Jan Kratochvil
2012-12-17 21:43 ` Tom Tromey
2012-12-18 16:39 ` Jan Kratochvil
2012-12-18 16:45 ` Tom Tromey
2012-12-18 16:50 ` Jan Kratochvil
2012-12-19 19:32 ` Tom Tromey
2012-12-19 20:11 ` Marc Khouzam
2012-12-20 8:58 ` Dodji Seketeli
2013-01-03 18:06 ` Tom Tromey
2012-12-07 18:41 ` Tom Tromey
2013-01-03 18:16 ` RFA: [1/2] add "catch-type" to all catchpoints Tom Tromey
2013-01-03 18:39 ` Eli Zaretskii
2013-01-16 17:23 ` Tom Tromey
2013-01-03 18:23 ` RFA: [2/2] catch signal Tom Tromey
2013-01-16 17:28 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox