* linux-low.c (linux_prepare_to_access_memory): New.
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-low.c
index 65a87f68ed85780fb75f5b093e7a13948315d823..7fa9336e8cd550881cdafe50b683f57bcd51b21b 100644 (file)
@@ -127,6 +127,10 @@ int stopping_threads;
 /* FIXME make into a target method?  */
 int using_threads = 1;
 
+/* True if we're presently stabilizing threads (moving them out of
+   jump pads).  */
+static int stabilizing_threads;
+
 /* This flag is true iff we've just created or attached to our first
    inferior but it has not stopped yet.  As soon as it does, we need
    to call the low target's arch_setup callback.  Doing this only on
@@ -139,14 +143,14 @@ static int new_inferior;
 static void linux_resume_one_lwp (struct lwp_info *lwp,
                                  int step, int signal, siginfo_t *info);
 static void linux_resume (struct thread_resume *resume_info, size_t n);
-static void stop_all_lwps (void);
+static void stop_all_lwps (int suspend, struct lwp_info *except);
+static void unstop_all_lwps (int unsuspend, struct lwp_info *except);
 static int linux_wait_for_event (ptid_t ptid, int *wstat, int options);
 static void *add_lwp (ptid_t ptid);
 static int linux_stopped_by_watchpoint (void);
 static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
 static int linux_core_of_thread (ptid_t ptid);
 static void proceed_all_lwps (void);
-static void unstop_all_lwps (struct lwp_info *except);
 static int finish_step_over (struct lwp_info *lwp);
 static CORE_ADDR get_stop_pc (struct lwp_info *lwp);
 static int kill_lwp (unsigned long lwpid, int signo);
@@ -170,6 +174,16 @@ supports_breakpoints (void)
   return (the_low_target.get_pc != NULL);
 }
 
+/* Returns true if this target can support fast tracepoints.  This
+   does not mean that the in-process agent has been loaded in the
+   inferior.  */
+
+static int
+supports_fast_tracepoints (void)
+{
+  return the_low_target.install_fast_tracepoint_jump_pad != NULL;
+}
+
 struct pending_signals
 {
   int signal;
@@ -765,7 +779,7 @@ linux_kill (int pid)
 
   /* If we're killing a running inferior, make sure it is stopped
      first, as PTRACE_KILL will not work otherwise.  */
-  stop_all_lwps ();
+  stop_all_lwps (0, NULL);
 
   find_inferior (&all_threads, linux_kill_one_lwp, &pid);
 
@@ -790,7 +804,7 @@ linux_kill (int pid)
 
   /* Since we presently can only stop all lwps of all processes, we
      need to unstop lwps of other processes.  */
-  unstop_all_lwps (NULL);
+  unstop_all_lwps (0, NULL);
   return 0;
 }
 
@@ -840,19 +854,22 @@ linux_detach (int pid)
      the thread is stopped to sucessfully detach.  Second, thread_db
      may need to uninstall thread event breakpoints from memory, which
      only works with a stopped process anyway.  */
-  stop_all_lwps ();
+  stop_all_lwps (0, NULL);
 
 #ifdef USE_THREAD_DB
   thread_db_detach (process);
 #endif
 
+  /* Stabilize threads (move out of jump pads).  */
+  stabilize_threads ();
+
   find_inferior (&all_threads, linux_detach_one_lwp, &pid);
 
   the_target->mourn (process);
 
   /* Since we presently can only stop all lwps of all processes, we
      need to unstop lwps of other processes.  */
-  unstop_all_lwps (NULL);
+  unstop_all_lwps (0, NULL);
   return 0;
 }
 
@@ -928,7 +945,7 @@ status_pending_p_callback (struct inferior_list_entry *entry, void *arg)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
   ptid_t ptid = * (ptid_t *) arg;
-  struct thread_info *thread = get_lwp_thread (lwp);
+  struct thread_info *thread;
 
   /* Check if we're only interested in events from a specific process
      or its lwps.  */
@@ -941,7 +958,7 @@ status_pending_p_callback (struct inferior_list_entry *entry, void *arg)
   /* If we got a `vCont;t', but we haven't reported a stop yet, do
      report any status pending the LWP may have.  */
   if (thread->last_resume_kind == resume_stop
-      && thread->last_status.kind == TARGET_WAITKIND_STOPPED)
+      && thread->last_status.kind != TARGET_WAITKIND_IGNORE)
     return 0;
 
   return lwp->status_pending_p;
@@ -1113,6 +1130,12 @@ handle_tracepoints (struct lwp_info *lwp)
   struct thread_info *tinfo = get_lwp_thread (lwp);
   int tpoint_related_event = 0;
 
+  /* If this tracepoint hit causes a tracing stop, we'll immediately
+     uninsert tracepoints.  To do this, we temporarily pause all
+     threads, unpatch away, and then unpause threads.  We need to make
+     sure the unpausing doesn't resume LWP too.  */
+  lwp->suspended++;
+
   /* And we need to be sure that any all-threads-stopping doesn't try
      to move threads out of the jump pads, as it could deadlock the
      inferior (LWP could be in the jump pad, maybe even holding the
@@ -1121,10 +1144,17 @@ handle_tracepoints (struct lwp_info *lwp)
   /* Do any necessary step collect actions.  */
   tpoint_related_event |= tracepoint_finished_step (tinfo, lwp->stop_pc);
 
+  tpoint_related_event |= handle_tracepoint_bkpts (tinfo, lwp->stop_pc);
+
   /* See if we just hit a tracepoint and do its main collect
      actions.  */
   tpoint_related_event |= tracepoint_was_hit (tinfo, lwp->stop_pc);
 
+  lwp->suspended--;
+
+  gdb_assert (lwp->suspended == 0);
+  gdb_assert (!stabilizing_threads || lwp->collecting_fast_tracepoint);
+
   if (tpoint_related_event)
     {
       if (debug_threads)
@@ -1135,6 +1165,231 @@ handle_tracepoints (struct lwp_info *lwp)
   return 0;
 }
 
