gdb:
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-low.c
index f2887e65413f368c37aa22512968f88b5f175114..b4f3d5ad467ac4ce20e19b329b59c8e6763f59ed 100644 (file)
 
 struct inferior_list all_lwps;
 
-/* A list of all unknown processes which receive stop signals.  Some other
-   process will presumably claim each of these as forked children
-   momentarily.  */
+/* A list of all unknown processes which receive stop signals.  Some
+   other process will presumably claim each of these as forked
+   children momentarily.  */
 
-struct inferior_list stopped_pids;
+struct simple_pid_list
+{
+  /* The process ID.  */
+  int pid;
+
+  /* The status as reported by waitpid.  */
+  int status;
+
+  /* Next in chain.  */
+  struct simple_pid_list *next;
+};
+struct simple_pid_list *stopped_pids;
+
+/* Trivial list manipulation functions to keep track of a list of new
+   stopped processes.  */
+
+static void
+add_to_pid_list (struct simple_pid_list **listp, int pid, int status)
+{
+  struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list));
+
+  new_pid->pid = pid;
+  new_pid->status = status;
+  new_pid->next = *listp;
+  *listp = new_pid;
+}
+
+static int
+pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
+{
+  struct simple_pid_list **p;
+
+  for (p = listp; *p != NULL; p = &(*p)->next)
+    if ((*p)->pid == pid)
+      {
+       struct simple_pid_list *next = (*p)->next;
+
+       *statusp = (*p)->status;
+       xfree (*p);
+       *p = next;
+       return 1;
+      }
+  return 0;
+}
 
 /* FIXME this is a bit of a hack, and could be removed.  */
 int stopping_threads;
@@ -353,12 +396,12 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
     {
       ptid_t ptid;
       unsigned long new_pid;
-      int ret, status = W_STOPCODE (SIGSTOP);
+      int ret, status;
 
       ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_child), 0, &new_pid);
 
       /* If we haven't already seen the new PID stop, wait for it now.  */
