Blob Blame History Raw
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  <palves@redhat.com>
+
+	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  <lgustavo@codesourcery.com>
 
 	* 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.