* win32-i386-low.c: Add 64-bit support.
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-low.c
index 38af9d0beb86513cccae2baab7326d4c1e88baf5..6b7b40f9cd04a43453a8a6346c159ab652c86451 100644 (file)
@@ -39,6 +39,7 @@
 #include <dirent.h>
 #include <sys/stat.h>
 #include <sys/vfs.h>
+#include <sys/uio.h>
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -286,19 +287,6 @@ linux_add_process (int pid, int attached)
   return proc;
 }
 
-/* Remove a process from the common process list,
-   also freeing all private data.  */
-
-static void
-linux_remove_process (struct process_info *process)
-{
-  struct process_info_private *priv = process->private;
-
-  free (priv->arch_private);
-  free (priv);
-  remove_process (process);
-}
-
 /* Wrapper function for waitpid which handles EINTR, and emulates
    __WALL for systems where that is not available.  */
 
@@ -533,8 +521,6 @@ add_lwp (ptid_t ptid)
 
   lwp->head.id = ptid;
 
-  lwp->last_resume_kind = resume_continue;
-
   if (the_low_target.new_thread != NULL)
     lwp->arch_private = the_low_target.new_thread ();
 
@@ -643,7 +629,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
        of a new thread that is being created.
        In this case we should ignore that SIGSTOP and resume the
        process.  This is handled below by setting stop_expected = 1,
-       and the fact that add_lwp sets last_resume_kind ==
+       and the fact that add_thread sets last_resume_kind ==
        resume_continue.
 
      2) This is the first thread (the process thread), and we're attaching
@@ -679,19 +665,17 @@ linux_attach_lwp (unsigned long lwpid)
 int
 linux_attach (unsigned long pid)
 {
-  struct lwp_info *lwp;
-
   linux_attach_lwp_1 (pid, 1);
-
   linux_add_process (pid, 1);
 
   if (!non_stop)
     {
-      /* Don't ignore the initial SIGSTOP if we just attached to this
-        process.  It will be collected by wait shortly.  */
-      lwp = (struct lwp_info *) find_inferior_id (&all_lwps,
-                                                 ptid_build (pid, pid, 0));
-      lwp->last_resume_kind = resume_stop;
+      struct thread_info *thread;
+
+     /* Don't ignore the initial SIGSTOP if we just attached to this
+       process.  It will be collected by wait shortly.  */
+      thread = find_thread_ptid (ptid_build (pid, pid, 0));
+      thread->last_resume_kind = resume_stop;
     }
 
   return 0;
@@ -807,11 +791,9 @@ linux_kill (int pid)
       lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     } while (lwpid > 0 && WIFSTOPPED (wstat));
 
-#ifdef USE_THREAD_DB
-  thread_db_free (process, 0);
-#endif
   delete_lwp (lwp);
-  linux_remove_process (process);
+
+  the_target->mourn (process);
   return 0;
 }
 
@@ -892,7 +874,7 @@ linux_detach (int pid)
     return -1;
 
 #ifdef USE_THREAD_DB
-  thread_db_free (process, 1);
+  thread_db_detach (process);
 #endif
 
   current_inferior =
@@ -900,10 +882,29 @@ linux_detach (int pid)
 
   delete_all_breakpoints ();
   find_inferior (&all_threads, linux_detach_one_lwp, &pid);
-  linux_remove_process (process);
+
+  the_target->mourn (process);
   return 0;
 }
 
