Change signature of linux_target_ops.new_thread
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index f5f92d9d96b65411ff93ca7ab2364a3a26b4238f..283a12bc7125d327a8c2295aae4f3f0ccf273ef7 100644 (file)
@@ -281,6 +281,33 @@ static int check_stopped_by_breakpoint (struct lwp_info *lp);
 static int sigtrap_is_event (int status);
 static int (*linux_nat_status_is_event) (int status) = sigtrap_is_event;
 
+\f
+/* LWP accessors.  */
+
+/* See nat/linux-nat.h.  */
+
+ptid_t
+ptid_of_lwp (struct lwp_info *lwp)
+{
+  return lwp->ptid;
+}
+
+/* See nat/linux-nat.h.  */
+
+int
+lwp_is_stopped (struct lwp_info *lwp)
+{
+  return lwp->stopped;
+}
+
+/* See nat/linux-nat.h.  */
+
+enum target_stop_reason
+lwp_stop_reason (struct lwp_info *lwp)
+{
+  return lwp->stop_reason;
+}
+
 \f
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
@@ -834,14 +861,11 @@ find_lwp_pid (ptid_t ptid)
   return NULL;
 }
 
-/* Call CALLBACK with its second argument set to DATA for every LWP in
-   the list.  If CALLBACK returns 1 for a particular LWP, return a
-   pointer to the structure describing that LWP immediately.
-   Otherwise return NULL.  */
+/* See nat/linux-nat.h.  */
 
 struct lwp_info *
 iterate_over_lwps (ptid_t filter,
-                  int (*callback) (struct lwp_info *, void *),
+                  iterate_over_lwps_ftype callback,
                   void *data)
 {
   struct lwp_info *lp, *lpnext;
@@ -852,7 +876,7 @@ iterate_over_lwps (ptid_t filter,
 
       if (ptid_match (lp->ptid, filter))
        {
-         if ((*callback) (lp, data))
+         if ((*callback) (lp, data) != 0)
            return lp;
        }
     }
@@ -1503,7 +1527,8 @@ linux_nat_detach (struct target_ops *ops, const char *args, int from_tty)
    single-step it.  If SIGNAL is nonzero, give it that signal.  */
 
 static void
-linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
+linux_resume_one_lwp_throw (struct lwp_info *lp, int step,
+                           enum gdb_signal signo)
 {
   lp->step = step;
 
@@ -1522,11 +1547,68 @@ linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
   if (linux_nat_prepare_to_resume != NULL)
     linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, lp->ptid, step, signo);
-  lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
+
+  /* Successfully resumed.  Clear state that no longer makes sense,
+     and mark the LWP as running.  Must not do this before resuming
+     otherwise if that fails other code will be confused.  E.g., we'd
+     later try to stop the LWP and hang forever waiting for a stop
+     status.  Note that we must not throw after this is cleared,
+     otherwise handle_zombie_lwp_error would get confused.  */
   lp->stopped = 0;
+  lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
   registers_changed_ptid (lp->ptid);
 }
 
+/* Called when we try to resume a stopped LWP and that errors out.  If
+   the LWP is no longer in ptrace-stopped state (meaning it's zombie,
+   or about to become), discard the error, clear any pending status
+   the LWP may have, and return true (we'll collect the exit status
+   soon enough).  Otherwise, return false.  */
+
+static int
+check_ptrace_stopped_lwp_gone (struct lwp_info *lp)
+{
+  /* If we get an error after resuming the LWP successfully, we'd
+     confuse !T state for the LWP being gone.  */
+  gdb_assert (lp->stopped);
+
+  /* We can't just check whether the LWP is in 'Z (Zombie)' state,
+     because even if ptrace failed with ESRCH, the tracee may be "not
+     yet fully dead", but already refusing ptrace requests.  In that
+     case the tracee has 'R (Running)' state for a little bit
+     (observed in Linux 3.18).  See also the note on ESRCH in the
+     ptrace(2) man page.  Instead, check whether the LWP has any state
+     other than ptrace-stopped.  */
+
+  /* Don't assume anything if /proc/PID/status can't be read.  */
+  if (linux_proc_pid_is_trace_stopped_nowarn (ptid_get_lwp (lp->ptid)) == 0)
+    {
+      lp->stop_reason = TARGET_STOPPED_BY_NO_REASON;
+      lp->status = 0;
+      lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+      return 1;
+    }
+  return 0;
+}
+
+/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP
+   disappears while we try to resume it.  */
+
+static void
+linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo)
+{
+  TRY
+    {
+      linux_resume_one_lwp_throw (lp, step, signo);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (!check_ptrace_stopped_lwp_gone (lp))
+       throw_exception (ex);
+    }
+  END_CATCH
+}
+
 /* Resume LP.  */
 
 static void
@@ -2841,6 +2923,7 @@ select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
 
       /* First see how many events we have.  */
       iterate_over_lwps (filter, count_events_callback, &num_events);
+      gdb_assert (num_events > 0);
 
       /* Now randomly pick a LWP out of those that have had
         events.  */
@@ -3541,24 +3624,39 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
     {
       struct regcache *regcache = get_thread_regcache (lp->ptid);
       struct gdbarch *gdbarch = get_regcache_arch (regcache);
-      CORE_ADDR pc = regcache_read_pc (regcache);
 
-      /* Don't bother if there's a breakpoint at PC that we'd hit
-        immediately, and we're not waiting for this LWP.  */
-      if (!ptid_match (lp->ptid, *wait_ptid_p))
+      TRY
        {
-         if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
-           return 0;
-       }
+         CORE_ADDR pc = regcache_read_pc (regcache);
+         int leave_stopped = 0;
 
-      if (debug_linux_nat)
-       fprintf_unfiltered (gdb_stdlog,
-                           "RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
-                           target_pid_to_str (lp->ptid),
-                           paddress (gdbarch, pc),
-                           lp->step);
+         /* Don't bother if there's a breakpoint at PC that we'd hit
+            immediately, and we're not waiting for this LWP.  */
+         if (!ptid_match (lp->ptid, *wait_ptid_p))
+           {
+             if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
+               leave_stopped = 1;
+           }
 
-      linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0);
+         if (!leave_stopped)
+           {
+             if (debug_linux_nat)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "RSRL: resuming stopped-resumed LWP %s at "
+                                   "%s: step=%d\n",
+                                   target_pid_to_str (lp->ptid),
+                                   paddress (gdbarch, pc),
+                                   lp->step);
+
+             linux_resume_one_lwp_throw (lp, lp->step, GDB_SIGNAL_0);
+           }
+       }
+      CATCH (ex, RETURN_MASK_ERROR)
+       {
+         if (!check_ptrace_stopped_lwp_gone (lp))
+           throw_exception (ex);
+       }
+      END_CATCH
     }
 
   return 0;
@@ -4864,6 +4962,15 @@ linux_nat_get_siginfo (ptid_t ptid, siginfo_t *siginfo)
   return 1;
 }
 
+/* See nat/linux-nat.h.  */
+
+ptid_t
+current_lwp_ptid (void)
+{
+  gdb_assert (ptid_lwp_p (inferior_ptid));
+  return inferior_ptid;
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_linux_nat;
 
This page took 0.032486 seconds and 4 git commands to generate.