+/* Convenience wrapper.  Returns true if LWP is presently collecting a
+   fast tracepoint.  */
+
+static int
+linux_fast_tracepoint_collecting (struct lwp_info *lwp,
+                                 struct fast_tpoint_collect_status *status)
+{
+  CORE_ADDR thread_area;
+
+  if (the_low_target.get_thread_area == NULL)
+    return 0;
+
+  /* Get the thread area address.  This is used to recognize which
+     thread is which when tracing with the in-process agent library.
+     We don't read anything from the address, and treat it as opaque;
+     it's the address itself that we assume is unique per-thread.  */
+  if ((*the_low_target.get_thread_area) (lwpid_of (lwp), &thread_area) == -1)
+    return 0;
+
+  return fast_tracepoint_collecting (thread_area, lwp->stop_pc, status);
+}
+
+/* The reason we resume in the caller, is because we want to be able
+   to pass lwp->status_pending as WSTAT, and we need to clear
+   status_pending_p before resuming, otherwise, linux_resume_one_lwp
+   refuses to resume.  */
+
+static int
+maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat)
+{
+  struct thread_info *saved_inferior;
+
+  saved_inferior = current_inferior;
+  current_inferior = get_lwp_thread (lwp);
+
+  if ((wstat == NULL
+       || (WIFSTOPPED (*wstat) && WSTOPSIG (*wstat) != SIGTRAP))
+      && supports_fast_tracepoints ()
+      && in_process_agent_loaded ())
+    {
+      struct fast_tpoint_collect_status status;
+      int r;
+
+      if (debug_threads)
+       fprintf (stderr, "\
+Checking whether LWP %ld needs to move out of the jump pad.\n",
+                lwpid_of (lwp));
+
+      r = linux_fast_tracepoint_collecting (lwp, &status);
+
+      if (wstat == NULL
+         || (WSTOPSIG (*wstat) != SIGILL
+             && WSTOPSIG (*wstat) != SIGFPE
+             && WSTOPSIG (*wstat) != SIGSEGV
+             && WSTOPSIG (*wstat) != SIGBUS))
+       {
+         lwp->collecting_fast_tracepoint = r;
+
+         if (r != 0)
+           {
+             if (r == 1 && lwp->exit_jump_pad_bkpt == NULL)
+               {
+                 /* Haven't executed the original instruction yet.
+                    Set breakpoint there, and wait till it's hit,
+                    then single-step until exiting the jump pad.  */
+                 lwp->exit_jump_pad_bkpt
+                   = set_breakpoint_at (status.adjusted_insn_addr, NULL);
+               }
+
+             if (debug_threads)
+               fprintf (stderr, "\
+Checking whether LWP %ld needs to move out of the jump pad...it does\n",
+                lwpid_of (lwp));
+
+             return 1;
+           }
+       }
+      else
+       {
+         /* If we get a synchronous signal while collecting, *and*
+            while executing the (relocated) original instruction,
+            reset the PC to point at the tpoint address, before
+            reporting to GDB.  Otherwise, it's an IPA lib bug: just
+            report the signal to GDB, and pray for the best.  */
+
+         lwp->collecting_fast_tracepoint = 0;
+
+         if (r != 0
+             && (status.adjusted_insn_addr <= lwp->stop_pc
+                 && lwp->stop_pc < status.adjusted_insn_addr_end))
+           {
+             siginfo_t info;
+             struct regcache *regcache;
+
+             /* The si_addr on a few signals references the address
+                of the faulting instruction.  Adjust that as
+                well.  */
+             if ((WSTOPSIG (*wstat) == SIGILL
+                  || WSTOPSIG (*wstat) == SIGFPE
+                  || WSTOPSIG (*wstat) == SIGBUS
+                  || WSTOPSIG (*wstat) == SIGSEGV)
+                 && ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), 0, &info) == 0
+                 /* Final check just to make sure we don't clobber
+                    the siginfo of non-kernel-sent signals.  */
+                 && (uintptr_t) info.si_addr == lwp->stop_pc)
+               {
+                 info.si_addr = (void *) (uintptr_t) status.tpoint_addr;
+                 ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp), 0, &info);
+               }
+
+             regcache = get_thread_regcache (get_lwp_thread (lwp), 1);
+             (*the_low_target.set_pc) (regcache, status.tpoint_addr);
+             lwp->stop_pc = status.tpoint_addr;
+
+             /* Cancel any fast tracepoint lock this thread was
+                holding.  */
+             force_unlock_trace_buffer ();
+           }
+
+         if (lwp->exit_jump_pad_bkpt != NULL)
+           {
+             if (debug_threads)
+               fprintf (stderr,
+                        "Cancelling fast exit-jump-pad: removing bkpt. "
+                        "stopping all threads momentarily.\n");
+
+             stop_all_lwps (1, lwp);
+             cancel_breakpoints ();
+
+             delete_breakpoint (lwp->exit_jump_pad_bkpt);
+             lwp->exit_jump_pad_bkpt = NULL;
+
+             unstop_all_lwps (1, lwp);
+
+             gdb_assert (lwp->suspended >= 0);
+           }
+       }
+    }
+
+  if (debug_threads)
+    fprintf (stderr, "\
+Checking whether LWP %ld needs to move out of the jump pad...no\n",
+            lwpid_of (lwp));
+  return 0;
+}
+
+/* Enqueue one signal in the "signals to report later when out of the
+   jump pad" list.  */
+
+static void
+enqueue_one_deferred_signal (struct lwp_info *lwp, int *wstat)
+{
+  struct pending_signals *p_sig;
+
+  if (debug_threads)
+    fprintf (stderr, "\
+Deferring signal %d for LWP %ld.\n", WSTOPSIG (*wstat), lwpid_of (lwp));
+
+  if (debug_threads)
+    {
+      struct pending_signals *sig;
+
+      for (sig = lwp->pending_signals_to_report;
+          sig != NULL;
+          sig = sig->prev)
+       fprintf (stderr,
+                "   Already queued %d\n",
+                sig->signal);
+
+      fprintf (stderr, "   (no more currently queued signals)\n");
+    }
+
+  p_sig = xmalloc (sizeof (*p_sig));
+  p_sig->prev = lwp->pending_signals_to_report;
+  p_sig->signal = WSTOPSIG (*wstat);
+  memset (&p_sig->info, 0, sizeof (siginfo_t));
+  ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), 0, &p_sig->info);
+
+  lwp->pending_signals_to_report = p_sig;
+}
+
+/* Dequeue one signal from the "signals to report later when out of
+   the jump pad" list.  */
+
+static int
+dequeue_one_deferred_signal (struct lwp_info *lwp, int *wstat)
+{
+  if (lwp->pending_signals_to_report != NULL)
+    {
+      struct pending_signals **p_sig;
+
+      p_sig = &lwp->pending_signals_to_report;
+      while ((*p_sig)->prev != NULL)
+       p_sig = &(*p_sig)->prev;
+
+      *wstat = W_STOPCODE ((*p_sig)->signal);
+      if ((*p_sig)->info.si_signo != 0)
+       ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp), 0, &(*p_sig)->info);
+      free (*p_sig);
+      *p_sig = NULL;
+
+      if (debug_threads)
+       fprintf (stderr, "Reporting deferred signal %d for LWP %ld.\n",
+                WSTOPSIG (*wstat), lwpid_of (lwp));
+
+      if (debug_threads)
+       {
+         struct pending_signals *sig;
+
+         for (sig = lwp->pending_signals_to_report;
+              sig != NULL;
+              sig = sig->prev)
+           fprintf (stderr,
+                    "   Still queued %d\n",
+                    sig->signal);
+
+         fprintf (stderr, "   (no more queued signals)\n");
+       }
+
+      return 1;
+    }
+
+  return 0;
+}
+
 /* Arrange for a breakpoint to be hit again later.  We don't keep the
    SIGTRAP status and don't forward the SIGTRAP signal to the LWP.  We
    will handle the current event, eventually we will resume this LWP,
@@ -1216,6 +1471,21 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
     {
       requested_child = find_lwp_pid (ptid);
 
+      if (!stopping_threads
+         && requested_child->status_pending_p
+         && requested_child->collecting_fast_tracepoint)
+       {
+         enqueue_one_deferred_signal (requested_child,
+                                      &requested_child->status_pending);
+         requested_child->status_pending_p = 0;
+         requested_child->status_pending = 0;
+         linux_resume_one_lwp (requested_child, 0, 0, NULL);
+       }
+
+      if (requested_child->suspended
+         && requested_child->status_pending_p)
+       fatal ("requesting an event out of a suspended child?");
+
       if (requested_child->status_pending_p)
        event_child = requested_child;
     }
@@ -1290,7 +1560,7 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
              /* Cancel the step-over operation --- the thread that
                 started it is gone.  */
              if (finish_step_over (event_child))
