http://sourceware.org/ml/gdb-cvs/2012-02/msg00180.html ### src/gdb/gdbserver/ChangeLog 2012/02/25 19:54:50 1.556 ### src/gdb/gdbserver/ChangeLog 2012/02/27 16:19:19 1.557 ## -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 --- src/gdb/gdbserver/linux-low.c 2012/02/24 15:15:56 1.193 +++ src/gdb/gdbserver/linux-low.c 2012/02/27 16:19:19 1.194 @@ -598,6 +598,37 @@ 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 @@ 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.