+static void
+linux_mourn (struct process_info *process)
+{
+  struct process_info_private *priv;
+
+#ifdef USE_THREAD_DB
+  thread_db_mourn (process);
+#endif
+
+  /* Freeing all private data.  */
+  priv = process->private;
+  free (priv->arch_private);
+  free (priv);
+  process->private = NULL;
+
+  remove_process (process);
+}
+
 static void
 linux_join (int pid)
 {
@@ -954,7 +955,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 (lwp->last_resume_kind == resume_stop
+  if (thread->last_resume_kind == resume_stop
       && thread->last_status.kind == TARGET_WAITKIND_STOPPED)
     return 0;
 
@@ -1116,6 +1117,39 @@ retry:
   return child;
 }
 
+/* This function should only be called if the LWP got a SIGTRAP.
+
+   Handle any tracepoint steps or hits.  Return true if a tracepoint
+   event was handled, 0 otherwise.  */
+
+static int
+handle_tracepoints (struct lwp_info *lwp)
+{
+  struct thread_info *tinfo = get_lwp_thread (lwp);
+  int tpoint_related_event = 0;
+
+  /* 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
+     lock.)  */
+
+  /* Do any necessary step collect actions.  */
+  tpoint_related_event |= tracepoint_finished_step (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);
+
+  if (tpoint_related_event)
+    {
+      if (debug_threads)
+       fprintf (stderr, "got a tracepoint event\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,
@@ -1343,7 +1377,7 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
            fprintf (stderr, "Expected stop.\n");
          event_child->stop_expected = 0;
 
-         should_stop = (event_child->last_resume_kind == resume_stop
+         should_stop = (current_inferior->last_resume_kind == resume_stop
                         || stopping_threads);
 
          if (!should_stop)
@@ -1408,14 +1442,15 @@ static int
 count_events_callback (struct inferior_list_entry *entry, void *data)
 {
   struct lwp_info *lp = (struct lwp_info *) entry;
+  struct thread_info *thread = get_lwp_thread (lp);
   int *count = data;
 
   gdb_assert (count != NULL);
 
   /* Count only resumed LWPs that have a SIGTRAP event pending that
      should be reported to GDB.  */
-  if (get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
-      && lp->last_resume_kind != resume_stop
+  if (thread->last_status.kind == TARGET_WAITKIND_IGNORE
+      && thread->last_resume_kind != resume_stop
       && lp->status_pending_p
       && WIFSTOPPED (lp->status_pending)
       && WSTOPSIG (lp->status_pending) == SIGTRAP
@@ -1431,9 +1466,10 @@ static int
 select_singlestep_lwp_callback (struct inferior_list_entry *entry, void *data)
 {
   struct lwp_info *lp = (struct lwp_info *) entry;
+  struct thread_info *thread = get_lwp_thread (lp);
 
-  if (get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
-      && lp->last_resume_kind == resume_step
+  if (thread->last_status.kind == TARGET_WAITKIND_IGNORE
+      && thread->last_resume_kind == resume_step
       && lp->status_pending_p)
     return 1;
   else
@@ -1447,13 +1483,14 @@ static int
 select_event_lwp_callback (struct inferior_list_entry *entry, void *data)
 {
   struct lwp_info *lp = (struct lwp_info *) entry;
+  struct thread_info *thread = get_lwp_thread (lp);
   int *selector = data;
 
   gdb_assert (selector != NULL);
 
   /* Select only resumed LWPs that have a SIGTRAP event pending. */
-  if (lp->last_resume_kind != resume_stop
-      && get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
+  if (thread->last_resume_kind != resume_stop
+      && thread->last_status.kind == TARGET_WAITKIND_IGNORE
       && lp->status_pending_p
       && WIFSTOPPED (lp->status_pending)
       && WSTOPSIG (lp->status_pending) == SIGTRAP
@@ -1468,6 +1505,7 @@ static int
 cancel_breakpoints_callback (struct inferior_list_entry *entry, void *data)
 {
   struct lwp_info *lp = (struct lwp_info *) entry;
+  struct thread_info *thread = get_lwp_thread (lp);
   struct lwp_info *event_lp = data;
 
   /* Leave the LWP that has been elected to receive a SIGTRAP alone.  */
@@ -1485,8 +1523,8 @@ cancel_breakpoints_callback (struct inferior_list_entry *entry, void *data)
      delete or disable the breakpoint, but the LWP will have already
      tripped on it.  */
 
-  if (lp->last_resume_kind != resume_stop
-      && get_lwp_thread (lp)->last_status.kind == TARGET_WAITKIND_IGNORE
+  if (thread->last_resume_kind != resume_stop
+      && thread->last_status.kind == TARGET_WAITKIND_IGNORE
       && lp->status_pending_p
       && WIFSTOPPED (lp->status_pending)
       && WSTOPSIG (lp->status_pending) == SIGTRAP
@@ -1563,7 +1601,7 @@ gdb_wants_lwp_stopped (struct inferior_list_entry *entry)
   thread->last_status.kind = TARGET_WAITKIND_STOPPED;
   thread->last_status.value.sig = TARGET_SIGNAL_0;
 
-  lwp->last_resume_kind = resume_stop;
+  thread->last_resume_kind = resume_stop;
 }
 
 /* Set all LWP's states as "want-stopped".  */
@@ -1588,6 +1626,7 @@ linux_wait_1 (ptid_t ptid,
   int bp_explains_trap;
   int maybe_internal_trap;
   int report_to_gdb;
+  int trace_event;
 
   /* Translate generic target options into linux options.  */
   options = __WALL;
@@ -1656,14 +1695,7 @@ retry:
     {
       if (WIFEXITED (w) || WIFSIGNALED (w))
        {
-         int pid = pid_of (event_child);
-         struct process_info *process = find_process_pid (pid);
-
-#ifdef USE_THREAD_DB
-         thread_db_free (process, 0);
-#endif
          delete_lwp (event_child);
-         linux_remove_process (process);
 
          current_inferior = NULL;
 
@@ -1726,6 +1758,11 @@ retry:
       /* Now invoke the callbacks of any internal breakpoints there.  */
       check_breakpoints (event_child->stop_pc);
 
+      /* Handle tracepoint data collecting.  This may overflow the
+        trace buffer, and cause a tracing stop, removing
+        breakpoints.  */
+      trace_event = handle_tracepoints (event_child);
+
       if (bp_explains_trap)
        {
          /* If we stepped or ran into an internal breakpoint, we've
@@ -1743,6 +1780,8 @@ 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
@@ -1758,9 +1797,9 @@ retry:
      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
-                  || event_child->last_resume_kind == resume_step
+                  || current_inferior->last_resume_kind == resume_step
                   || event_child->stopped_by_watchpoint
-                  || (!step_over_finished && !bp_explains_trap)
+                  || (!step_over_finished && !bp_explains_trap && !trace_event)
                   || gdb_breakpoint_here (event_child->stop_pc));
 
   /* We found no reason GDB would want us to stop.  We either hit one
@@ -1774,6 +1813,8 @@ retry:
            fprintf (stderr, "Hit a gdbserver breakpoint.\n");
          if (step_over_finished)
            fprintf (stderr, "Step-over finished.\n");
+         if (trace_event)
+           fprintf (stderr, "Tracepoint event.\n");
        }
 
       /* We're not reporting this breakpoint to GDB, so apply the
@@ -1799,7 +1840,7 @@ retry:
 
   if (debug_threads)
     {
-      if (event_child->last_resume_kind == resume_step)
+      if (current_inferior->last_resume_kind == resume_step)
        fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
       if (event_child->stopped_by_watchpoint)
        fprintf (stderr, "Stopped by watchpoint.\n");
@@ -1851,14 +1892,16 @@ retry:
 
   /* Do this before the gdb_wants_all_stopped calls below, since they
      always set last_resume_kind to resume_stop.  */
-  if (event_child->last_resume_kind == resume_stop && WSTOPSIG (w) == SIGSTOP)
+  if (current_inferior->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 = TARGET_SIGNAL_0;
     }
-  else if (event_child->last_resume_kind == resume_stop && WSTOPSIG (w) != SIGSTOP)
+  else if (current_inferior->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.  */
@@ -2134,6 +2177,15 @@ linux_resume_one_lwp (struct lwp_info *lwp,
   if (lwp->stopped == 0)
     return;
 
+  /* 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))
+    {
+      /* Collecting 'while-stepping' actions doesn't make sense
+        anymore.  */
+      release_while_stepping_state_list (get_lwp_thread (lwp));
+    }
+
   /* If we have pending signals or status, and a new signal, enqueue the
      signal.  Also enqueue the signal if we are waiting to reinsert a
      breakpoint; it will be picked up again below.  */
@@ -2198,6 +2250,24 @@ linux_resume_one_lwp (struct lwp_info *lwp,
       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
+     while-stepping into a signal handler.  A possible smart thing to
+     do would be to set an internal breakpoint at the signal return
+     address, continue, and carry on catching this while-stepping
+     action only when that breakpoint is hit.  A future
+     enhancement.  */
+  if (get_lwp_thread (lwp)->while_stepping != NULL
+      && can_hardware_single_step ())
+    {
+      if (debug_threads)
+       fprintf (stderr,
+                "lwp %ld has a while-stepping action -> forcing step.\n",
+                lwpid_of (lwp));
+      step = 1;
+    }
+
   if (debug_threads && the_low_target.get_pc != NULL)
     {
       struct regcache *regcache = get_thread_regcache (current_inferior, 1);
@@ -2290,7 +2360,7 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
              && (ptid_get_pid (ptid) == pid_of (lwp))))
        {
          if (r->resume[ndx].kind == resume_stop
-             && lwp->last_resume_kind == resume_stop)
+             && thread->last_resume_kind == resume_stop)
            {
              if (debug_threads)
                fprintf (stderr, "already %s LWP %ld at GDB's request\n",
@@ -2303,7 +2373,7 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
            }
 
          lwp->resume = &r->resume[ndx];
-         lwp->last_resume_kind = lwp->resume->kind;
+         thread->last_resume_kind = lwp->resume->kind;
          return 0;
        }
     }
@@ -2341,6 +2411,7 @@ static int
 need_step_over_p (struct inferior_list_entry *entry, void *dummy)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
+  struct thread_info *thread;
   struct thread_info *saved_inferior;
   CORE_ADDR pc;
 
@@ -2356,7 +2427,9 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy)
       return 0;
     }
 
-  if (lwp->last_resume_kind == resume_stop)
+  thread = get_lwp_thread (lwp);
+
+  if (thread->last_resume_kind == resume_stop)
     {
       if (debug_threads)
        fprintf (stderr,
@@ -2403,7 +2476,7 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy)
     }
 
   saved_inferior = current_inferior;
-  current_inferior = get_lwp_thread (lwp);
+  current_inferior = thread;
 
   /* We can only step over breakpoints we know about.  */
   if (breakpoint_here (pc))
@@ -2731,6 +2804,7 @@ static void
 proceed_one_lwp (struct inferior_list_entry *entry)
 {
   struct lwp_info *lwp;
+  struct thread_info *thread;
   int step;
 
   lwp = (struct lwp_info *) entry;
@@ -2746,7 +2820,9 @@ proceed_one_lwp (struct inferior_list_entry *entry)
       return;
     }
 
-  if (lwp->last_resume_kind == resume_stop)
+  thread = get_lwp_thread (lwp);
+
+  if (thread->last_resume_kind == resume_stop)
     {
       if (debug_threads)
        fprintf (stderr, "   client wants LWP %ld stopped\n", lwpid_of (lwp));
@@ -2768,7 +2844,7 @@ proceed_one_lwp (struct inferior_list_entry *entry)
       return;
     }
 
-  step = lwp->last_resume_kind == resume_step;
+  step = thread->last_resume_kind == resume_step;
   linux_resume_one_lwp (lwp, step, 0, NULL);
 }
 
@@ -2977,14 +3053,15 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
   struct regset_info *regset;
   int saw_general_regs = 0;
   int pid;
+  struct iovec iov;
 
   regset = target_regsets;
 
   pid = lwpid_of (get_thread_lwp (current_inferior));
   while (regset->size >= 0)
     {
-      void *buf;
-      int res;
+      void *buf, *data;
+      int nt_type, res;
 
       if (regset->size == 0 || disabled_regsets[regset - target_regsets])
        {
@@ -2993,10 +3070,21 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
        }
 
       buf = xmalloc (regset->size);
+
+      nt_type = regset->nt_type;
+      if (nt_type)
+       {
+         iov.iov_base = buf;
+         iov.iov_len = regset->size;
+         data = (void *) &iov;
+       }
+      else
+       data = buf;
+
 #ifndef __sparc__
-      res = ptrace (regset->get_request, pid, 0, buf);
+      res = ptrace (regset->get_request, pid, nt_type, data);
 #else
-      res = ptrace (regset->get_request, pid, buf, 0);
+      res = ptrace (regset->get_request, pid, data, nt_type);
 #endif
       if (res < 0)
        {
@@ -3034,14 +3122,15 @@ regsets_store_inferior_registers (struct regcache *regcache)
   struct regset_info *regset;
   int saw_general_regs = 0;
   int pid;
+  struct iovec iov;
 
   regset = target_regsets;
 
   pid = lwpid_of (get_thread_lwp (current_inferior));
   while (regset->size >= 0)
     {
-      void *buf;
-      int res;
+      void *buf, *data;
+      int nt_type, res;
 
       if (regset->size == 0 || disabled_regsets[regset - target_regsets])
        {
@@ -3054,10 +3143,21 @@ regsets_store_inferior_registers (struct regcache *regcache)
       /* First fill the buffer with the current register set contents,
         in case there are any items in the kernel's regset that are
         not in gdbserver's regcache.  */
+
+      nt_type = regset->nt_type;
+      if (nt_type)
+       {
+         iov.iov_base = buf;
+         iov.iov_len = regset->size;
+         data = (void *) &iov;
+       }
+      else
+       data = buf;
+
 #ifndef __sparc__
-      res = ptrace (regset->get_request, pid, 0, buf);
+      res = ptrace (regset->get_request, pid, nt_type, data);
 #else
-      res = ptrace (regset->get_request, pid, buf, 0);
+      res = ptrace (regset->get_request, pid, &iov, data);
 #endif
 
       if (res == 0)
@@ -3067,9 +3167,9 @@ regsets_store_inferior_registers (struct regcache *regcache)
 
          /* Only now do we write the register set.  */
 #ifndef __sparc__
-         res = ptrace (regset->set_request, pid, 0, buf);
+         res = ptrace (regset->set_request, pid, nt_type, data);
 #else
-         res = ptrace (regset->set_request, pid, buf, 0);
+         res = ptrace (regset->set_request, pid, data, nt_type);
 #endif
        }
 
@@ -3937,6 +4037,10 @@ linux_async (int enable)
 {
   int previous = (linux_event_pipe[0] != -1);
 
+  if (debug_threads)
+    fprintf (stderr, "linux_async (%d), previous=%d\n",
+            enable, previous);
+
   if (previous != enable)
     {
       sigset_t mask;
@@ -4133,11 +4237,59 @@ linux_core_of_thread (ptid_t ptid)
   return core;
 }
 
+static void
+linux_process_qsupported (const char *query)
+{
+  if (the_low_target.process_qsupported != NULL)
+    the_low_target.process_qsupported (query);
+}
+
+static int
+linux_supports_tracepoints (void)
+{
+  if (*the_low_target.supports_tracepoints == NULL)
+    return 0;
+
+  return (*the_low_target.supports_tracepoints) ();
+}
+
+static CORE_ADDR
+linux_read_pc (struct regcache *regcache)
+{
+  if (the_low_target.get_pc == NULL)
+    return 0;
+
+  return (*the_low_target.get_pc) (regcache);
+}
+
+static void
+linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+  gdb_assert (the_low_target.set_pc != NULL);
+
+  (*the_low_target.set_pc) (regcache, pc);
+}
+
+static int
+linux_thread_stopped (struct thread_info *thread)
+{
+  return get_thread_lwp (thread)->stopped;
+}
+
+/* This exposes stop-all-threads functionality to other modules.  */
+
+static void
+linux_pause_all (void)
+{
+  stop_all_lwps ();
+}
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_attach,
   linux_kill,
   linux_detach,
+  linux_mourn,
   linux_join,
   linux_thread_alive,
   linux_resume,
@@ -4176,7 +4328,14 @@ static struct target_ops linux_target_ops = {
 #else
   NULL,
 #endif
-  linux_core_of_thread
+  linux_core_of_thread,
+  linux_process_qsupported,
+  linux_supports_tracepoints,
+  linux_read_pc,
+  linux_write_pc,
+  linux_thread_stopped,
+  linux_pause_all,
+  NULL,              /* get_tib_address (Windows OS specific).  */
 };
 
 static void
This page took 0.032246 seconds and 4 git commands to generate.