gdbserver: report correct status in thread stop race condition
[deliverable/binutils-gdb.git] / gdbserver / linux-low.cc
index 3c68c57384be38c83ac4c0190eb417aa4ba80d1f..b70a3aa2d1612170577a41d08706d5660003798c 100644 (file)
@@ -3589,6 +3589,9 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
        unstop_all_lwps (1, event_child);
     }
 
+  /* At this point, we haven't set OURSTATUS.  This is where we do it.  */
+  gdb_assert (ourstatus->kind == TARGET_WAITKIND_IGNORE);
+
   if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE)
     {
       /* If the reported event is an exit, fork, vfork or exec, let
@@ -3607,7 +3610,31 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
       event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE;
     }
   else
-    ourstatus->kind = TARGET_WAITKIND_STOPPED;
+    {
+      /* The LWP stopped due to a plain signal or a syscall signal.  Either way,
+         event_chid->waitstatus wasn't filled in with the details, so look at
+        the wait status W.  */
+      if (WSTOPSIG (w) == SYSCALL_SIGTRAP)
+       {
+         get_syscall_trapinfo (event_child,
+                               &ourstatus->value.syscall_number);
+         ourstatus->kind = event_child->syscall_state;
+       }
+      else if (current_thread->last_resume_kind == resume_stop
+              && WSTOPSIG (w) == SIGSTOP)
+       {
+         /* A thread that has been requested to stop by GDB with vCont;t,
+            and it stopped cleanly, so report as SIG0.  The use of
+            SIGSTOP is an implementation detail.  */
+         ourstatus->kind = TARGET_WAITKIND_STOPPED;
+         ourstatus->value.sig = GDB_SIGNAL_0;
+       }
+      else
+       {
+         ourstatus->kind = TARGET_WAITKIND_STOPPED;
+         ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w));
+       }
+    }
 
   /* Now that we've selected our final event LWP, un-adjust its PC if
      it was a software breakpoint, and the client doesn't know we can
@@ -3625,32 +3652,6 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
        }
     }
 
-  if (WSTOPSIG (w) == SYSCALL_SIGTRAP)
-    {
-      get_syscall_trapinfo (event_child,
-                           &ourstatus->value.syscall_number);
-      ourstatus->kind = event_child->syscall_state;
-    }
-  else if (current_thread->last_resume_kind == resume_stop
-          && WSTOPSIG (w) == SIGSTOP)
-    {
-      /* A thread that has been requested to stop by GDB with vCont;t,
-        and it stopped cleanly, so report as SIG0.  The use of
-        SIGSTOP is an implementation detail.  */
-      ourstatus->value.sig = GDB_SIGNAL_0;
-    }
-  else if (current_thread->last_resume_kind == resume_stop
-          && WSTOPSIG (w) != SIGSTOP)
-    {
-      /* A thread that has been requested to stop by GDB with vCont;t,
-        but, it stopped for other reasons.  */
-      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w));
-    }
-  else if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
-    {
-      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w));
-    }
-
   gdb_assert (step_over_bkpt == null_ptid);
 
   if (debug_threads)
This page took 0.038944 seconds and 4 git commands to generate.