From 2b009048566bc0f8eed7ac4c889da40b9470cb0f Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Fri, 29 Jan 2010 15:40:22 +0000 Subject: [PATCH] * infrun.c (prepare_to_proceed): Handle other signals which might match a breakpoint. (handle_inferior_event): Move the check for unusual breakpoint signals earlier. gdbserver/ * linux-low.c (get_stop_pc): Check for SIGTRAP. (linux_wait_for_event_1): Handle SIGILL and SIGSEGV as possible breakpoints. --- gdb/ChangeLog | 7 ++++++ gdb/gdbserver/ChangeLog | 6 +++++ gdb/gdbserver/linux-low.c | 21 ++++++++++++---- gdb/infrun.c | 50 +++++++++++++++++++++++---------------- 4 files changed, 58 insertions(+), 26 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d7b426d7f5..45d1e61974 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2010-01-29 Daniel Jacobowitz + + * infrun.c (prepare_to_proceed): Handle other signals which might + match a breakpoint. + (handle_inferior_event): Move the check for unusual breakpoint + signals earlier. + 2010-01-29 Paul Hilfinger amd64 - function returning record with field straddling 2 registers. diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index e1ad397d5b..fc6b6e222e 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,9 @@ +2010-01-29 Daniel Jacobowitz + + * linux-low.c (get_stop_pc): Check for SIGTRAP. + (linux_wait_for_event_1): Handle SIGILL and SIGSEGV as possible + breakpoints. + 2010-01-21 Pedro Alves * linux-ppc-low.c (ppc_arch_setup): Adjust to regcache changes. diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 8ec73d2045..fb4aa5c249 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -455,7 +455,8 @@ get_stop_pc (void) struct regcache *regcache = get_thread_regcache (current_inferior, 1); CORE_ADDR stop_pc = (*the_low_target.get_pc) (regcache); - if (! get_thread_lwp (current_inferior)->stepping) + if (! get_thread_lwp (current_inferior)->stepping + && WSTOPSIG (get_thread_lwp (current_inferior)->last_status) == SIGTRAP) stop_pc -= the_low_target.decr_pc_after_break; if (debug_threads) @@ -1244,18 +1245,28 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) continue; } - /* If this event was not handled above, and is not a SIGTRAP, report - it. */ - if (!WIFSTOPPED (*wstat) || WSTOPSIG (*wstat) != SIGTRAP) + /* If this event was not handled above, and is not a SIGTRAP, + report it. SIGILL and SIGSEGV are also treated as traps in case + a breakpoint is inserted at the current PC. */ + if (!WIFSTOPPED (*wstat) + || (WSTOPSIG (*wstat) != SIGTRAP && WSTOPSIG (*wstat) != SIGILL + && WSTOPSIG (*wstat) != SIGSEGV)) return lwpid_of (event_child); /* If this target does not support breakpoints, we simply report the - SIGTRAP; it's of no concern to us. */ + signal; it's of no concern to us. */ if (the_low_target.get_pc == NULL) return lwpid_of (event_child); stop_pc = get_stop_pc (); + /* Only handle SIGILL or SIGSEGV if we've hit a recognized + breakpoint. */ + if (WSTOPSIG (*wstat) != SIGTRAP + && (event_child->stepping + || ! (*the_low_target.breakpoint_at) (stop_pc))) + return lwpid_of (event_child); + /* bp_reinsert will only be set if we were single-stepping. Notice that we will resume the process after hitting a gdbserver breakpoint; single-stepping to/over one diff --git a/gdb/infrun.c b/gdb/infrun.c index 06f3ea09dd..8307986900 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1640,7 +1640,10 @@ prepare_to_proceed (int step) /* Make sure we were stopped at a breakpoint. */ if (wait_status.kind != TARGET_WAITKIND_STOPPED - || wait_status.value.sig != TARGET_SIGNAL_TRAP) + || (wait_status.value.sig != TARGET_SIGNAL_TRAP + && wait_status.value.sig != TARGET_SIGNAL_ILL + && wait_status.value.sig != TARGET_SIGNAL_SEGV + && wait_status.value.sig != TARGET_SIGNAL_EMT)) { return 0; } @@ -2661,6 +2664,7 @@ handle_inferior_event (struct execution_control_state *ecs) { struct frame_info *frame; struct gdbarch *gdbarch; + struct regcache *regcache; int sw_single_step_trap_p = 0; int stopped_by_watchpoint; int stepped_after_stopped_by_watchpoint = 0; @@ -2721,6 +2725,30 @@ handle_inferior_event (struct execution_control_state *ecs) breakpoint_retire_moribund (); + /* First, distinguish signals caused by the debugger from signals + that have to do with the program's own actions. Note that + breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending + on the operating system version. Here we detect when a SIGILL or + SIGEMT is really a breakpoint and change it to SIGTRAP. We do + something similar for SIGSEGV, since a SIGSEGV will be generated + when we're trying to execute a breakpoint instruction on a + non-executable stack. This happens for call dummy breakpoints + for architectures like SPARC that place call dummies on the + stack. */ + regcache = get_thread_regcache (ecs->ptid); + if (ecs->ws.kind == TARGET_WAITKIND_STOPPED + && (ecs->ws.value.sig == TARGET_SIGNAL_ILL + || ecs->ws.value.sig == TARGET_SIGNAL_SEGV + || ecs->ws.value.sig == TARGET_SIGNAL_EMT) + && breakpoint_inserted_here_p (get_regcache_aspace (regcache), + regcache_read_pc (regcache))) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: Treating signal as SIGTRAP\n"); + ecs->ws.value.sig = TARGET_SIGNAL_TRAP; + } + /* Mark the non-executing threads accordingly. In all-stop, all threads of all processes are stopped when we get any event reported. In non-stop mode, only the event thread stops. If @@ -3500,27 +3528,7 @@ targets should add new threads to the thread list themselves in non-stop mode.") 3) set ecs->random_signal to 1, and the decision between 1 and 2 will be made according to the signal handling tables. */ - /* First, distinguish signals caused by the debugger from signals - that have to do with the program's own actions. Note that - breakpoint insns may cause SIGTRAP or SIGILL or SIGEMT, depending - on the operating system version. Here we detect when a SIGILL or - SIGEMT is really a breakpoint and change it to SIGTRAP. We do - something similar for SIGSEGV, since a SIGSEGV will be generated - when we're trying to execute a breakpoint instruction on a - non-executable stack. This happens for call dummy breakpoints - for architectures like SPARC that place call dummies on the - stack. - - If we're doing a displaced step past a breakpoint, then the - breakpoint is always inserted at the original instruction; - non-standard signals can't be explained by the breakpoint. */ if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP - || (! ecs->event_thread->trap_expected - && breakpoint_inserted_here_p (get_regcache_aspace (get_current_regcache ()), - stop_pc) - && (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL - || ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV - || ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT)) || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP || stop_soon == STOP_QUIETLY_REMOTE) {