-      if (! pull_pid_from_list (&stopped_pids, new_pid))
+      if (!pull_pid_from_list (&stopped_pids, new_pid, &status))
        {
          /* The new child has a pending SIGSTOP.  We can't affect it until it
             hits the SIGSTOP, but we're already attached.  */
@@ -598,37 +641,6 @@ linux_create_inferior (char *program, char **allargs)
   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
@@ -674,7 +686,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
      ptrace call on this LWP.  */
   new_lwp->must_set_ptrace_flags = 1;
 
-  if (pid_is_stopped (lwpid))
+  if (linux_proc_pid_is_stopped (lwpid))
     {
       if (debug_threads)
        fprintf (stderr,
@@ -1201,7 +1213,7 @@ retry:
      was reported to us by the kernel.  Save its PID.  */
   if (child == NULL && WIFSTOPPED (*wstatp))
     {
-      add_pid_to_list (&stopped_pids, ret);
+      add_to_pid_list (&stopped_pids, ret, *wstatp);
       goto retry;
     }
   else if (child == NULL)
@@ -2540,6 +2552,15 @@ Check if we're already there.\n",
         why.  */
       find_inferior (&all_lwps, cancel_breakpoints_callback, event_child);
 
+      /* If we were going a step-over, all other threads but the stepping one
+        had been paused in start_step_over, with their suspend counts
+        incremented.  We don't want to do a full unstop/unpause, because we're
+        in all-stop mode (so we want threads stopped), but we still need to
+        unsuspend the other threads, to decrement their `suspended' count
+        back.  */
+      if (step_over_finished)
+       unsuspend_all_lwps (event_child);
+
       /* Stabilize threads (move out of jump pads).  */
       stabilize_threads ();
     }
@@ -3803,145 +3824,11 @@ unstop_all_lwps (int unsuspend, struct lwp_info *except)
     find_inferior (&all_lwps, proceed_one_lwp, except);
 }
 
-#ifdef HAVE_LINUX_USRREGS
-
-int
-register_addr (int regnum)
-{
-  int addr;
-
-  if (regnum < 0 || regnum >= the_low_target.num_regs)
-    error ("Invalid register number %d.", regnum);
-
-  addr = the_low_target.regmap[regnum];
-
-  return addr;
-}
-
-/* Fetch one register.  */
-static void
-fetch_register (struct regcache *regcache, int regno)
-{
-  CORE_ADDR regaddr;
-  int i, size;
-  char *buf;
-  int pid;
-
-  if (regno >= the_low_target.num_regs)
-    return;
-  if ((*the_low_target.cannot_fetch_register) (regno))
-    return;
-
-  regaddr = register_addr (regno);
-  if (regaddr == -1)
-    return;
-
-  size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
-         & -sizeof (PTRACE_XFER_TYPE));
-  buf = alloca (size);
-
-  pid = lwpid_of (get_thread_lwp (current_inferior));
-  for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
-    {
-      errno = 0;
-      *(PTRACE_XFER_TYPE *) (buf + i) =
-       ptrace (PTRACE_PEEKUSER, pid,
-               /* Coerce to a uintptr_t first to avoid potential gcc warning
-                  of coercing an 8 byte integer to a 4 byte pointer.  */
-               (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0);
-      regaddr += sizeof (PTRACE_XFER_TYPE);
-      if (errno != 0)
-       error ("reading register %d: %s", regno, strerror (errno));
-    }
-
-  if (the_low_target.supply_ptrace_register)
-    the_low_target.supply_ptrace_register (regcache, regno, buf);
-  else
-    supply_register (regcache, regno, buf);
-}
-
-/* Store one register.  */
-static void
-store_register (struct regcache *regcache, int regno)
-{
-  CORE_ADDR regaddr;
-  int i, size;
-  char *buf;
-  int pid;
-
-  if (regno >= the_low_target.num_regs)
-    return;
-  if ((*the_low_target.cannot_store_register) (regno))
-    return;
-
-  regaddr = register_addr (regno);
-  if (regaddr == -1)
-    return;
-
-  size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
-         & -sizeof (PTRACE_XFER_TYPE));
-  buf = alloca (size);
-  memset (buf, 0, size);
-
-  if (the_low_target.collect_ptrace_register)
-    the_low_target.collect_ptrace_register (regcache, regno, buf);
-  else
-    collect_register (regcache, regno, buf);
-
-  pid = lwpid_of (get_thread_lwp (current_inferior));
-  for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
-    {
-      errno = 0;
-      ptrace (PTRACE_POKEUSER, pid,
-           /* Coerce to a uintptr_t first to avoid potential gcc warning
-              about coercing an 8 byte integer to a 4 byte pointer.  */
-             (PTRACE_ARG3_TYPE) (uintptr_t) regaddr,
-             (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i));
-      if (errno != 0)
-       {
-         /* At this point, ESRCH should mean the process is
-            already gone, in which case we simply ignore attempts
-            to change its registers.  See also the related
-            comment in linux_resume_one_lwp.  */
-         if (errno == ESRCH)
-           return;
-
-         if ((*the_low_target.cannot_store_register) (regno) == 0)
-           error ("writing register %d: %s", regno, strerror (errno));
-       }
-      regaddr += sizeof (PTRACE_XFER_TYPE);
-    }
-}
-
-/* Fetch all registers, or just one, from the child process.  */
-static void
-usr_fetch_inferior_registers (struct regcache *regcache, int regno)
-{
-  if (regno == -1)
-    for (regno = 0; regno < the_low_target.num_regs; regno++)
-      fetch_register (regcache, regno);
-  else
-    fetch_register (regcache, regno);
-}
-
-/* Store our register values back into the inferior.
-   If REGNO is -1, do this for all registers.
-   Otherwise, REGNO specifies which register (so we can save time).  */
-static void
-usr_store_inferior_registers (struct regcache *regcache, int regno)
-{
-  if (regno == -1)
-    for (regno = 0; regno < the_low_target.num_regs; regno++)
-      store_register (regcache, regno);
-  else
-    store_register (regcache, regno);
-}
-#endif /* HAVE_LINUX_USRREGS */
-
-
 
 #ifdef HAVE_LINUX_REGSETS
 