-               unstop_all_lwps (event_child);
+               unstop_all_lwps (1, event_child);
              delete_lwp (event_child);
              return lwpid;
            }
@@ -1314,43 +1584,6 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
          continue;
        }
 
-      /* If GDB is not interested in this signal, don't stop other
-        threads, and don't report it to GDB.  Just resume the
-        inferior right away.  We do this for threading-related
-        signals as well as any that GDB specifically requested we
-        ignore.  But never ignore SIGSTOP if we sent it ourselves,
-        and do not ignore signals when stepping - they may require
-        special handling to skip the signal handler.  */
-      /* FIXME drow/2002-06-09: Get signal numbers from the inferior's
-        thread library?  */
-      if (WIFSTOPPED (*wstat)
-         && !event_child->stepping
-         && (
-#if defined (USE_THREAD_DB) && defined (__SIGRTMIN)
-             (current_process ()->private->thread_db != NULL
-              && (WSTOPSIG (*wstat) == __SIGRTMIN
-                  || WSTOPSIG (*wstat) == __SIGRTMIN + 1))
-             ||
-#endif
-             (pass_signals[target_signal_from_host (WSTOPSIG (*wstat))]
-              && !(WSTOPSIG (*wstat) == SIGSTOP
-                   && event_child->stop_expected))))
-       {
-         siginfo_t info, *info_p;
-
-         if (debug_threads)
-           fprintf (stderr, "Ignored signal %d for LWP %ld.\n",
-                    WSTOPSIG (*wstat), lwpid_of (event_child));
-
-         if (ptrace (PTRACE_GETSIGINFO, lwpid_of (event_child), 0, &info) == 0)
-           info_p = &info;
-         else
-           info_p = NULL;
-         linux_resume_one_lwp (event_child, event_child->stepping,
-                               WSTOPSIG (*wstat), info_p);
-         continue;
-       }
-
       if (WIFSTOPPED (*wstat)
          && WSTOPSIG (*wstat) == SIGSTOP
          && event_child->stop_expected)
@@ -1521,6 +1754,12 @@ cancel_breakpoints_callback (struct inferior_list_entry *entry, void *data)
   return 0;
 }
 
+static void
+linux_cancel_breakpoints (void)
+{
+  find_inferior (&all_lwps, cancel_breakpoints_callback, NULL);
+}
+
 /* Select one LWP out of those that have events pending.  */
 
 static void
@@ -1570,30 +1809,137 @@ select_event_lwp (struct lwp_info **orig_lp)
     }
 }
 
-/* Set this inferior LWP's state as "want-stopped".  We won't resume
-   this LWP until the client gives us another action for it.  */
+/* Decrement the suspend count of an LWP.  */
 
-static void
-gdb_wants_lwp_stopped (struct inferior_list_entry *entry)
+static int
+unsuspend_one_lwp (struct inferior_list_entry *entry, void *except)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
-  struct thread_info *thread = get_lwp_thread (lwp);
 
-  /* Most threads are stopped implicitly (all-stop); tag that with
-     signal 0.  The thread being explicitly reported stopped to the
-     client, gets it's status fixed up afterwards.  */
-  thread->last_status.kind = TARGET_WAITKIND_STOPPED;
-  thread->last_status.value.sig = TARGET_SIGNAL_0;
+  /* Ignore EXCEPT.  */
+  if (lwp == except)
+    return 0;
+
+  lwp->suspended--;
+
+  gdb_assert (lwp->suspended >= 0);
+  return 0;
+}
+
+/* Decrement the suspend count of all LWPs, except EXCEPT, if non
+   NULL.  */
 
-  thread->last_resume_kind = resume_stop;
+static void
+unsuspend_all_lwps (struct lwp_info *except)
+{
+  find_inferior (&all_lwps, unsuspend_one_lwp, except);
 }
 
-/* Set all LWP's states as "want-stopped".  */
+static void move_out_of_jump_pad_callback (struct inferior_list_entry *entry);
+static int stuck_in_jump_pad_callback (struct inferior_list_entry *entry,
+                                      void *data);
+static int lwp_running (struct inferior_list_entry *entry, void *data);
+static ptid_t linux_wait_1 (ptid_t ptid,
+                           struct target_waitstatus *ourstatus,
+                           int target_options);
+
+/* Stabilize threads (move out of jump pads).
+
+   If a thread is midway collecting a fast tracepoint, we need to
+   finish the collection and move it out of the jump pad before
+   reporting the signal.
+
+   This avoids recursion while collecting (when a signal arrives
+   midway, and the signal handler itself collects), which would trash
+   the trace buffer.  In case the user set a breakpoint in a signal
+   handler, this avoids the backtrace showing the jump pad, etc..
+   Most importantly, there are certain things we can't do safely if
+   threads are stopped in a jump pad (or in its callee's).  For
+   example:
+
+     - starting a new trace run.  A thread still collecting the
+   previous run, could trash the trace buffer when resumed.  The trace
+   buffer control structures would have been reset but the thread had
+   no way to tell.  The thread could even midway memcpy'ing to the
+   buffer, which would mean that when resumed, it would clobber the
+   trace buffer that had been set for a new run.
+
+     - we can't rewrite/reuse the jump pads for new tracepoints
+   safely.  Say you do tstart while a thread is stopped midway while
+   collecting.  When the thread is later resumed, it finishes the
+   collection, and returns to the jump pad, to execute the original
+   instruction that was under the tracepoint jump at the time the
+   older run had been started.  If the jump pad had been rewritten
+   since for something else in the new run, the thread would now
+   execute the wrong / random instructions.  */
 
 static void
-gdb_wants_all_stopped (void)
+linux_stabilize_threads (void)
 {
-  for_each_inferior (&all_lwps, gdb_wants_lwp_stopped);
+  struct thread_info *save_inferior;
+  struct lwp_info *lwp_stuck;
+
+  lwp_stuck
+    = (struct lwp_info *) find_inferior (&all_lwps,
+                                        stuck_in_jump_pad_callback, NULL);
+  if (lwp_stuck != NULL)
+    {
+      fprintf (stderr, "can't stabilize, LWP %ld is stuck in jump pad\n",
+              lwpid_of (lwp_stuck));
+      return;
+    }
+
+  save_inferior = current_inferior;
+
+  stabilizing_threads = 1;
+
+  /* Kick 'em all.  */
+  for_each_inferior (&all_lwps, move_out_of_jump_pad_callback);
+
+  /* Loop until all are stopped out of the jump pads.  */
+  while (find_inferior (&all_lwps, lwp_running, NULL) != NULL)
+    {
+      struct target_waitstatus ourstatus;
+      struct lwp_info *lwp;
+      ptid_t ptid;
+      int wstat;
+
+      /* Note that we go through the full wait even loop.  While
+        moving threads out of jump pad, we need to be able to step
+        over internal breakpoints and such.  */
+      ptid = linux_wait_1 (minus_one_ptid, &ourstatus, 0);
+
+      if (ourstatus.kind == TARGET_WAITKIND_STOPPED)
+       {
+         lwp = get_thread_lwp (current_inferior);
+
+         /* Lock it.  */
+         lwp->suspended++;
+
+         if (ourstatus.value.sig != TARGET_SIGNAL_0
+             || current_inferior->last_resume_kind == resume_stop)
+           {
+             wstat = W_STOPCODE (target_signal_to_host (ourstatus.value.sig));
+             enqueue_one_deferred_signal (lwp, &wstat);
+           }
+       }
+    }
+
+  find_inferior (&all_lwps, unsuspend_one_lwp, NULL);
+
+  stabilizing_threads = 0;
+
+  current_inferior = save_inferior;
+
+  lwp_stuck
+    = (struct lwp_info *) find_inferior (&all_lwps,
+                                        stuck_in_jump_pad_callback, NULL);
+  if (lwp_stuck != NULL)
+    {
+      if (debug_threads)
+       fprintf (stderr, "couldn't stabilize, LWP %ld got stuck in jump pad\n",
+                lwpid_of (lwp_stuck));
+    }
 }
 
 /* Wait for process, returns status.  */
@@ -1618,6 +1964,8 @@ linux_wait_1 (ptid_t ptid,
     options |= WNOHANG;
 
 retry:
+  bp_explains_trap = 0;
+  trace_event = 0;
   ourstatus->kind = TARGET_WAITKIND_IGNORE;
 
   /* If we were only supposed to resume one thread, only wait for
@@ -1697,7 +2045,7 @@ retry:
 
            }
 
-         return pid_to_ptid (pid);
+         return ptid_of (event_child);
        }
     }
   else
@@ -1760,22 +2108,160 @@ retry:
       /* We have some other signal, possibly a step-over dance was in
         progress, and it should be cancelled too.  */
       step_over_finished = finish_step_over (event_child);
-
-      trace_event = 0;
     }
 
   /* We have all the data we need.  Either report the event to GDB, or
      resume threads and keep waiting for more.  */
 
-  /* Check If GDB would be interested in this event.  If GDB wanted
-     this thread to single step, we always want to report the SIGTRAP,
-     and let GDB handle it.  Watchpoints should always be reported.
-     So should signals we can't explain.  A SIGTRAP we can't explain
-     could be a GDB breakpoint --- we may or not support Z0
-     breakpoints.  If we do, we're be able to handle GDB breakpoints
-     on top of internal breakpoints, by handling the internal
-     breakpoint and still reporting the event to GDB.  If we don't,
-     we're out of luck, GDB won't see the breakpoint hit.  */
+  /* If we're collecting a fast tracepoint, finish the collection and
+     move out of the jump pad before delivering a signal.  See
+     linux_stabilize_threads.  */
+
+  if (WIFSTOPPED (w)
+      && WSTOPSIG (w) != SIGTRAP
+      && supports_fast_tracepoints ()
+      && in_process_agent_loaded ())
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "Got signal %d for LWP %ld.  Check if we need "
+                "to defer or adjust it.\n",
+                WSTOPSIG (w), lwpid_of (event_child));
+
+      /* Allow debugging the jump pad itself.  */
+      if (current_inferior->last_resume_kind != resume_step
+         && maybe_move_out_of_jump_pad (event_child, &w))
+       {
+         enqueue_one_deferred_signal (event_child, &w);
+
+         if (debug_threads)
+           fprintf (stderr,
+                    "Signal %d for LWP %ld deferred (in jump pad)\n",
+                    WSTOPSIG (w), lwpid_of (event_child));
+
+         linux_resume_one_lwp (event_child, 0, 0, NULL);
+         goto retry;
+       }
+    }
+
+  if (event_child->collecting_fast_tracepoint)
+    {
+      if (debug_threads)
+       fprintf (stderr, "\
+LWP %ld was trying to move out of the jump pad (%d).  \
+Check if we're already there.\n",
+                lwpid_of (event_child),
+                event_child->collecting_fast_tracepoint);
+
+      trace_event = 1;
+
+      event_child->collecting_fast_tracepoint
+       = linux_fast_tracepoint_collecting (event_child, NULL);
+
+      if (event_child->collecting_fast_tracepoint != 1)
+       {
+         /* No longer need this breakpoint.  */
+         if (event_child->exit_jump_pad_bkpt != NULL)
+           {
+             if (debug_threads)
+               fprintf (stderr,
+                        "No longer need exit-jump-pad bkpt; removing it."
+                        "stopping all threads momentarily.\n");
+
+             /* Other running threads could hit this breakpoint.
+                We don't handle moribund locations like GDB does,
+                instead we always pause all threads when removing
+                breakpoints, so that any step-over or
+                decr_pc_after_break adjustment is always taken
+                care of while the breakpoint is still
+                inserted.  */
+             stop_all_lwps (1, event_child);
+             cancel_breakpoints ();
+
+             delete_breakpoint (event_child->exit_jump_pad_bkpt);
+             event_child->exit_jump_pad_bkpt = NULL;
+
+             unstop_all_lwps (1, event_child);
+
+             gdb_assert (event_child->suspended >= 0);
+           }
+       }
+
+      if (event_child->collecting_fast_tracepoint == 0)
+       {
+         if (debug_threads)
+           fprintf (stderr,
+                    "fast tracepoint finished "
+                    "collecting successfully.\n");
+
+         /* We may have a deferred signal to report.  */
+         if (dequeue_one_deferred_signal (event_child, &w))
+           {
+             if (debug_threads)
+               fprintf (stderr, "dequeued one signal.\n");
+           }
+         else
+           {
+             if (debug_threads)
+               fprintf (stderr, "no deferred signals.\n");
+
+             if (stabilizing_threads)
+               {
+                 ourstatus->kind = TARGET_WAITKIND_STOPPED;
+                 ourstatus->value.sig = TARGET_SIGNAL_0;
+                 return ptid_of (event_child);
+               }
+           }
+       }
+    }
+
+  /* Check whether GDB would be interested in this event.  */
+
+  /* If GDB is not interested in this signal, don't stop other
+     threads, and don't report it to GDB.  Just resume the inferior
+     right away.  We do this for threading-related signals as well as
+     any that GDB specifically requested we ignore.  But never ignore
+     SIGSTOP if we sent it ourselves, and do not ignore signals when
+     stepping - they may require special handling to skip the signal
+     handler.  */
+  /* FIXME drow/2002-06-09: Get signal numbers from the inferior's
+     thread library?  */
+  if (WIFSTOPPED (w)
+      && current_inferior->last_resume_kind != resume_step
+      && (
+#if defined (USE_THREAD_DB) && defined (__SIGRTMIN)
+         (current_process ()->private->thread_db != NULL
+          && (WSTOPSIG (w) == __SIGRTMIN
+              || WSTOPSIG (w) == __SIGRTMIN + 1))
+         ||
+#endif
+         (pass_signals[target_signal_from_host (WSTOPSIG (w))]
+          && !(WSTOPSIG (w) == SIGSTOP
+               && current_inferior->last_resume_kind == resume_stop))))
+    {
+      siginfo_t info, *info_p;
+
+      if (debug_threads)
+       fprintf (stderr, "Ignored signal %d for LWP %ld.\n",
+                WSTOPSIG (w), lwpid_of (event_child));
+
+      if (ptrace (PTRACE_GETSIGINFO, lwpid_of (event_child), 0, &info) == 0)
+       info_p = &info;
+      else
+       info_p = NULL;
+      linux_resume_one_lwp (event_child, event_child->stepping,
+                           WSTOPSIG (w), info_p);
+      goto retry;
+    }
+
+  /* If GDB wanted this thread to single step, we always want to
+     report the SIGTRAP, and let GDB handle it.  Watchpoints should
+     always be reported.  So should signals we can't explain.  A
+     SIGTRAP we can't explain could be a GDB breakpoint --- we may or
+     not support Z0 breakpoints.  If we do, we're be able to handle
+     GDB breakpoints on top of internal breakpoints, by handling the
+     internal breakpoint and still reporting the event to GDB.  If we
+     don't, we're out of luck, GDB won't see the breakpoint hit.  */
   report_to_gdb = (!maybe_internal_trap
                   || current_inferior->last_resume_kind == resume_step
                   || event_child->stopped_by_watchpoint
@@ -1808,12 +2294,17 @@ retry:
          (*the_low_target.set_pc) (regcache, event_child->stop_pc);
        }
 
-      /* We've finished stepping over a breakpoint.  We've stopped all
-        LWPs momentarily except the stepping one.  This is where we
-        resume them all again.  We're going to keep waiting, so use
-        proceed, which handles stepping over the next breakpoint.  */
+      /* We may have finished stepping over a breakpoint.  If so,
+        we've stopped and suspended all LWPs momentarily except the
+        stepping one.  This is where we resume them all again.  We're
+        going to keep waiting, so use proceed, which handles stepping
+        over the next breakpoint.  */
       if (debug_threads)
        fprintf (stderr, "proceeding all threads.\n");
+
+      if (step_over_finished)
+       unsuspend_all_lwps (event_child);
+
       proceed_all_lwps ();
       goto retry;
     }
@@ -1832,10 +2323,10 @@ retry:
 
   /* Alright, we're going to report a stop.  */
 
-  if (!non_stop)
+  if (!non_stop && !stabilizing_threads)
     {
       /* In all-stop, stop all threads.  */
-      stop_all_lwps ();
+      stop_all_lwps (0, NULL);
 
       /* If we're not waiting for a specific LWP, choose an event LWP
         from among those that have had events.  Giving equal priority
@@ -1857,6 +2348,9 @@ retry:
         See the comment in cancel_breakpoints_callback to find out
         why.  */
       find_inferior (&all_lwps, cancel_breakpoints_callback, event_child);
+
+      /* Stabilize threads (move out of jump pads).  */
+      stabilize_threads ();
     }
   else
     {
@@ -1865,13 +2359,11 @@ retry:
         threads stopped by now anyway.  In non-stop, we need to
         re-resume threads that GDB wanted to be running.  */
       if (step_over_finished)
-       unstop_all_lwps (event_child);
+       unstop_all_lwps (1, event_child);
     }
 
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
-  /* Do this before the gdb_wants_all_stopped calls below, since they
-     always set last_resume_kind to resume_stop.  */
   if (current_inferior->last_resume_kind == resume_stop
       && WSTOPSIG (w) == SIGSTOP)
     {
@@ -1894,27 +2386,12 @@ retry:
 
   gdb_assert (ptid_equal (step_over_bkpt, null_ptid));
 
-  if (!non_stop)
-    {
-      /* From GDB's perspective, all-stop mode always stops all
-        threads implicitly.  Tag all threads as "want-stopped".  */
-      gdb_wants_all_stopped ();
-    }
-  else
-    {
-      /* We're reporting this LWP as stopped.  Update it's
-        "want-stopped" state to what the client wants, until it gets
-        a new resume action.  */
-      gdb_wants_lwp_stopped (&event_child->head);
-    }
-
   if (debug_threads)
     fprintf (stderr, "linux_wait ret = %s, %d, %d\n",
             target_pid_to_str (ptid_of (event_child)),
             ourstatus->kind,
             ourstatus->value.sig);
 
-  get_lwp_thread (event_child)->last_status = *ourstatus;
   return ptid_of (event_child);
 }
 
