From: Jan Kratochvil <jan.kratochvil@redhat.com>
To: Tom Tromey <tromey@redhat.com>
Cc: gdb-patches@sourceware.org
Subject: Re: RFC: implement "catch signal"
Date: Sun, 02 Dec 2012 09:38:00 -0000 [thread overview]
Message-ID: <20121202093807.GA21883@host2.jankratochvil.net> (raw)
In-Reply-To: <874nkpv03j.fsf@fleche.redhat.com>
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
next prev parent reply other threads:[~2012-12-02 9:38 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-16 19:07 Tom Tromey
2012-11-16 19:49 ` Eli Zaretskii
2012-11-17 2:22 ` Yao Qi
2012-12-02 9:38 ` Jan Kratochvil [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20121202093807.GA21883@host2.jankratochvil.net \
--to=jan.kratochvil@redhat.com \
--cc=gdb-patches@sourceware.org \
--cc=tromey@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox