2011-09-09 Pedro Alves gdb/ * breakpoint.c (base_breakpoint_ops, init_catchpoint) (base_breakpoint_ops): Make extern. * infrun.c (handle_inferior_event): Always run all signals through bpstat_stop_status. If a random signal is explained by a breakpoint, clear stop_signal to TARGET_SIGNAL_0, not TARGET_SIGNAL_TRAP. * break-catch-sig.c: New file. * Makefile.in (COMMON_OBS): Add break-catch-sig.o. * breakpoint.h (base_breakpoint_ops, init_catchpoint): Declare. --- gdb/Makefile.in | 2 gdb/break-catch-sig.c | 541 ++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/breakpoint.c | 6 gdb/breakpoint.h | 6 gdb/infrun.c | 13 - 5 files changed, 553 insertions(+), 15 deletions(-) Index: src/gdb/breakpoint.c =================================================================== --- src.orig/gdb/breakpoint.c 2011-09-09 16:46:34.529763360 +0100 +++ src/gdb/breakpoint.c 2011-09-09 16:49:42.569763393 +0100 @@ -237,7 +237,7 @@ static int is_masked_watchpoint (const s /* 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 @@ -6678,7 +6678,7 @@ syscall_catchpoint_p (struct breakpoint 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, @@ -10861,7 +10861,7 @@ base_breakpoint_print_recreate (struct b internal_error_pure_virtual_called (); } -static struct breakpoint_ops base_breakpoint_ops = +struct breakpoint_ops base_breakpoint_ops = { base_breakpoint_dtor, base_breakpoint_allocate_location, Index: src/gdb/infrun.c =================================================================== --- src.orig/gdb/infrun.c 2011-09-09 16:46:34.539763360 +0100 +++ src/gdb/infrun.c 2011-09-09 16:49:42.569763393 +0100 @@ -4031,9 +4031,7 @@ handle_inferior_event (struct execution_ 3) set ecs->random_signal to 1, and the decision between 1 and 2 will be made according to the signal handling tables. */ - if (ecs->event_thread->suspend.stop_signal == TARGET_SIGNAL_TRAP - || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP - || stop_soon == STOP_QUIETLY_REMOTE) + if (1) { if (ecs->event_thread->suspend.stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap) @@ -4144,17 +4142,10 @@ handle_inferior_event (struct execution_ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat); if (!ecs->random_signal) - ecs->event_thread->suspend.stop_signal = TARGET_SIGNAL_TRAP; + ecs->event_thread->suspend.stop_signal = TARGET_SIGNAL_0; } } - /* When we reach this point, we've pretty much decided - that the reason for stopping must've been a random - (unexpected) signal. */ - - else - ecs->random_signal = 1; - process_event_stop_test: /* Re-fetch current thread's frame in case we did a Index: src/gdb/break-catch-sig.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/break-catch-sig.c 2011-09-09 16:49:42.569763393 +0100 @@ -0,0 +1,541 @@ +/* Everything about signal catchpoints, for GDB. + + Copyright (C) 2011 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 . */ + +#include "defs.h" +#include "arch-utils.h" +#include +#include "breakpoint.h" +#include "gdbcmd.h" +#include "inferior.h" +#include "annotate.h" +#include "valprint.h" +#include "cli/cli-utils.h" + +/* 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(int) *signals_to_be_caught; +}; + +/* The breakpoint_ops structure to be used in signal catchpoints. */ + +static struct breakpoint_ops signal_catchpoint_ops; + +struct signal_catch_info +{ + /* We keep a count of the number of times the user has requested a + particular signal to be tracked, and pass this information to the + target. This lets capable targets implement filtering + directly. */ + + /* Number of times that "any" signal is requested. */ + int any_signal_count; + + /* Count of each signal. */ + VEC(int) *signals_counts; + + /* This counts all signal catch requests, so we can readily + determine if any catching is necessary. */ + int total_signals_count; +}; + +static struct signal_catch_info signal_catch_info; + +/* 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 (int, 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; + + ++info->total_signals_count; + if (!c->signals_to_be_caught) + ++info->any_signal_count; + else + { + int i, iter; + + for (i = 0; + VEC_iterate (int, c->signals_to_be_caught, i, iter); + i++) + { + int elem; + + if (iter >= VEC_length (int, info->signals_counts)) + { + int old_size = VEC_length (int, info->signals_counts); + uintptr_t vec_addr_offset = old_size * ((uintptr_t) sizeof (int)); + uintptr_t vec_addr; + VEC_safe_grow (int, info->signals_counts, iter + 1); + vec_addr = (uintptr_t) VEC_address (int, info->signals_counts) + + vec_addr_offset; + memset ((void *) vec_addr, 0, + (iter + 1 - old_size) * sizeof (int)); + } + elem = VEC_index (int, info->signals_counts, iter); + VEC_replace (int, info->signals_counts, iter, ++elem); + } + } + + /* ???: How does this interact with "handle" ? */ + +#if 0 + target_set_signal_catchpoint (PIDGET (inferior_ptid), + inf->total_signals_count != 0, + inf->any_signal_count, + VEC_length (int, inf->signals_counts), + VEC_address (int, inf->signals_counts)); +#endif + 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; + + --info->total_signals_count; + if (!c->signals_to_be_caught) + --info->any_signal_count; + else + { + int i, iter; + + for (i = 0; + VEC_iterate (int, c->signals_to_be_caught, i, iter); + i++) + { + int elem; + if (iter >= VEC_length (int, info->signals_counts)) + /* Shouldn't happen. */ + continue; + elem = VEC_index (int, info->signals_counts, iter); + VEC_replace (int, info->signals_counts, iter, --elem); + } + } + + /* ???: How does this interact with "handle" ? */ + + return 0; + +#if 0 + return target_set_signal_catchpoint (PIDGET (inferior_ptid), + inf->total_signals_count != 0, + inf->any_signal_count, + VEC_length (int, inf->signals_counts), + VEC_address (int, inf->signals_counts)); +#endif +} + +/* 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, + struct target_waitstatus *ws) +{ + const struct signal_catchpoint *c = (void *) bl->owner; + int signal_number; + + if (ws->kind != TARGET_WAITKIND_STOPPED) + return 0; + + /* FIXME: host vs target mixup. */ + 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, iter; + + for (i = 0; + VEC_iterate (int, c->signals_to_be_caught, i, iter); + i++) + if (signal_number == iter) + break; + /* Not the same. */ + if (!iter) + return 0; + } + + return 1; +} + +struct signal +{ + /* The signal number. */ + int number; + + /* The signal name. */ + const char *name; +}; + +void +get_signal_by_number (int signal_number, + struct signal *s) +{ + s->number = signal_number; + s->name = NULL; +} + +/* 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; + struct signal s; + struct cleanup *old_chain; + char *signal_id; + + get_last_target_status (&ptid, &last); + + get_signal_by_number (last.value.sig, &s); + + annotate_catchpoint (b->number); + + if (s.name == NULL) + signal_id = xstrprintf ("%d", last.value.sig); + else + signal_id = xstrprintf ("'%s'", s.name); + + old_chain = make_cleanup (xfree, signal_id); + printf_filtered (_("\nCatchpoint %d (signal %s), "), b->number, signal_id); + + do_cleanups (old_chain); + + 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 (int, 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, iter; + char *text = xstrprintf ("%s", ""); + + for (i = 0; + VEC_iterate (int, c->signals_to_be_caught, i, iter); + i++) + { + char *x = text; + struct signal s; + + get_signal_by_number (iter, &s); + + if (s.name != NULL) + text = xstrprintf ("%s%s, ", text, s.name); + else + text = xstrprintf ("%s%d, ", text, iter); + + /* We have to xfree the last 'text' (now stored at 'x') + because xstrprintf dinamically allocates new space for it + on every call. */ + xfree (x); + } + /* Remove the last comma. */ + text[strlen (text) - 2] = '\0'; + ui_out_field_string (uiout, "what", text); + } + else + ui_out_field_string (uiout, "what", ""); + 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, iter; + + if (VEC_length (int, 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 (int, c->signals_to_be_caught, i, iter); + i++) + { + struct signal s; + + get_signal_by_number (iter, &s); + + if (s.name) + printf_filtered (" '%s' [%d]", s.name, s.number); + else + printf_filtered (" %d", s.number); + } + printf_filtered (")"); + } + else + printf_filtered (_("Catchpoint %d (any signal)"), + 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, iter; + + for (i = 0; + VEC_iterate (int, c->signals_to_be_caught, i, iter); + i++) + { + struct signal s; + + get_signal_by_number (iter, &s); + if (s.name) + fprintf_unfiltered (fp, " %s", s.name); + else + fprintf_unfiltered (fp, " %d", s.number); + } + } +} + +static void +create_signal_catchpoint (int tempflag, VEC(int) *filter) +{ + 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; + + install_breakpoint (0, &c->base); +} + + +/* Splits the argument using space as delimiter. Returns an xmalloc'd + filter list, or NULL if no filtering is required. */ +static VEC(int) * +catch_signal_split_args (char *arg) +{ + VEC(int) *result = NULL; + struct cleanup *cleanup = make_cleanup (VEC_cleanup (int), &result); + + while (*arg != '\0') + { + int i, signal_number; + char *endptr; + char cur_name[128]; + struct signal s; + + /* Skip whitespace. */ + while (isspace (*arg)) + arg++; + + for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i) + cur_name[i] = arg[i]; + cur_name[i] = '\0'; + arg += i; + + /* Check if the user provided a signal name or a number. */ + signal_number = (int) strtol (cur_name, &endptr, 0); + if (*endptr == '\0') + get_signal_by_number (signal_number, &s); + else + { + /* We have a name. Let's check if it's valid and convert it + to a number. */ +#if 0 + get_signal_by_name (cur_name, &s); + if (s.number == UNKNOWN_SIGNAL) + /* Here we have to issue an error instead of a warning, + because GDB cannot do anything useful if there's no + signal number to be caught. */ +#endif + error (_("Unknown signal name '%s'."), cur_name); + } + + /* Ok, it's valid. */ + VEC_safe_push (int, result, s.number); + } + + discard_cleanups (cleanup); + return result; +} + +/* Complete signal names. Used by "catch signal". */ +static char ** +catch_signal_completer (struct cmd_list_element *cmd, + char *text, char *word) +{ +#if 0 + const char **list = get_signal_names (); +#else + const char **list = NULL; +#endif + + return (list == NULL) ? NULL : complete_on_enum (list, text, word); +} + +/* Implement the "catch signal" command. */ + +static void +catch_signal_command (char *arg, int from_tty, + struct cmd_list_element *command) +{ + int tempflag; + VEC(int) *filter; + struct signal s; + struct gdbarch *gdbarch = get_current_arch (); + +#if 0 + /* Checking if the feature if supported. */ + if (gdbarch_get_signal_number_p (gdbarch) == 0) + error (_("The feature 'catch signal' is not supported on \ +this architeture yet.")); +#endif + + tempflag = get_cmd_context (command) == CATCH_TEMPORARY; + + arg = skip_spaces (arg); + + /* We need to do this first "dummy" translation in order to get the + signal XML file loaded or, most important, to display a warning + to the user if there's no XML file for his/her architecture. */ + get_signal_by_number (0, &s); + + /* The allowed syntax is: + catch signal + catch signal [ ... ] + + Let's check if there's a signal name. */ + + if (arg != NULL) + filter = catch_signal_split_args (arg); + else + filter = NULL; + + create_signal_catchpoint (tempflag, filter); +} + +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; +} + +void +_initialize_break_catch_sig (void) +{ + initialize_signal_catchpoint_ops (); + + add_catch_command ("signal", _("\ +Catch signals by their names and/or numbers.\n\ +Arguments say which signals to catch. If no arguments\n\ +are given, every signal will be caught.\n\ +Arguments, if given, should be one or more signal names\n\ +(if your system supports that), or signal numbers."), + catch_signal_command, + catch_signal_completer, + CATCH_PERMANENT, + CATCH_TEMPORARY); +} Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2011-09-09 16:41:07.479763303 +0100 +++ src/gdb/Makefile.in 2011-09-09 16:49:42.569763393 +0100 @@ -855,7 +855,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ addrmap.o \ auxv.o \ bfd-target.o \ - blockframe.o breakpoint.o findvar.o regcache.o \ + blockframe.o break-catch-sig.o breakpoint.o findvar.o regcache.o \ charset.o continuations.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 \ Index: src/gdb/breakpoint.h =================================================================== --- src.orig/gdb/breakpoint.h 2011-09-09 16:41:08.819763303 +0100 +++ src/gdb/breakpoint.h 2011-09-09 16:49:42.579763393 +0100 @@ -1063,6 +1063,7 @@ extern void awatch_command_wrapper (char 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 void initialize_breakpoint_ops (void); @@ -1095,6 +1096,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