+#define use_linux_regsets 1
+
 static int
 regsets_fetch_inferior_registers (struct regcache *regcache)
 {
@@ -4101,34 +3988,224 @@ regsets_store_inferior_registers (struct regcache *regcache)
     return 0;
   else
     return 1;
-  return 0;
 }
 
-#endif /* HAVE_LINUX_REGSETS */
+#else /* !HAVE_LINUX_REGSETS */
 
+#define use_linux_regsets 0
+#define regsets_fetch_inferior_registers(regcache) 1
+#define regsets_store_inferior_registers(regcache) 1
 
-void
-linux_fetch_registers (struct regcache *regcache, int regno)
-{
-#ifdef HAVE_LINUX_REGSETS
-  if (regsets_fetch_inferior_registers (regcache) == 0)
-    return;
 #endif
+
+/* Return 1 if register REGNO is supported by one of the regset ptrace
+   calls or 0 if it has to be transferred individually.  */
+
+static int
+linux_register_in_regsets (int regno)
+{
+  unsigned char mask = 1 << (regno % 8);
+  size_t index = regno / 8;
+
+  return (use_linux_regsets
+         && (the_low_target.regset_bitmap == NULL
+             || (the_low_target.regset_bitmap[index] & mask) != 0));
+}
+
 #ifdef HAVE_LINUX_USRREGS
-  usr_fetch_inferior_registers (regcache, regno);
+
+int
+register_addr (int regnum)
+{
+  int addr;
+
+  if (regnum < 0 || regnum >= the_low_target.num_regs)
+    error ("Invalid register number %d.", regnum);
+
+  addr = the_low_target.regmap[regnum];
+
+  return addr;
+}
+
+/* Fetch one register.  */
+static void
+fetch_register (struct regcache *regcache, int regno)
+{
+  CORE_ADDR regaddr;
+  int i, size;
+  char *buf;
+  int pid;
+
+  if (regno >= the_low_target.num_regs)
+    return;
+  if ((*the_low_target.cannot_fetch_register) (regno))
+    return;
+
+  regaddr = register_addr (regno);
+  if (regaddr == -1)
+    return;
+
+  size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
+         & -sizeof (PTRACE_XFER_TYPE));
+  buf = alloca (size);
+
+  pid = lwpid_of (get_thread_lwp (current_inferior));
+  for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
+    {
+      errno = 0;
+      *(PTRACE_XFER_TYPE *) (buf + i) =
+       ptrace (PTRACE_PEEKUSER, pid,
+               /* Coerce to a uintptr_t first to avoid potential gcc warning
+                  of coercing an 8 byte integer to a 4 byte pointer.  */
+               (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0);
+      regaddr += sizeof (PTRACE_XFER_TYPE);
+      if (errno != 0)
+       error ("reading register %d: %s", regno, strerror (errno));
+    }
+
+  if (the_low_target.supply_ptrace_register)
+    the_low_target.supply_ptrace_register (regcache, regno, buf);
+  else
+    supply_register (regcache, regno, buf);
+}
+
+/* Store one register.  */
+static void
+store_register (struct regcache *regcache, int regno)
+{
+  CORE_ADDR regaddr;
+  int i, size;
+  char *buf;
+  int pid;
+
+  if (regno >= the_low_target.num_regs)
+    return;
+  if ((*the_low_target.cannot_store_register) (regno))
+    return;
+
+  regaddr = register_addr (regno);
+  if (regaddr == -1)
+    return;
+
+  size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
+         & -sizeof (PTRACE_XFER_TYPE));
+  buf = alloca (size);
+  memset (buf, 0, size);
+
+  if (the_low_target.collect_ptrace_register)
+    the_low_target.collect_ptrace_register (regcache, regno, buf);
+  else
+    collect_register (regcache, regno, buf);
+
+  pid = lwpid_of (get_thread_lwp (current_inferior));
+  for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
+    {
+      errno = 0;
+      ptrace (PTRACE_POKEUSER, pid,
+           /* Coerce to a uintptr_t first to avoid potential gcc warning
+              about coercing an 8 byte integer to a 4 byte pointer.  */
+             (PTRACE_ARG3_TYPE) (uintptr_t) regaddr,
+             (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i));
+      if (errno != 0)
+       {
+         /* At this point, ESRCH should mean the process is
+            already gone, in which case we simply ignore attempts
+            to change its registers.  See also the related
+            comment in linux_resume_one_lwp.  */
+         if (errno == ESRCH)
+           return;
+
+         if ((*the_low_target.cannot_store_register) (regno) == 0)
+           error ("writing register %d: %s", regno, strerror (errno));
+       }
+      regaddr += sizeof (PTRACE_XFER_TYPE);
+    }
+}
+
+/* Fetch all registers, or just one, from the child process.
+   If REGNO is -1, do this for all registers, skipping any that are
+   assumed to have been retrieved by regsets_fetch_inferior_registers,
+   unless ALL is non-zero.
+   Otherwise, REGNO specifies which register (so we can save time).  */
+static void
+usr_fetch_inferior_registers (struct regcache *regcache, int regno, int all)
+{
+  if (regno == -1)
+    {
+      for (regno = 0; regno < the_low_target.num_regs; regno++)
+       if (all || !linux_register_in_regsets (regno))
+         fetch_register (regcache, regno);
+    }
+  else
+    fetch_register (regcache, regno);
+}
+
+/* Store our register values back into the inferior.
+   If REGNO is -1, do this for all registers, skipping any that are
+   assumed to have been saved by regsets_store_inferior_registers,
+   unless ALL is non-zero.
+   Otherwise, REGNO specifies which register (so we can save time).  */
+static void
+usr_store_inferior_registers (struct regcache *regcache, int regno, int all)
+{
+  if (regno == -1)
+    {
+      for (regno = 0; regno < the_low_target.num_regs; regno++)
+       if (all || !linux_register_in_regsets (regno))
+         store_register (regcache, regno);
+    }
+  else
+    store_register (regcache, regno);
+}
+
+#else /* !HAVE_LINUX_USRREGS */
+
+#define usr_fetch_inferior_registers(regcache, regno, all) do {} while (0)
+#define usr_store_inferior_registers(regcache, regno, all) do {} while (0)
+
 #endif
