diff options
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r-- | gdb/linux-nat.c | 208 |
1 files changed, 55 insertions, 153 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 33b13fa..b82c248 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1901,7 +1901,7 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty) /* Resume LP. */ static void -resume_lwp (struct lwp_info *lp, int step) +resume_lwp (struct lwp_info *lp, int step, enum gdb_signal signo) { if (lp->stopped) { @@ -1919,14 +1919,18 @@ resume_lwp (struct lwp_info *lp, int step) { if (debug_linux_nat) fprintf_unfiltered (gdb_stdlog, - "RC: PTRACE_CONT %s, 0, 0 (resuming sibling)\n", - target_pid_to_str (lp->ptid)); + "RC: Resuming sibling %s, %s, %s\n", + target_pid_to_str (lp->ptid), + (signo != GDB_SIGNAL_0 + ? strsignal (gdb_signal_to_host (signo)) + : "0"), + step ? "step" : "resume"); if (linux_nat_prepare_to_resume != NULL) linux_nat_prepare_to_resume (lp); linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), - step, GDB_SIGNAL_0); + step, signo); lp->stopped = 0; lp->step = step; memset (&lp->siginfo, 0, sizeof (lp->siginfo)); @@ -1949,10 +1953,27 @@ resume_lwp (struct lwp_info *lp, int step) } } +/* Resume LWP, with the last stop signal, if it is in pass state. */ + static int -resume_callback (struct lwp_info *lp, void *data) +linux_nat_resume_callback (struct lwp_info *lp, void *data) { - resume_lwp (lp, 0); + enum gdb_signal signo = GDB_SIGNAL_0; + + if (lp->stopped) + { + struct thread_info *thread; + + thread = find_thread_ptid (lp->ptid); + if (thread != NULL) + { + if (signal_pass_state (thread->suspend.stop_signal)) + signo = thread->suspend.stop_signal; + thread->suspend.stop_signal = GDB_SIGNAL_0; + } + } + + resume_lwp (lp, 0, signo); return 0; } @@ -2059,11 +2080,11 @@ linux_nat_resume (struct target_ops *ops, } /* Mark LWP as not stopped to prevent it from being continued by - resume_callback. */ + linux_nat_resume_callback. */ lp->stopped = 0; if (resume_many) - iterate_over_lwps (ptid, resume_callback, NULL); + iterate_over_lwps (ptid, linux_nat_resume_callback, NULL); /* Convert to something the lower layer understands. */ ptid = pid_to_ptid (GET_LWP (lp->ptid)); @@ -2881,110 +2902,39 @@ stop_wait_callback (struct lwp_info *lp, void *data) if (WSTOPSIG (status) != SIGSTOP) { - if (linux_nat_status_is_event (status)) - { - /* If a LWP other than the LWP that we're reporting an - event for has hit a GDB breakpoint (as opposed to - some random trap signal), then just arrange for it to - hit it again later. We don't keep the SIGTRAP status - and don't forward the SIGTRAP signal to the LWP. We - will handle the current event, eventually we will - resume all LWPs, and this one will get its breakpoint - trap again. - - If we do not do this, then we run the risk that the - user will delete or disable the breakpoint, but the - thread will have already tripped on it. */ - - /* Save the trap's siginfo in case we need it later. */ - save_siginfo (lp); - - save_sigtrap (lp); - - /* Now resume this LWP and get the SIGSTOP event. */ - errno = 0; - ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); - if (debug_linux_nat) - { - fprintf_unfiltered (gdb_stdlog, - "PTRACE_CONT %s, 0, 0 (%s)\n", - target_pid_to_str (lp->ptid), - errno ? safe_strerror (errno) : "OK"); - - fprintf_unfiltered (gdb_stdlog, - "SWC: Candidate SIGTRAP event in %s\n", - target_pid_to_str (lp->ptid)); - } - /* Hold this event/waitstatus while we check to see if - there are any more (we still want to get that SIGSTOP). */ - stop_wait_callback (lp, NULL); - - /* Hold the SIGTRAP for handling by linux_nat_wait. If - there's another event, throw it back into the - queue. */ - if (lp->status) - { - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "SWC: kill %s, %s\n", - target_pid_to_str (lp->ptid), - status_to_str ((int) status)); - kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status)); - } + /* The thread was stopped with a signal other than SIGSTOP. */ - /* Save the sigtrap event. */ - lp->status = status; - return 0; - } - else - { - /* The thread was stopped with a signal other than - SIGSTOP, and didn't accidentally trip a breakpoint. */ + /* Save the trap's siginfo in case we need it later. */ + save_siginfo (lp); - if (debug_linux_nat) - { - fprintf_unfiltered (gdb_stdlog, - "SWC: Pending event %s in %s\n", - status_to_str ((int) status), - target_pid_to_str (lp->ptid)); - } - /* Now resume this LWP and get the SIGSTOP event. */ - errno = 0; - ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0); - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "SWC: PTRACE_CONT %s, 0, 0 (%s)\n", - target_pid_to_str (lp->ptid), - errno ? safe_strerror (errno) : "OK"); - - /* Hold this event/waitstatus while we check to see if - there are any more (we still want to get that SIGSTOP). */ - stop_wait_callback (lp, NULL); - - /* If the lp->status field is still empty, use it to - hold this event. If not, then this event must be - returned to the event queue of the LWP. */ - if (lp->status) - { - if (debug_linux_nat) - { - fprintf_unfiltered (gdb_stdlog, - "SWC: kill %s, %s\n", - target_pid_to_str (lp->ptid), - status_to_str ((int) status)); - } - kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status)); - } - else - lp->status = status; - return 0; - } + save_sigtrap (lp); + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "SWC: Pending event %s in %s\n", + status_to_str ((int) status), + target_pid_to_str (lp->ptid)); + + /* Save the sigtrap event. */ + lp->status = status; + gdb_assert (!lp->stopped); + gdb_assert (lp->signalled); + lp->stopped = 1; } else { /* We caught the SIGSTOP that we intended to catch, so there's no SIGSTOP pending. */ + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "SWC: Delayed SIGSTOP caught for %s.\n", + target_pid_to_str (lp->ptid)); + lp->stopped = 1; + + /* Reset SIGNALLED only after the stop_wait_callback call + above as it does gdb_assert on SIGNALLED. */ lp->signalled = 0; } } @@ -3238,7 +3188,7 @@ stop_and_resume_callback (struct lwp_info *lp, void *data) fprintf_unfiltered (gdb_stdlog, "SARC: re-resuming LWP %ld\n", GET_LWP (lp->ptid)); - resume_lwp (lp, lp->step); + resume_lwp (lp, lp->step, GDB_SIGNAL_0); } else { @@ -3612,54 +3562,6 @@ retry: lp = NULL; } - if (lp && lp->signalled && lp->last_resume_kind != resume_stop) - { - /* A pending SIGSTOP may interfere with the normal stream of - events. In a typical case where interference is a problem, - we have a SIGSTOP signal pending for LWP A while - single-stepping it, encounter an event in LWP B, and take the - pending SIGSTOP while trying to stop LWP A. After processing - the event in LWP B, LWP A is continued, and we'll never see - the SIGTRAP associated with the last time we were - single-stepping LWP A. */ - - /* Resume the thread. It should halt immediately returning the - pending SIGSTOP. */ - registers_changed (); - if (linux_nat_prepare_to_resume != NULL) - linux_nat_prepare_to_resume (lp); - linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), - lp->step, GDB_SIGNAL_0); - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLW: %s %s, 0, 0 (expect SIGSTOP)\n", - lp->step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT", - target_pid_to_str (lp->ptid)); - lp->stopped = 0; - gdb_assert (lp->resumed); - - /* Catch the pending SIGSTOP. */ - status = lp->status; - lp->status = 0; - - stop_wait_callback (lp, NULL); - - /* If the lp->status field isn't empty, we caught another signal - while flushing the SIGSTOP. Return it back to the event - queue of the LWP, as we already have an event to handle. */ - if (lp->status) - { - if (debug_linux_nat) - fprintf_unfiltered (gdb_stdlog, - "LLW: kill %s, %s\n", - target_pid_to_str (lp->ptid), - status_to_str (lp->status)); - kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status)); - } - - lp->status = status; - } - if (!target_can_async_p ()) { /* Causes SIGINT to be passed on to the attached process. */ |