@@ -1999,6 +2476,12 @@ kill_lwp (unsigned long lwpid, int signo)
   return kill (lwpid, signo);
 }
 
+void
+linux_stop_lwp (struct lwp_info *lwp)
+{
+  send_sigstop (lwp);
+}
+
 static void
 send_sigstop (struct lwp_info *lwp)
 {
@@ -2023,15 +2506,37 @@ send_sigstop (struct lwp_info *lwp)
   kill_lwp (pid, SIGSTOP);
 }
 
-static void
-send_sigstop_callback (struct inferior_list_entry *entry)
+static int
+send_sigstop_callback (struct inferior_list_entry *entry, void *except)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
 
+  /* Ignore EXCEPT.  */
+  if (lwp == except)
+    return 0;
+
   if (lwp->stopped)
-    return;
+    return 0;
 
   send_sigstop (lwp);
+  return 0;
+}
+
+/* Increment the suspend count of an LWP, and stop it, if not stopped
+   yet.  */
+static int
+suspend_and_send_sigstop_callback (struct inferior_list_entry *entry,
+                                  void *except)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+
+  /* Ignore EXCEPT.  */
+  if (lwp == except)
+    return 0;
+
+  lwp->suspended++;
+
+  return send_sigstop_callback (entry, except);
 }
 
 static void
@@ -2142,11 +2647,95 @@ wait_for_sigstop (struct inferior_list_entry *entry)
     }
 }
 
+/* Returns true if LWP ENTRY is stopped in a jump pad, and we can't
+   move it out, because we need to report the stop event to GDB.  For
+   example, if the user puts a breakpoint in the jump pad, it's
+   because she wants to debug it.  */
+
+static int
+stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  struct thread_info *thread = get_lwp_thread (lwp);
+
+  gdb_assert (lwp->suspended == 0);
+  gdb_assert (lwp->stopped);
+
+  /* Allow debugging the jump pad, gdb_collect, etc..  */
+  return (supports_fast_tracepoints ()
+         && in_process_agent_loaded ()
+         && (gdb_breakpoint_here (lwp->stop_pc)
+             || lwp->stopped_by_watchpoint
+             || thread->last_resume_kind == resume_step)
+         && linux_fast_tracepoint_collecting (lwp, NULL));
+}
+
 static void
-stop_all_lwps (void)
+move_out_of_jump_pad_callback (struct inferior_list_entry *entry)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  struct thread_info *thread = get_lwp_thread (lwp);
+  int *wstat;
+
+  gdb_assert (lwp->suspended == 0);
+  gdb_assert (lwp->stopped);
+
+  wstat = lwp->status_pending_p ? &lwp->status_pending : NULL;
+
+  /* Allow debugging the jump pad, gdb_collect, etc.  */
+  if (!gdb_breakpoint_here (lwp->stop_pc)
+      && !lwp->stopped_by_watchpoint
+      && thread->last_resume_kind != resume_step
+      && maybe_move_out_of_jump_pad (lwp, wstat))
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "LWP %ld needs stabilizing (in jump pad)\n",
+                lwpid_of (lwp));
+
+      if (wstat)
+       {
+         lwp->status_pending_p = 0;
+         enqueue_one_deferred_signal (lwp, wstat);
+
+         if (debug_threads)
+           fprintf (stderr,
+                    "Signal %d for LWP %ld deferred "
+                    "(in jump pad)\n",
+                    WSTOPSIG (*wstat), lwpid_of (lwp));
+       }
+
+      linux_resume_one_lwp (lwp, 0, 0, NULL);
+    }
+  else
+    lwp->suspended++;
+}
+
+static int
+lwp_running (struct inferior_list_entry *entry, void *data)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+
+  if (lwp->dead)
+    return 0;
+  if (lwp->stopped)
+    return 0;
+  return 1;
+}
+
+/* Stop all lwps that aren't stopped yet, except EXCEPT, if not NULL.
+   If SUSPEND, then also increase the suspend count of every LWP,
+   except EXCEPT.  */
+
+static void
+stop_all_lwps (int suspend, struct lwp_info *except)
 {
   stopping_threads = 1;
-  for_each_inferior (&all_lwps, send_sigstop_callback);
+
+  if (suspend)
+    find_inferior (&all_lwps, suspend_and_send_sigstop_callback, except);
+  else
+    find_inferior (&all_lwps, send_sigstop_callback, except);
   for_each_inferior (&all_lwps, wait_for_sigstop);
   stopping_threads = 0;
 }
