From c14d7ab2b61d410e10380fcdc21985cdcd88f810 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 27 Feb 2012 16:19:19 +0000 Subject: [PATCH] 2012-02-27 Pedro Alves PR server/9684 * linux-low.c (pid_is_stopped): New. (linux_attach_lwp_1): Handle attaching to 'T (stopped)' processes. --- gdb/gdbserver/ChangeLog | 6 ++++ gdb/gdbserver/linux-low.c | 58 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 1e2f5e9f727..b6d9ce93932 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,9 @@ +2012-02-27 Pedro Alves + + PR server/9684 + * linux-low.c (pid_is_stopped): New. + (linux_attach_lwp_1): Handle attaching to 'T (stopped)' processes. + 2012-02-25 Luis Machado * mem-break.c (clear_gdb_breakpoint_conditions): Fix de-allocation diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 8a832313756..f2887e65413 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -598,6 +598,37 @@ linux_create_inferior (char *program, char **allargs) return pid; } +/* Detect `T (stopped)' in `/proc/PID/status'. + Other states including `T (tracing stop)' are reported as false. */ + +static int +pid_is_stopped (pid_t pid) +{ + FILE *status_file; + char buf[100]; + int retval = 0; + + snprintf (buf, sizeof (buf), "/proc/%d/status", (int) pid); + status_file = fopen (buf, "r"); + if (status_file != NULL) + { + int have_state = 0; + + while (fgets (buf, sizeof (buf), status_file)) + { + if (strncmp (buf, "State:", 6) == 0) + { + have_state = 1; + break; + } + } + if (have_state && strstr (buf, "T (stopped)") != NULL) + retval = 1; + fclose (status_file); + } + return retval; +} + /* Attach to an inferior process. */ static void @@ -643,6 +674,33 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) ptrace call on this LWP. */ new_lwp->must_set_ptrace_flags = 1; + if (pid_is_stopped (lwpid)) + { + if (debug_threads) + fprintf (stderr, + "Attached to a stopped process\n"); + + /* The process is definitely stopped. It is in a job control + stop, unless the kernel predates the TASK_STOPPED / + TASK_TRACED distinction, in which case it might be in a + ptrace stop. Make sure it is in a ptrace stop; from there we + can kill it, signal it, et cetera. + + First make sure there is a pending SIGSTOP. Since we are + already attached, the process can not transition from stopped + to running without a PTRACE_CONT; so we know this signal will + go into the queue. The SIGSTOP generated by PTRACE_ATTACH is + probably already in the queue (unless this kernel is old + enough to use TASK_STOPPED for ptrace stops); but since + SIGSTOP is not an RT signal, it can only be queued once. */ + kill_lwp (lwpid, SIGSTOP); + + /* Finally, resume the stopped process. This will deliver the + SIGSTOP (or a higher priority signal, just like normal + PTRACE_ATTACH), which we'll catch later on. */ + ptrace (PTRACE_CONT, lwpid, 0, 0); + } + /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH brings it to a halt. -- 2.30.2