|
|
01917d |
From 6681535d2cecea1f67255c140f11b217518a2f4e Mon Sep 17 00:00:00 2001
|
|
|
01917d |
From: Pedro Alves <palves@redhat.com>
|
|
|
01917d |
Date: Wed, 17 Jun 2015 20:41:05 +0100
|
|
|
01917d |
Subject: [PATCH] Fix BZ1184724 - gdb output a internal-error: Assertion
|
|
|
01917d |
`num_lwps (GET_PID (inferior_ptid)) == 1'
|
|
|
01917d |
|
|
|
01917d |
The real issue with this bug is in the ptrace error:
|
|
|
01917d |
|
|
|
01917d |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
01917d |
(gdb) c
|
|
|
01917d |
Continuing.
|
|
|
01917d |
netcfStateCleanup () at interface/interface_backend_netcf.c:116
|
|
|
01917d |
116 }
|
|
|
01917d |
ptrace: No such process.
|
|
|
01917d |
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
01917d |
(gdb) quit
|
|
|
01917d |
Inferior 1 [process 11205] will be detached.
|
|
|
01917d |
Quit anyway? (y or n) y
|
|
|
01917d |
[Thread 0x7fefdf322880 (LWP 11205) exited]
|
|
|
01917d |
|
|
|
01917d |
../../gdb/linux-nat.c:1869: internal-error: linux_nat_detach: Assertion `num_lwps (GET_PID (inferior_ptid)) == 1' failed.
|
|
|
01917d |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
01917d |
|
|
|
01917d |
The assertion is just a consequence.
|
|
|
01917d |
|
|
|
01917d |
So the main fix is to backport the GDB [1] bits of upstream 23f238d3
|
|
|
01917d |
(Fix race exposed by gdb.threads/killed.exp). That makes
|
|
|
01917d |
linux_resume_one_lwp detect when the LWP being resumed disappears.
|
|
|
01917d |
However, we need to backport also part of 8a99810d (linux-nat.c: clean
|
|
|
01917d |
up pending status checking and resuming LWPs), which is what
|
|
|
01917d |
introduced the centralized linux_resume_one_lwp in the first place,
|
|
|
01917d |
and also one bit from 8817a6f2 (PR gdb/15713 - errors from
|
|
|
01917d |
i386_linux_resume lead to lock-up), which makes linux_nat_resume not
|
|
|
01917d |
clear the leader LWP's lwp->stopped flag too early, otherwise we'd hit
|
|
|
01917d |
the new assertion in check_ptrace_stopped_lwp_gone.
|
|
|
01917d |
|
|
|
01917d |
The test is new (not a backport), and without the fix triggers the
|
|
|
01917d |
"detach" assertion shown above.
|
|
|
01917d |
|
|
|
01917d |
[1] - The equivalent GDBserver bits are harder to backport, as they
|
|
|
01917d |
rely on GDB exceptions, which GDBserver 7.6.1 doesn't support yet.
|
|
|
01917d |
Fortunately, GDBserver already handles ESRCH from within its
|
|
|
01917d |
linux_resume_one_lwp, so doesn't trigger this particular bug and
|
|
|
01917d |
passes the test.
|
|
|
01917d |
|
|
|
01917d |
gdb/ChangeLog:
|
|
|
01917d |
2015-06-17 Pedro Alves <palves@redhat.com>
|
|
|
01917d |
|
|
|
01917d |
* common/linux-procfs.c (linux_proc_pid_is_trace_stopped): New
|
|
|
01917d |
function.
|
|
|
01917d |
* common/linux-procfs.h (linux_proc_pid_is_trace_stopped): New
|
|
|
01917d |
declaration.
|
|
|
01917d |
* linux-nat.c (linux_resume_one_lwp_throw, check_ptrace_stopped_lwp_gone)
|
|
|
01917d |
(linux_resume_one_lwp): New functions.
|
|
|
01917d |
(resume_lwp): Use linux_resume_one_lwp.
|
|
|
01917d |
(linux_nat_resume_callback): Skip if LWP is the same as the passed
|
|
|
01917d |
in data pointer.
|
|
|
01917d |
(linux_nat_resume): Don't clear the selected LWP's stopped flag
|
|
|
01917d |
before resuming the sibling LWPs. Instead pass LWP to
|
|
|
01917d |
linux_nat_resume_callback. Use linux_resume_one_lwp.
|
|
|
01917d |
(linux_handle_extended_wait, linux_nat_filter_event)
|
|
|
01917d |
(linux_nat_wait_1): Use linux_resume_one_lwp.
|
|
|
01917d |
(resume_stopped_resumed_lwps): Try register reads in TRY/CATCH and
|
|
|
01917d |
swallows errors if the LWP is gone. Use
|
|
|
01917d |
linux_resume_one_lwp_throw instead of linux_resume_one_lwp.
|
|
|
01917d |
|
|
|
01917d |
gdb/testsuite/ChangeLog:
|
|
|
01917d |
2015-06-17 Pedro Alves <palves@redhat.com>
|
|
|
01917d |
|
|
|
01917d |
* gdb.threads/thread-kills-process.c: New file.
|
|
|
01917d |
* gdb.threads/thread-kills-process.exp: New file.
|
|
|
01917d |
---
|
|
|
01917d |
gdb/ChangeLog | 13 ++
|
|
|
01917d |
gdb/common/linux-procfs.c | 6 +
|
|
|
01917d |
gdb/common/linux-procfs.h | 2 +
|
|
|
01917d |
gdb/linux-nat.c | 200 +++++++++++++--------
|
|
|
01917d |
gdb/testsuite/gdb.threads/thread-kills-process.c | 62 +++++++
|
|
|
01917d |
gdb/testsuite/gdb.threads/thread-kills-process.exp | 70 ++++++++
|
|
|
01917d |
6 files changed, 277 insertions(+), 76 deletions(-)
|
|
|
01917d |
create mode 100644 gdb/testsuite/gdb.threads/thread-kills-process.c
|
|
|
01917d |
create mode 100644 gdb/testsuite/gdb.threads/thread-kills-process.exp
|
|
|
01917d |
|
|
|
01917d |
Index: gdb-7.6.1/gdb/common/linux-procfs.c
|
|
|
01917d |
===================================================================
|
|
|
01917d |
--- gdb-7.6.1.orig/gdb/common/linux-procfs.c
|
|
|
01917d |
+++ gdb-7.6.1/gdb/common/linux-procfs.c
|
|
|
01917d |
@@ -111,6 +111,12 @@ linux_proc_pid_is_stopped (pid_t pid)
|
|
|
01917d |
return linux_proc_pid_has_state (pid, "T (stopped)");
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
+int
|
|
|
01917d |
+linux_proc_pid_is_trace_stopped (pid_t pid)
|
|
|
01917d |
+{
|
|
|
01917d |
+ return linux_proc_pid_has_state (pid, "T (tracing stop)");
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
/* See linux-procfs.h declaration. */
|
|
|
01917d |
|
|
|
01917d |
int
|
|
|
01917d |
Index: gdb-7.6.1/gdb/common/linux-procfs.h
|
|
|
01917d |
===================================================================
|
|
|
01917d |
--- gdb-7.6.1.orig/gdb/common/linux-procfs.h
|
|
|
01917d |
+++ gdb-7.6.1/gdb/common/linux-procfs.h
|
|
|
01917d |
@@ -36,6 +36,8 @@ extern pid_t linux_proc_get_tracerpid (p
|
|
|
01917d |
|
|
|
01917d |
extern int linux_proc_pid_is_stopped (pid_t pid);
|
|
|
01917d |
|
|
|
01917d |
+extern int linux_proc_pid_is_trace_stopped (pid_t pid);
|
|
|
01917d |
+
|
|
|
01917d |
/* Return non-zero if PID is a zombie. */
|
|
|
01917d |
|
|
|
01917d |
extern int linux_proc_pid_is_zombie (pid_t pid);
|
|
|
01917d |
Index: gdb-7.6.1/gdb/linux-nat.c
|
|
|
01917d |
===================================================================
|
|
|
01917d |
--- gdb-7.6.1.orig/gdb/linux-nat.c
|
|
|
01917d |
+++ gdb-7.6.1/gdb/linux-nat.c
|
|
|
01917d |
@@ -1928,6 +1928,85 @@ linux_nat_detach (struct target_ops *ops
|
|
|
01917d |
linux_ops->to_detach (ops, args, from_tty);
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
+/* Resume execution of the inferior process. If STEP is nonzero,
|
|
|
01917d |
+ single-step it. If SIGNAL is nonzero, give it that signal. */
|
|
|
01917d |
+
|
|
|
01917d |
+static void
|
|
|
01917d |
+linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
|
|
|
01917d |
+ enum gdb_signal signo)
|
|
|
01917d |
+{
|
|
|
01917d |
+ ptid_t ptid;
|
|
|
01917d |
+
|
|
|
01917d |
+ lp->step = step;
|
|
|
01917d |
+
|
|
|
01917d |
+ if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
+ linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
+
|
|
|
01917d |
+ ptid = pid_to_ptid (GET_LWP (lp->ptid));
|
|
|
01917d |
+ linux_ops->to_resume (linux_ops, ptid, step, signo);
|
|
|
01917d |
+
|
|
|
01917d |
+ /* Successfully resumed. Clear state that no longer makes sense,
|
|
|
01917d |
+ and mark the LWP as running. Must not do this before resuming
|
|
|
01917d |
+ otherwise if that fails other code will be confused. E.g., we'd
|
|
|
01917d |
+ later try to stop the LWP and hang forever waiting for a stop
|
|
|
01917d |
+ status. Note that we must not throw after this is cleared,
|
|
|
01917d |
+ otherwise handle_zombie_lwp_error would get confused. */
|
|
|
01917d |
+ lp->stopped = 0;
|
|
|
01917d |
+ lp->stopped_by_watchpoint = 0;
|
|
|
01917d |
+ registers_changed_ptid (lp->ptid);
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
+/* Called when we try to resume a stopped LWP and that errors out. If
|
|
|
01917d |
+ the LWP is no longer in ptrace-stopped state (meaning it's zombie,
|
|
|
01917d |
+ or about to become), discard the error, clear any pending status
|
|
|
01917d |
+ the LWP may have, and return true (we'll collect the exit status
|
|
|
01917d |
+ soon enough). Otherwise, return false. */
|
|
|
01917d |
+
|
|
|
01917d |
+static int
|
|
|
01917d |
+check_ptrace_stopped_lwp_gone (struct lwp_info *lp)
|
|
|
01917d |
+{
|
|
|
01917d |
+ /* If we get an error after resuming the LWP successfully, we'd
|
|
|
01917d |
+ confuse !T state for the LWP being gone. */
|
|
|
01917d |
+ gdb_assert (lp->stopped);
|
|
|
01917d |
+
|
|
|
01917d |
+ /* We can't just check whether the LWP is in 'Z (Zombie)' state,
|
|
|
01917d |
+ because even if ptrace failed with ESRCH, the tracee may be "not
|
|
|
01917d |
+ yet fully dead", but already refusing ptrace requests. In that
|
|
|
01917d |
+ case the tracee has 'R (Running)' state for a little bit
|
|
|
01917d |
+ (observed in Linux 3.18). See also the note on ESRCH in the
|
|
|
01917d |
+ ptrace(2) man page. Instead, check whether the LWP has any state
|
|
|
01917d |
+ other than ptrace-stopped. */
|
|
|
01917d |
+
|
|
|
01917d |
+ /* Don't assume anything if /proc/PID/status can't be read. */
|
|
|
01917d |
+ if (linux_proc_pid_is_trace_stopped (ptid_get_lwp (lp->ptid)) == 0)
|
|
|
01917d |
+ {
|
|
|
01917d |
+ lp->status = 0;
|
|
|
01917d |
+ lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
|
|
|
01917d |
+ lp->stopped_by_watchpoint = 0;
|
|
|
01917d |
+ return 1;
|
|
|
01917d |
+ }
|
|
|
01917d |
+ return 0;
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
+/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP
|
|
|
01917d |
+ disappears while we try to resume it. */
|
|
|
01917d |
+
|
|
|
01917d |
+static void
|
|
|
01917d |
+linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
|
|
|
01917d |
+{
|
|
|
01917d |
+ volatile struct gdb_exception ex;
|
|
|
01917d |
+
|
|
|
01917d |
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
|
|
|
01917d |
+ {
|
|
|
01917d |
+ linux_resume_one_lwp_throw (lp, step, signo);
|
|
|
01917d |
+ }
|
|
|
01917d |
+ if (ex.reason < 0)
|
|
|
01917d |
+ {
|
|
|
01917d |
+ if (!check_ptrace_stopped_lwp_gone (lp))
|
|
|
01917d |
+ throw_exception (ex);
|
|
|
01917d |
+ }
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
/* Resume LP. */
|
|
|
01917d |
|
|
|
01917d |
static void
|
|
|
01917d |
@@ -1956,14 +2035,7 @@ resume_lwp (struct lwp_info *lp, int ste
|
|
|
01917d |
: "0"),
|
|
|
01917d |
step ? "step" : "resume");
|
|
|
01917d |
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops,
|
|
|
01917d |
- pid_to_ptid (GET_LWP (lp->ptid)),
|
|
|
01917d |
- step, signo);
|
|
|
01917d |
- lp->stopped = 0;
|
|
|
01917d |
- lp->step = step;
|
|
|
01917d |
- lp->stopped_by_watchpoint = 0;
|
|
|
01917d |
+ linux_resume_one_lwp (lp, step, signo);
|
|
|
01917d |
}
|
|
|
01917d |
else
|
|
|
01917d |
{
|
|
|
01917d |
@@ -1982,13 +2054,17 @@ resume_lwp (struct lwp_info *lp, int ste
|
|
|
01917d |
}
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
-/* Resume LWP, with the last stop signal, if it is in pass state. */
|
|
|
01917d |
+/* Callback for iterate_over_lwps. If LWP is EXCEPT, do nothing.
|
|
|
01917d |
+ Resume LWP with the last stop signal, if it is in pass state. */
|
|
|
01917d |
|
|
|
01917d |
static int
|
|
|
01917d |
-linux_nat_resume_callback (struct lwp_info *lp, void *data)
|
|
|
01917d |
+linux_nat_resume_callback (struct lwp_info *lp, void *except)
|
|
|
01917d |
{
|
|
|
01917d |
enum gdb_signal signo = GDB_SIGNAL_0;
|
|
|
01917d |
|
|
|
01917d |
+ if (lp == except)
|
|
|
01917d |
+ return 0;
|
|
|
01917d |
+
|
|
|
01917d |
if (lp->stopped)
|
|
|
01917d |
{
|
|
|
01917d |
struct thread_info *thread;
|
|
|
01917d |
@@ -2108,20 +2184,10 @@ linux_nat_resume (struct target_ops *ops
|
|
|
01917d |
return;
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
- /* Mark LWP as not stopped to prevent it from being continued by
|
|
|
01917d |
- linux_nat_resume_callback. */
|
|
|
01917d |
- lp->stopped = 0;
|
|
|
01917d |
-
|
|
|
01917d |
if (resume_many)
|
|
|
01917d |
- iterate_over_lwps (ptid, linux_nat_resume_callback, NULL);
|
|
|
01917d |
+ iterate_over_lwps (ptid, linux_nat_resume_callback, lp);
|
|
|
01917d |
|
|
|
01917d |
- /* Convert to something the lower layer understands. */
|
|
|
01917d |
- ptid = pid_to_ptid (GET_LWP (lp->ptid));
|
|
|
01917d |
-
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, ptid, step, signo);
|
|
|
01917d |
- lp->stopped_by_watchpoint = 0;
|
|
|
01917d |
+ linux_resume_one_lwp (lp, step, signo);
|
|
|
01917d |
|
|
|
01917d |
if (debug_linux_nat)
|
|
|
01917d |
fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
@@ -2287,11 +2353,7 @@ linux_handle_syscall_trap (struct lwp_in
|
|
|
01917d |
|
|
|
01917d |
/* Note that gdbarch_get_syscall_number may access registers, hence
|
|
|
01917d |
fill a regcache. */
|
|
|
01917d |
- registers_changed ();
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
|
|
01917d |
- lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
+ linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
return 1;
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
@@ -2486,22 +2548,15 @@ linux_handle_extended_wait (struct lwp_i
|
|
|
01917d |
fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
"LHEW: resuming new LWP %ld\n",
|
|
|
01917d |
GET_LWP (new_lp->ptid));
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (new_lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
|
|
|
01917d |
- 0, GDB_SIGNAL_0);
|
|
|
01917d |
- new_lp->stopped = 0;
|
|
|
01917d |
+
|
|
|
01917d |
+ linux_resume_one_lwp (new_lp, 0, GDB_SIGNAL_0);
|
|
|
01917d |
}
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
if (debug_linux_nat)
|
|
|
01917d |
fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
"LHEW: resuming parent LWP %d\n", pid);
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
|
|
01917d |
- 0, GDB_SIGNAL_0);
|
|
|
01917d |
-
|
|
|
01917d |
+ linux_resume_one_lwp (lp, 0, GDB_SIGNAL_0);
|
|
|
01917d |
return 1;
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
@@ -3382,12 +3437,7 @@ linux_nat_filter_event (int lwpid, int s
|
|
|
01917d |
{
|
|
|
01917d |
/* This is a delayed SIGSTOP. */
|
|
|
01917d |
|
|
|
01917d |
- registers_changed ();
|
|
|
01917d |
-
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
|
|
01917d |
- lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
+ linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
if (debug_linux_nat)
|
|
|
01917d |
fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
"LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
|
|
|
01917d |
@@ -3395,7 +3445,6 @@ linux_nat_filter_event (int lwpid, int s
|
|
|
01917d |
"PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
|
|
01917d |
target_pid_to_str (lp->ptid));
|
|
|
01917d |
|
|
|
01917d |
- lp->stopped = 0;
|
|
|
01917d |
gdb_assert (lp->resumed);
|
|
|
01917d |
|
|
|
01917d |
/* Discard the event. */
|
|
|
01917d |
@@ -3416,11 +3465,7 @@ linux_nat_filter_event (int lwpid, int s
|
|
|
01917d |
/* This is a delayed SIGINT. */
|
|
|
01917d |
lp->ignore_sigint = 0;
|
|
|
01917d |
|
|
|
01917d |
- registers_changed ();
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
|
|
01917d |
- lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
+ linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
if (debug_linux_nat)
|
|
|
01917d |
fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
"LLW: %s %s, 0, 0 (discard SIGINT)\n",
|
|
|
01917d |
@@ -3428,7 +3473,6 @@ linux_nat_filter_event (int lwpid, int s
|
|
|
01917d |
"PTRACE_SINGLESTEP" : "PTRACE_CONT",
|
|
|
01917d |
target_pid_to_str (lp->ptid));
|
|
|
01917d |
|
|
|
01917d |
- lp->stopped = 0;
|
|
|
01917d |
gdb_assert (lp->resumed);
|
|
|
01917d |
|
|
|
01917d |
/* Discard the event. */
|
|
|
01917d |
@@ -3796,11 +3840,7 @@ retry:
|
|
|
01917d |
other threads to run. On the other hand, not resuming
|
|
|
01917d |
newly attached threads may cause an unwanted delay in
|
|
|
01917d |
getting them running. */
|
|
|
01917d |
- registers_changed ();
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
|
|
01917d |
- lp->step, signo);
|
|
|
01917d |
+ linux_resume_one_lwp (lp, lp->step, signo);
|
|
|
01917d |
if (debug_linux_nat)
|
|
|
01917d |
fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
"LLW: %s %s, %s (preempt 'handle')\n",
|
|
|
01917d |
@@ -3810,7 +3850,6 @@ retry:
|
|
|
01917d |
(signo != GDB_SIGNAL_0
|
|
|
01917d |
? strsignal (gdb_signal_to_host (signo))
|
|
|
01917d |
: "0"));
|
|
|
01917d |
- lp->stopped = 0;
|
|
|
01917d |
goto retry;
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
@@ -3935,32 +3974,41 @@ resume_stopped_resumed_lwps (struct lwp_
|
|
|
01917d |
{
|
|
|
01917d |
struct regcache *regcache = get_thread_regcache (lp->ptid);
|
|
|
01917d |
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
|
|
01917d |
- CORE_ADDR pc = regcache_read_pc (regcache);
|
|
|
01917d |
+ volatile struct gdb_exception ex;
|
|
|
01917d |
|
|
|
01917d |
gdb_assert (is_executing (lp->ptid));
|
|
|
01917d |
|
|
|
01917d |
- /* Don't bother if there's a breakpoint at PC that we'd hit
|
|
|
01917d |
- immediately, and we're not waiting for this LWP. */
|
|
|
01917d |
- if (!ptid_match (lp->ptid, *wait_ptid_p))
|
|
|
01917d |
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
|
|
|
01917d |
{
|
|
|
01917d |
- if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
|
|
|
01917d |
- return 0;
|
|
|
01917d |
- }
|
|
|
01917d |
+ CORE_ADDR pc = regcache_read_pc (regcache);
|
|
|
01917d |
+ int leave_stopped = 0;
|
|
|
01917d |
|
|
|
01917d |
- if (debug_linux_nat)
|
|
|
01917d |
- fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
- "RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
|
|
|
01917d |
- target_pid_to_str (lp->ptid),
|
|
|
01917d |
- paddress (gdbarch, pc),
|
|
|
01917d |
- lp->step);
|
|
|
01917d |
+ /* Don't bother if there's a breakpoint at PC that we'd hit
|
|
|
01917d |
+ immediately, and we're not waiting for this LWP. */
|
|
|
01917d |
+ if (!ptid_match (lp->ptid, *wait_ptid_p))
|
|
|
01917d |
+ {
|
|
|
01917d |
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
|
|
|
01917d |
+ leave_stopped = 1;
|
|
|
01917d |
+ }
|
|
|
01917d |
|
|
|
01917d |
- registers_changed ();
|
|
|
01917d |
- if (linux_nat_prepare_to_resume != NULL)
|
|
|
01917d |
- linux_nat_prepare_to_resume (lp);
|
|
|
01917d |
- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
|
|
|
01917d |
- lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
- lp->stopped = 0;
|
|
|
01917d |
- lp->stopped_by_watchpoint = 0;
|
|
|
01917d |
+ if (!leave_stopped)
|
|
|
01917d |
+ {
|
|
|
01917d |
+ if (debug_linux_nat)
|
|
|
01917d |
+ fprintf_unfiltered (gdb_stdlog,
|
|
|
01917d |
+ "RSRL: resuming stopped-resumed LWP %s at "
|
|
|
01917d |
+ "%s: step=%d\n",
|
|
|
01917d |
+ target_pid_to_str (lp->ptid),
|
|
|
01917d |
+ paddress (gdbarch, pc),
|
|
|
01917d |
+ lp->step);
|
|
|
01917d |
+
|
|
|
01917d |
+ linux_resume_one_lwp_throw (lp, lp->step, GDB_SIGNAL_0);
|
|
|
01917d |
+ }
|
|
|
01917d |
+ }
|
|
|
01917d |
+ if (ex.reason < 0)
|
|
|
01917d |
+ {
|
|
|
01917d |
+ if (!check_ptrace_stopped_lwp_gone (lp))
|
|
|
01917d |
+ throw_exception (ex);
|
|
|
01917d |
+ }
|
|
|
01917d |
}
|
|
|
01917d |
|
|
|
01917d |
return 0;
|
|
|
01917d |
Index: gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.c
|
|
|
01917d |
===================================================================
|
|
|
01917d |
--- /dev/null
|
|
|
01917d |
+++ gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.c
|
|
|
01917d |
@@ -0,0 +1,62 @@
|
|
|
01917d |
+/* Copyright 2015 Free Software Foundation, Inc.
|
|
|
01917d |
+
|
|
|
01917d |
+ This file is part of GDB.
|
|
|
01917d |
+
|
|
|
01917d |
+ This program is free software; you can redistribute it and/or modify
|
|
|
01917d |
+ it under the terms of the GNU General Public License as published by
|
|
|
01917d |
+ the Free Software Foundation; either version 3 of the License, or
|
|
|
01917d |
+ (at your option) any later version.
|
|
|
01917d |
+
|
|
|
01917d |
+ This program is distributed in the hope that it will be useful,
|
|
|
01917d |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
01917d |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
01917d |
+ GNU General Public License for more details.
|
|
|
01917d |
+
|
|
|
01917d |
+ You should have received a copy of the GNU General Public License
|
|
|
01917d |
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
01917d |
+
|
|
|
01917d |
+#include <pthread.h>
|
|
|
01917d |
+#include <unistd.h>
|
|
|
01917d |
+
|
|
|
01917d |
+volatile int call_exit;
|
|
|
01917d |
+static pthread_barrier_t barrier;
|
|
|
01917d |
+#define NUMTHREADS 256
|
|
|
01917d |
+
|
|
|
01917d |
+void *
|
|
|
01917d |
+thread_function (void *arg)
|
|
|
01917d |
+{
|
|
|
01917d |
+ pthread_barrier_wait (&barrier);
|
|
|
01917d |
+
|
|
|
01917d |
+ while (!call_exit)
|
|
|
01917d |
+ usleep (1);
|
|
|
01917d |
+
|
|
|
01917d |
+ _exit (0);
|
|
|
01917d |
+ return NULL;
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
+void
|
|
|
01917d |
+all_threads_started (void)
|
|
|
01917d |
+{
|
|
|
01917d |
+ call_exit = 1;
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
+int
|
|
|
01917d |
+main (int argc, char **argv)
|
|
|
01917d |
+{
|
|
|
01917d |
+ pthread_t threads[NUMTHREADS];
|
|
|
01917d |
+ int i;
|
|
|
01917d |
+
|
|
|
01917d |
+ pthread_barrier_init (&barrier, NULL, NUMTHREADS + 1);
|
|
|
01917d |
+
|
|
|
01917d |
+ for (i = 0; i < NUMTHREADS; ++i)
|
|
|
01917d |
+ pthread_create (&threads[i], NULL, thread_function, NULL);
|
|
|
01917d |
+
|
|
|
01917d |
+ pthread_barrier_wait (&barrier);
|
|
|
01917d |
+
|
|
|
01917d |
+ all_threads_started ();
|
|
|
01917d |
+
|
|
|
01917d |
+ for (i = 0; i < NUMTHREADS; ++i)
|
|
|
01917d |
+ pthread_join (threads[i], NULL);
|
|
|
01917d |
+
|
|
|
01917d |
+ return 0;
|
|
|
01917d |
+}
|
|
|
01917d |
Index: gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.exp
|
|
|
01917d |
===================================================================
|
|
|
01917d |
--- /dev/null
|
|
|
01917d |
+++ gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.exp
|
|
|
01917d |
@@ -0,0 +1,70 @@
|
|
|
01917d |
+# Copyright (C) 2015 Free Software Foundation, Inc.
|
|
|
01917d |
+
|
|
|
01917d |
+# This program is free software; you can redistribute it and/or modify
|
|
|
01917d |
+# it under the terms of the GNU General Public License as published by
|
|
|
01917d |
+# the Free Software Foundation; either version 3 of the License, or
|
|
|
01917d |
+# (at your option) any later version.
|
|
|
01917d |
+#
|
|
|
01917d |
+# This program is distributed in the hope that it will be useful,
|
|
|
01917d |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
01917d |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
01917d |
+# GNU General Public License for more details.
|
|
|
01917d |
+#
|
|
|
01917d |
+# You should have received a copy of the GNU General Public License
|
|
|
01917d |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
01917d |
+
|
|
|
01917d |
+standard_testfile
|
|
|
01917d |
+
|
|
|
01917d |
+if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
|
|
|
01917d |
+ return -1
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
+clean_restart ${binfile}
|
|
|
01917d |
+if {![runto_main]} {
|
|
|
01917d |
+ fail "Couldn't run to main"
|
|
|
01917d |
+ return
|
|
|
01917d |
+}
|
|
|
01917d |
+
|
|
|
01917d |
+gdb_breakpoint "all_threads_started"
|
|
|
01917d |
+
|
|
|
01917d |
+gdb_continue_to_breakpoint "all_threads_started"
|
|
|
01917d |
+
|
|
|
01917d |
+# Update the thread list, otherwise when testing against GDBserver,
|
|
|
01917d |
+# GDB won't know about thread 2. (Only necessary with GDB < 7.9.)
|
|
|
01917d |
+gdb_test "info threads" ".*"
|
|
|
01917d |
+
|
|
|
01917d |
+# Select any thread but the leader.
|
|
|
01917d |
+gdb_test "thread 2" ".*" "switch to non-leader thread"
|
|
|
01917d |
+
|
|
|
01917d |
+# Delete breakpoints so that GDB doesn't switch back the to leader to
|
|
|
01917d |
+# step over its breakpoint.
|
|
|
01917d |
+delete_breakpoints
|
|
|
01917d |
+
|
|
|
01917d |
+# Let threads exit the process on next resume.
|
|
|
01917d |
+gdb_test "p call_exit = 0" " = 0"
|
|
|
01917d |
+
|
|
|
01917d |
+# While GDB is busy resuming all threads one by one, one of the
|
|
|
01917d |
+# threads should manage to exit the process. GDB should handle that
|
|
|
01917d |
+# gracefully instead of erroring out.
|
|
|
01917d |
+#
|
|
|
01917d |
+# gdb_continue_to_end doesn't work with GDBserver until the
|
|
|
01917d |
+# introduction of the "exit_is_reliable" board variable
|
|
|
01917d |
+# (b477a5e649150) in GDB 7.7.
|
|
|
01917d |
+#gdb_continue_to_end "" continue 1
|
|
|
01917d |
+gdb_test "continue" "$inferior_exited_re normally.*"
|
|
|
01917d |
+
|
|
|
01917d |
+# On the buggy GDB where the "continue" above would error out, a
|
|
|
01917d |
+# subsequent "detach" (e.g., the user tries to quit GDB, and quit
|
|
|
01917d |
+# offers to detach) would hit this assertion:
|
|
|
01917d |
+#
|
|
|
01917d |
+# linux-nat.c:1869: internal-error: linux_nat_detach: Assertion `num_lwps (GET_PID (inferior_ptid)) == 1' failed.
|
|
|
01917d |
+
|
|
|
01917d |
+# That was a consequence of the original bug, but let's make sure that
|
|
|
01917d |
+# even when "continue" is handled properly, detach doesn't stumble on
|
|
|
01917d |
+# anything stale.
|
|
|
01917d |
+gdb_test "detach" "The program is not being run\\." \
|
|
|
01917d |
+ "detach after exit"
|
|
|
01917d |
+
|
|
|
01917d |
+# Likewise "continue".
|
|
|
01917d |
+gdb_test "continue" "The program is not being run\\." \
|
|
|
01917d |
+ "continue after exit"
|