@@ -2160,10 +2749,15 @@ linux_resume_one_lwp (struct lwp_info *lwp,
                      int step, int signal, siginfo_t *info)
 {
   struct thread_info *saved_inferior;
+  int fast_tp_collecting;
 
   if (lwp->stopped == 0)
     return;
 
+  fast_tp_collecting = lwp->collecting_fast_tracepoint;
+
+  gdb_assert (!stabilizing_threads || fast_tp_collecting);
+
   /* Cancel actions that rely on GDB not changing the PC (e.g., the
      user used the "jump" command, or "set $pc = foo").  */
   if (lwp->stop_pc != get_pc (lwp))
@@ -2177,8 +2771,10 @@ linux_resume_one_lwp (struct lwp_info *lwp,
      signal.  Also enqueue the signal if we are waiting to reinsert a
      breakpoint; it will be picked up again below.  */
   if (signal != 0
-      && (lwp->status_pending_p || lwp->pending_signals != NULL
-         || lwp->bp_reinsert != 0))
+      && (lwp->status_pending_p
+         || lwp->pending_signals != NULL
+         || lwp->bp_reinsert != 0
+         || fast_tp_collecting))
     {
       struct pending_signals *p_sig;
       p_sig = xmalloc (sizeof (*p_sig));
@@ -2227,8 +2823,14 @@ linux_resume_one_lwp (struct lwp_info *lwp,
 
       if (lwp->bp_reinsert != 0 && can_hardware_single_step ())
        {
-         if (step == 0)
-           fprintf (stderr, "BAD - reinserting but not stepping.\n");
+         if (fast_tp_collecting == 0)
+           {
+             if (step == 0)
+               fprintf (stderr, "BAD - reinserting but not stepping.\n");
+             if (lwp->suspended)
+               fprintf (stderr, "BAD - reinserting and suspended(%d).\n",
+                        lwp->suspended);
+           }
 
          step = 1;
        }
@@ -2237,6 +2839,33 @@ linux_resume_one_lwp (struct lwp_info *lwp,
       signal = 0;
     }
 
+  if (fast_tp_collecting == 1)
+    {
+      if (debug_threads)
+       fprintf (stderr, "\
+lwp %ld wants to get out of fast tracepoint jump pad (exit-jump-pad-bkpt)\n",
+                lwpid_of (lwp));
+
+      /* Postpone any pending signal.  It was enqueued above.  */
+      signal = 0;
+    }
+  else if (fast_tp_collecting == 2)
+    {
+      if (debug_threads)
+       fprintf (stderr, "\
+lwp %ld wants to get out of fast tracepoint jump pad single-stepping\n",
+                lwpid_of (lwp));
+
+      if (can_hardware_single_step ())
+       step = 1;
+      else
+       fatal ("moving out of jump pad single-stepping"
+              " not implemented on this target");
+
+      /* Postpone any pending signal.  It was enqueued above.  */
+      signal = 0;
+    }
+
   /* If we have while-stepping actions in this thread set it stepping.
      If we have a signal to deliver, it may or may not be set to
      SIG_IGN, we don't know.  Assume so, and allow collecting
@@ -2262,9 +2891,12 @@ linux_resume_one_lwp (struct lwp_info *lwp,
       fprintf (stderr, "  resuming from pc 0x%lx\n", (long) pc);
     }
 
-  /* If we have pending signals, consume one unless we are trying to reinsert
-     a breakpoint.  */
-  if (lwp->pending_signals != NULL && lwp->bp_reinsert == 0)
+  /* If we have pending signals, consume one unless we are trying to
+     reinsert a breakpoint or we're trying to finish a fast tracepoint
+     collect.  */
+  if (lwp->pending_signals != NULL
+      && lwp->bp_reinsert == 0
+      && fast_tp_collecting == 0)
     {
       struct pending_signals **p_sig;
 
@@ -2361,6 +2993,23 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
 
          lwp->resume = &r->resume[ndx];
          thread->last_resume_kind = lwp->resume->kind;
+
+         /* If we had a deferred signal to report, dequeue one now.
+            This can happen if LWP gets more than one signal while
+            trying to get out of a jump pad.  */
+         if (lwp->stopped
+             && !lwp->status_pending_p
+             && dequeue_one_deferred_signal (lwp, &lwp->status_pending))
+           {
+             lwp->status_pending_p = 1;
+
+             if (debug_threads)
+               fprintf (stderr,
+                        "Dequeueing deferred signal %d for LWP %ld, "
+                        "leaving status pending.\n",
+                        WSTOPSIG (lwp->status_pending), lwpid_of (lwp));
+           }
+
          return 0;
        }
     }
@@ -2425,6 +3074,17 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy)
       return 0;
     }
 
+  gdb_assert (lwp->suspended >= 0);
+
+  if (lwp->suspended)
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "Need step over [LWP %ld]? Ignoring, suspended\n",
+                lwpid_of (lwp));
+      return 0;
+    }
+
   if (!lwp->need_step_over)
     {
       if (debug_threads)
@@ -2466,7 +3126,7 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy)
   current_inferior = thread;
 
   /* We can only step over breakpoints we know about.  */
-  if (breakpoint_here (pc))
+  if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc))
     {
       /* Don't step over a breakpoint that GDB expects to hit
         though.  */
@@ -2538,7 +3198,8 @@ start_step_over (struct lwp_info *lwp)
             "Starting step-over on LWP %ld.  Stopping all threads\n",
             lwpid_of (lwp));
 
-  stop_all_lwps ();
+  stop_all_lwps (1, lwp);
+  gdb_assert (lwp->suspended == 0);
 
   if (debug_threads)
     fprintf (stderr, "Done stopping all threads for step-over.\n");
@@ -2554,6 +3215,7 @@ start_step_over (struct lwp_info *lwp)
 
   lwp->bp_reinsert = pc;
   uninsert_breakpoints_at (pc);
+  uninsert_fast_tracepoint_jumps_at (pc);
 
   if (can_hardware_single_step ())
     {
@@ -2590,6 +3252,7 @@ finish_step_over (struct lwp_info *lwp)
       /* Reinsert any breakpoint at LWP->BP_REINSERT.  Note that there
         may be no breakpoint to reinsert there by now.  */
       reinsert_breakpoints_at (lwp->bp_reinsert);
+      reinsert_fast_tracepoint_jumps_at (lwp->bp_reinsert);
 
       lwp->bp_reinsert = 0;
 
@@ -2787,14 +3450,15 @@ linux_resume (struct thread_resume *resume_info, size_t n)
    breakpoint that needs stepping over, we start a step-over operation
    on that particular thread, and leave all others stopped.  */
 
-static void
-proceed_one_lwp (struct inferior_list_entry *entry)
+static int
+proceed_one_lwp (struct inferior_list_entry *entry, void *except)
 {
-  struct lwp_info *lwp;
+  struct lwp_info *lwp = (struct lwp_info *) entry;
   struct thread_info *thread;
   int step;
 
-  lwp = (struct lwp_info *) entry;
+  if (lwp == except)
+    return 0;
 
   if (debug_threads)
     fprintf (stderr,
@@ -2804,7 +3468,7 @@ proceed_one_lwp (struct inferior_list_entry *entry)
     {
       if (debug_threads)
        fprintf (stderr, "   LWP %ld already running\n", lwpid_of (lwp));
-      return;
+      return 0;
     }
 
   thread = get_lwp_thread (lwp);
@@ -2815,7 +3479,7 @@ proceed_one_lwp (struct inferior_list_entry *entry)
       if (debug_threads)
        fprintf (stderr, "   client wants LWP to remain %ld stopped\n",
                 lwpid_of (lwp));
-      return;
+      return 0;
     }
 
   if (lwp->status_pending_p)
@@ -2823,14 +3487,16 @@ proceed_one_lwp (struct inferior_list_entry *entry)
       if (debug_threads)
        fprintf (stderr, "   LWP %ld has pending status, leaving stopped\n",
                 lwpid_of (lwp));
-      return;
+      return 0;
     }
 
+  gdb_assert (lwp->suspended >= 0);
+
   if (lwp->suspended)
     {
       if (debug_threads)
        fprintf (stderr, "   LWP %ld is suspended\n", lwpid_of (lwp));
-      return;
+      return 0;
     }
 
   if (thread->last_resume_kind == resume_stop)
@@ -2856,6 +3522,21 @@ proceed_one_lwp (struct inferior_list_entry *entry)
 
   step = thread->last_resume_kind == resume_step;
   linux_resume_one_lwp (lwp, step, 0, NULL);
+  return 0;
+}
+
+static int
+unsuspend_and_proceed_one_lwp (struct inferior_list_entry *entry, void *except)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+
+  if (lwp == except)
+    return 0;
+
+  lwp->suspended--;
+  gdb_assert (lwp->suspended >= 0);
+
+  return proceed_one_lwp (entry, except);
 }
 
 /* When we finish a step-over, set threads running again.  If there's
@@ -2893,7 +3574,7 @@ proceed_all_lwps (void)
   if (debug_threads)
     fprintf (stderr, "Proceeding, no step-over needed\n");
 
-  for_each_inferior (&all_lwps, proceed_one_lwp);
+  find_inferior (&all_lwps, proceed_one_lwp, NULL);
 }
 
 /* Stopped LWPs that the client wanted to be running, that don't have
@@ -2901,7 +3582,7 @@ proceed_all_lwps (void)
    NULL.  This undoes a stop_all_lwps call.  */
 
 static void
