From 3b0f7442800817f8a19b8eebd3b897a75328af14 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 16 Jan 2013 17:31:35 +0000 Subject: 2013-01-03 Pedro Alves Tom Tromey 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) : New field. (bpstat_explains_signal): Remove macro, declare as function. (base_breakpoint_ops, init_catchpoint): Declare. * break-catch-sig.c: New file. * inferior.h (signal_catch_update): Declare. * infrun.c (signal_catch): New global. (handle_syscall_event): Update for change to bpstat_explains_signal. (handle_inferior_event): Likewise. Always handle random signals via bpstats. (signal_cache_update): Check signal_catch. (signal_catch_update): New function. (_initialize_infrun): Initialize signal_catch. * Makefile.in (SFILES): Add break-catch-sig.c. (COMMON_OBS): Add break-catch-sig.o. gdb/doc * gdb.texinfo (Set Catchpoints): Document "catch signal". (Signals): Likewise. gdb/testsuite * gdb.base/catch-signal.c: New file. * gdb.base/catch-signal.exp: New file. --- gdb/infrun.c | 256 ++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 140 insertions(+), 116 deletions(-) (limited to 'gdb/infrun.c') diff --git a/gdb/infrun.c b/gdb/infrun.c index 910501603da..c0fbf0b6dce 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 -- cgit v1.2.1