aboutsummaryrefslogtreecommitdiff
path: root/gdb/linux-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r--gdb/linux-nat.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 73fd2cb..0adf3a9 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -1137,6 +1137,73 @@ linux_nat_create_inferior (struct target_ops *ops,
#endif /* HAVE_PERSONALITY */
}
+/* Callback for linux_proc_attach_tgid_threads. Attach to PTID if not
+ already attached. Returns true if a new LWP is found, false
+ otherwise. */
+
+static int
+attach_proc_task_lwp_callback (ptid_t ptid)
+{
+ struct lwp_info *lp;
+
+ /* Ignore LWPs we're already attached to. */
+ lp = find_lwp_pid (ptid);
+ if (lp == NULL)
+ {
+ int lwpid = ptid_get_lwp (ptid);
+
+ if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) < 0)
+ {
+ int err = errno;
+
+ /* Be quiet if we simply raced with the thread exiting.
+ EPERM is returned if the thread's task still exists, and
+ is marked as exited or zombie, as well as other
+ conditions, so in that case, confirm the status in
+ /proc/PID/status. */
+ if (err == ESRCH
+ || (err == EPERM && linux_proc_pid_is_gone (lwpid)))
+ {
+ if (debug_linux_nat)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "Cannot attach to lwp %d: "
+ "thread is gone (%d: %s)\n",
+ lwpid, err, safe_strerror (err));
+ }
+ }
+ else
+ {
+ warning (_("Cannot attach to lwp %d: %s\n"),
+ lwpid,
+ linux_ptrace_attach_fail_reason_string (ptid,
+ err));
+ }
+ }
+ else
+ {
+ if (debug_linux_nat)
+ fprintf_unfiltered (gdb_stdlog,
+ "PTRACE_ATTACH %s, 0, 0 (OK)\n",
+ target_pid_to_str (ptid));
+
+ lp = add_lwp (ptid);
+ lp->cloned = 1;
+
+ /* The next time we wait for this LWP we'll see a SIGSTOP as
+ PTRACE_ATTACH brings it to a halt. */
+ lp->signalled = 1;
+
+ /* We need to wait for a stop before being able to make the
+ next ptrace call on this LWP. */
+ lp->must_set_ptrace_flags = 1;
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
static void
linux_nat_attach (struct target_ops *ops, const char *args, int from_tty)
{
@@ -1230,6 +1297,16 @@ linux_nat_attach (struct target_ops *ops, const char *args, int from_tty)
lp->status = status;
+ /* We must attach to every LWP. If /proc is mounted, use that to
+ find them now. The inferior may be using raw clone instead of
+ using pthreads. But even if it is using pthreads, thread_db
+ walks structures in the inferior's address space to find the list
+ of threads/LWPs, and those structures may well be corrupted.
+ Note that once thread_db is loaded, we'll still use it to list
+ threads and associate pthread info with each LWP. */
+ linux_proc_attach_tgid_threads (ptid_get_pid (lp->ptid),
+ attach_proc_task_lwp_callback);
+
if (target_can_async_p ())
target_async (inferior_event_handler, 0);
}
@@ -2159,6 +2236,14 @@ wait_lwp (struct lwp_info *lp)
gdb_assert (WIFSTOPPED (status));
lp->stopped = 1;
+ if (lp->must_set_ptrace_flags)
+ {
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+
+ linux_enable_event_reporting (ptid_get_lwp (lp->ptid), inf->attach_flag);
+ lp->must_set_ptrace_flags = 0;
+ }
+
/* Handle GNU/Linux's syscall SIGTRAPs. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SYSCALL_SIGTRAP)
{
@@ -2783,6 +2868,14 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
ever being continued.) */
lp->stopped = 1;
+ if (WIFSTOPPED (status) && lp->must_set_ptrace_flags)
+ {
+ struct inferior *inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+
+ linux_enable_event_reporting (ptid_get_lwp (lp->ptid), inf->attach_flag);
+ lp->must_set_ptrace_flags = 0;
+ }
+
/* Handle GNU/Linux's syscall SIGTRAPs. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SYSCALL_SIGTRAP)
{