-unstop_all_lwps (struct lwp_info *except)
+unstop_all_lwps (int unsuspend, struct lwp_info *except)
 {
   if (debug_threads)
     {
@@ -2913,14 +3594,10 @@ unstop_all_lwps (struct lwp_info *except)
                 "unstopping all lwps\n");
     }
 
-  /* Make sure proceed_one_lwp doesn't try to resume this thread.  */
-  if (except != NULL)
-    ++except->suspended;
-
-  for_each_inferior (&all_lwps, proceed_one_lwp);
-
-  if (except != NULL)
-    --except->suspended;
+  if (unsuspend)
+    find_inferior (&all_lwps, unsuspend_and_proceed_one_lwp, except);
+  else
+    find_inferior (&all_lwps, proceed_one_lwp, except);
 }
 
 #ifdef HAVE_LINUX_USRREGS
@@ -4036,8 +4713,16 @@ sigchld_handler (int signo)
   int old_errno = errno;
 
   if (debug_threads)
-    /* fprintf is not async-signal-safe, so call write directly.  */
-    write (2, "sigchld_handler\n", sizeof ("sigchld_handler\n") - 1);
+    {
+      do
+       {
+         /* fprintf is not async-signal-safe, so call write
+            directly.  */
+         if (write (2, "sigchld_handler\n",
+                    sizeof ("sigchld_handler\n") - 1) < 0)
+           break; /* just ignore */
+       } while (0);
+    }
 
   if (target_is_async_p ())
     async_file_mark (); /* trigger a linux_wait */
@@ -4241,13 +4926,21 @@ linux_core_of_thread (ptid_t ptid)
     }
 
   p = strchr (content, '(');
-  p = strchr (p, ')') + 2; /* skip ")" and a whitespace. */
 
-  p = strtok_r (p, " ", &ts);
-  for (i = 0; i != 36; ++i)
+  /* Skip ")".  */
+  if (p != NULL)
+    p = strchr (p, ')');
+  if (p != NULL)
+    p++;
+
+  /* If the first field after program name has index 0, then core number is
+     the field with index 36.  There's no constant for that anywhere.  */
+  if (p != NULL)
+    p = strtok_r (p, " ", &ts);
+  for (i = 0; p != NULL && i != 36; ++i)
     p = strtok_r (NULL, " ", &ts);
 
-  if (sscanf (p, "%d", &core) == 0)
+  if (p == NULL || sscanf (p, "%d", &core) == 0)
     core = -1;
 
   free (content);
@@ -4298,9 +4991,63 @@ linux_thread_stopped (struct thread_info *thread)
 /* This exposes stop-all-threads functionality to other modules.  */
 
 static void
-linux_pause_all (void)
+linux_pause_all (int freeze)
 {
-  stop_all_lwps ();
+  stop_all_lwps (freeze, NULL);
+}
+
+/* This exposes unstop-all-threads functionality to other gdbserver
+   modules.  */
+
+static void
+linux_unpause_all (int unfreeze)
+{
+  unstop_all_lwps (unfreeze, NULL);
+}
+
+static int
+linux_prepare_to_access_memory (void)
+{
+  /* Neither ptrace nor /proc/PID/mem allow accessing memory through a
+     running LWP.  */
+  if (non_stop)
+    linux_pause_all (1);
+  return 0;
+}
+
+static void
+linux_unprepare_to_access_memory (void)
+{
+  /* Neither ptrace nor /proc/PID/mem allow accessing memory through a
+     running LWP.  */
+  if (non_stop)
+    linux_unpause_all (1);
+}
+
+static int
+linux_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+                                       CORE_ADDR collector,
+                                       CORE_ADDR lockaddr,
+                                       ULONGEST orig_size,
+                                       CORE_ADDR *jump_entry,
+                                       unsigned char *jjump_pad_insn,
+                                       ULONGEST *jjump_pad_insn_size,
+                                       CORE_ADDR *adjusted_insn_addr,
+                                       CORE_ADDR *adjusted_insn_addr_end)
+{
+  return (*the_low_target.install_fast_tracepoint_jump_pad)
+    (tpoint, tpaddr, collector, lockaddr, orig_size,
+     jump_entry, jjump_pad_insn, jjump_pad_insn_size,
+     adjusted_insn_addr, adjusted_insn_addr_end);
+}
+
+static struct emit_ops *
+linux_emit_ops (void)
+{
+  if (the_low_target.emit_ops != NULL)
+    return (*the_low_target.emit_ops) ();
+  else
+    return NULL;
 }
 
 static struct target_ops linux_target_ops = {
@@ -4315,6 +5062,8 @@ static struct target_ops linux_target_ops = {
   linux_wait,
   linux_fetch_registers,
   linux_store_registers,
+  linux_prepare_to_access_memory,
+  linux_unprepare_to_access_memory,
   linux_read_memory,
   linux_write_memory,
   linux_look_up_symbols,
@@ -4353,8 +5102,13 @@ static struct target_ops linux_target_ops = {
   linux_read_pc,
   linux_write_pc,
   linux_thread_stopped,
+  NULL,
   linux_pause_all,
-  NULL,              /* get_tib_address (Windows OS specific).  */
+  linux_unpause_all,
+  linux_cancel_breakpoints,
+  linux_stabilize_threads,
+  linux_install_fast_tracepoint_jump_pad,
+  linux_emit_ops
 };
 
 static void
This page took 0.087782 seconds and 4 git commands to generate.