+
+
+void
+linux_fetch_registers (struct regcache *regcache, int regno)
+{
+  int use_regsets;
+  int all = 0;
+
+  if (regno == -1)
+    {
+      all = regsets_fetch_inferior_registers (regcache);
+      usr_fetch_inferior_registers (regcache, regno, all);
+    }
+  else
+    {
+      use_regsets = linux_register_in_regsets (regno);
+      if (use_regsets)
+       all = regsets_fetch_inferior_registers (regcache);
+      if (!use_regsets || all)
+       usr_fetch_inferior_registers (regcache, regno, 1);
+    }
 }
 
 void
 linux_store_registers (struct regcache *regcache, int regno)
 {
-#ifdef HAVE_LINUX_REGSETS
-  if (regsets_store_inferior_registers (regcache) == 0)
-    return;
-#endif
-#ifdef HAVE_LINUX_USRREGS
-  usr_store_inferior_registers (regcache, regno);
-#endif
+  int use_regsets;
+  int all = 0;
+
+  if (regno == -1)
+    {
+      all = regsets_store_inferior_registers (regcache);
+      usr_store_inferior_registers (regcache, regno, all);
+    }
+  else
+    {
+      use_regsets = linux_register_in_regsets (regno);
+      if (use_regsets)
+       all = regsets_store_inferior_registers (regcache);
+      if (!use_regsets || all)
+       usr_store_inferior_registers (regcache, regno, 1);
+    }
 }
 
 
@@ -4777,6 +4854,12 @@ linux_supports_disable_randomization (void)
 #endif
 }
 
+static int
+linux_supports_agent (void)
+{
+  return 1;
+}
+
 /* Enumerate spufs IDs for process PID.  */
 static int
 spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
@@ -5499,6 +5582,7 @@ static struct target_ops linux_target_ops = {
   linux_supports_disable_randomization,
   linux_get_min_fast_tracepoint_insn_len,
   linux_qxfer_libraries_svr4,
+  linux_supports_agent,
 };
 
 static void
This page took 0.043277 seconds and 4 git commands to generate.