import gdb-2000-01-17 snapshot
[deliverable/binutils-gdb.git] / gdb / i386-linux-nat.c
index 657315332712a4769e9bb20a7dce07af88c8ad8b..dddb218ba6aabea2e8ab17100ad66857dfb60294 100644 (file)
@@ -34,6 +34,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include <sys/reg.h>
 #endif
 
+/*
+ * Some systems (Linux) may have threads implemented as pseudo-processes, 
+ * in which case we may be tracing more than one process at a time.
+ * In that case, inferior_pid will contain the main process ID and the 
+ * individual thread (process) id mashed together.  These macros are 
+ * used to separate them out.  The definitions may be overridden in tm.h
+ */
+
+#if !defined (PIDGET)  /* Default definition for PIDGET/TIDGET.  */
+#define PIDGET(PID)    PID
+#define TIDGET(PID)    0
+#endif
+
 /* This is a duplicate of the table in i386-xdep.c. */
 
 static int regmap[] = 
@@ -58,6 +71,13 @@ static int regmap[] =
    file may or may not define it, and even if it is defined, the
    kernel will return EIO if it's running on a pre-SSE processor.
 
+   PTRACE_GETXFPREGS is a Cygnus invention, since we wrote our own
+   Linux kernel patch for SSE support.  That patch may or may not
+   actually make it into the official distribution.  If you find that
+   years have gone by since this stuff was added, and Linux isn't
+   using PTRACE_GETXFPREGS, that means that our patch didn't make it,
+   and you can delete this, and the related code.
+
    My instinct is to attach this to some architecture- or
    target-specific data structure, but really, a particular GDB
    process can only run on top of one kernel at a time.  So it's okay
@@ -121,12 +141,12 @@ fill_gregset (gregset_t *gregsetp,
 {
   if (regno == -1)
     convert_to_gregset (gregsetp, registers, 0);
-  else
+  else if (regno >= 0 && regno < NUM_GREGS)
     {
       signed char valid[NUM_GREGS];
       memset (valid, 0, sizeof (valid));
       valid[regno] = 1;
-      convert_to_gregset (gregsetp, valid, valid);
+      convert_to_gregset (gregsetp, registers, valid);
     }
 }
 
@@ -134,12 +154,12 @@ fill_gregset (gregset_t *gregsetp,
 /* Read the general registers from the process, and store them
    in registers[].  */
 static void
-fetch_regs ()
+fetch_regs (int tid)
 {
   int ret, regno;
   gregset_t buf;
 
-  ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int) &buf);
+  ret = ptrace (PTRACE_GETREGS, tid, 0, (int) &buf);
   if (ret < 0)
     {
       warning ("Couldn't get registers");
@@ -153,12 +173,12 @@ fetch_regs ()
 /* Set the inferior's general registers to the values in registers[]
    --- but only those registers marked as valid.  */
 static void
-store_regs ()
+store_regs (int tid)
 {
   int ret, regno;
   gregset_t buf;
 
-  ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int) &buf);
+  ret = ptrace (PTRACE_GETREGS, tid, 0, (int) &buf);
   if (ret < 0)
     {
       warning ("Couldn't get registers");
@@ -167,7 +187,7 @@ store_regs ()
 
   convert_to_gregset (&buf, registers, register_valid);
 
-  ret = ptrace (PTRACE_SETREGS, inferior_pid, 0, (int)buf);
+  ret = ptrace (PTRACE_SETREGS, tid, 0, (int)buf);
   if (ret < 0)
     {
       warning ("Couldn't write registers");
@@ -278,12 +298,12 @@ fill_fpregset (fpregset_t *fpregsetp,
 /* Get the whole floating point state of the process and store the
    floating point stack into registers[].  */
 static void
-fetch_fpregs ()
+fetch_fpregs (int tid)
 {
   int ret, regno;
   fpregset_t buf;
 
-  ret = ptrace (PTRACE_GETFPREGS, inferior_pid,        0, (int) &buf);
+  ret = ptrace (PTRACE_GETFPREGS, tid, 0, (int) &buf);
   if (ret < 0)
     {
       warning ("Couldn't get floating point status");
@@ -299,12 +319,12 @@ fetch_fpregs ()
 /* Set the inferior's floating-point registers to the values in
    registers[] --- but only those registers marked valid.  */
 static void
-store_fpregs ()
+store_fpregs (int tid)
 {
   int ret;
   fpregset_t buf;
 
-  ret = ptrace (PTRACE_GETFPREGS, inferior_pid,        0, (int) &buf);
+  ret = ptrace (PTRACE_GETFPREGS, tid, 0, (int) &buf);
   if (ret < 0)
     {
       warning ("Couldn't get floating point status");
@@ -313,7 +333,7 @@ store_fpregs ()
 
   convert_to_fpregset (&buf, registers, register_valid);
 
-  ret = ptrace (PTRACE_SETFPREGS, inferior_pid, 0, (int) &buf);
+  ret = ptrace (PTRACE_SETFPREGS, tid, 0, (int) &buf);
   if (ret < 0)
     {
       warning ("Couldn't write floating point status");
@@ -325,6 +345,13 @@ store_fpregs ()
 /* Transfering floating-point and SSE registers to and from GDB.  */
 
 
+/* PTRACE_GETXFPREGS is a Cygnus invention, since we wrote our own
+   Linux kernel patch for SSE support.  That patch may or may not
+   actually make it into the official distribution.  If you find that
+   years have gone by since this code was added, and Linux isn't using
+   PTRACE_GETXFPREGS, that means that our patch didn't make it, and
+   you can delete this code.  */
+
 #ifdef HAVE_PTRACE_GETXFPREGS
 static void
 supply_xfpregset (struct user_xfpregs_struct *xfpregs)
@@ -413,7 +440,7 @@ convert_to_xfpregset (struct user_xfpregs_struct *xfpregs,
 /* Make a PTRACE_GETXFPREGS request, and supply all the register
    values that yields to GDB.  */
 static int
-fetch_xfpregs ()
+fetch_xfpregs (int tid)
 {
   int ret;
   struct user_xfpregs_struct xfpregs;
@@ -421,7 +448,7 @@ fetch_xfpregs ()
   if (! have_ptrace_getxfpregs) 
     return 0;
 
-  ret = ptrace (PTRACE_GETXFPREGS, inferior_pid, 0, &xfpregs);
+  ret = ptrace (PTRACE_GETXFPREGS, tid, 0, &xfpregs);
   if (ret == -1)
     {
       if (errno == EIO)
@@ -442,7 +469,7 @@ fetch_xfpregs ()
 /* Send all the valid register values in GDB's register file covered
    by the PTRACE_SETXFPREGS request to the inferior.  */
 static int
-store_xfpregs ()
+store_xfpregs (int tid)
 {
   int ret;
   struct user_xfpregs_struct xfpregs;
@@ -450,7 +477,7 @@ store_xfpregs ()
   if (! have_ptrace_getxfpregs)
     return 0;
 
-  ret = ptrace (PTRACE_GETXFPREGS, inferior_pid, 0, &xfpregs);
+  ret = ptrace (PTRACE_GETXFPREGS, tid, 0, &xfpregs);
   if (ret == -1)
     {
       if (errno == EIO)
@@ -465,7 +492,7 @@ store_xfpregs ()
 
   convert_to_xfpregset (&xfpregs, registers, register_valid);
 
-  if (ptrace (PTRACE_SETXFPREGS, inferior_pid, 0, &xfpregs) < 0)
+  if (ptrace (PTRACE_SETXFPREGS, tid, 0, &xfpregs) < 0)
     {
       warning ("Couldn't write floating-point and SSE registers.");
       return 0;
@@ -497,8 +524,8 @@ dummy_sse_values ()
 
 /* Stub versions of the above routines, for systems that don't have
    PTRACE_GETXFPREGS.  */
-static int store_xfpregs () { return 0; }
-static int fetch_xfpregs () { return 0; }
+static int store_xfpregs (int tid) { return 0; }
+static int fetch_xfpregs (int tid) { return 0; }
 static void dummy_sse_values () {}
 
 #endif
@@ -514,27 +541,33 @@ static void dummy_sse_values () {}
 void
 fetch_inferior_registers (int regno)
 {
+  /* linux lwp id's are process id's */
+  int tid;
+
+  if ((tid = TIDGET (inferior_pid)) == 0)
+    tid = inferior_pid;                /* not a threaded program */
+
   /* Use the xfpregs requests whenever possible, since they transfer
      more registers in one system call, and we'll cache the results.
      But remember that fetch_xfpregs can fail, and return zero.  */
   if (regno == -1)
     {
-      fetch_regs ();
-      if (fetch_xfpregs ())
+      fetch_regs (tid);
+      if (fetch_xfpregs (tid))
        return;
-      fetch_fpregs ();
+      fetch_fpregs (tid);
       return;
     }
 
   if (GETREGS_SUPPLIES (regno))
     {
-      fetch_regs ();
+      fetch_regs (tid);
       return;
     }
 
   if (GETXFPREGS_SUPPLIES (regno))
     {
-      if (fetch_xfpregs ())
+      if (fetch_xfpregs (tid))
        return;
 
       /* Either our processor or our kernel doesn't support the SSE
@@ -543,7 +576,7 @@ fetch_inferior_registers (int regno)
         more graceful to handle differences in the register set using
         gdbarch.  Until then, this will at least make things work
         plausibly.  */
-      fetch_fpregs ();
+      fetch_fpregs (tid);
       dummy_sse_values ();
       return;
     }
@@ -563,32 +596,38 @@ void
 store_inferior_registers (regno)
      int regno;
 {
+  /* linux lwp id's are process id's */
+  int tid;
+
+  if ((tid = TIDGET (inferior_pid)) == 0)
+    tid = inferior_pid;                /* not a threaded program */
+
   /* Use the xfpregs requests whenever possible, since they transfer
      more registers in one system call.  But remember that
-     fetch_xfpregs can fail, and return zero.  */
+     store_xfpregs can fail, and return zero.  */
   if (regno == -1)
     {
-      store_regs ();
-      if (store_xfpregs ())
+      store_regs (tid);
+      if (store_xfpregs (tid))
        return;
-      store_fpregs ();
+      store_fpregs (tid);
       return;
     }
 
   if (GETREGS_SUPPLIES (regno))
     {
-      store_regs ();
+      store_regs (tid);
       return;
     }
 
   if (GETXFPREGS_SUPPLIES (regno))
     {
-      if (store_xfpregs ())
+      if (store_xfpregs (tid))
        return;
 
       /* Either our processor or our kernel doesn't support the SSE
         registers, so just write the FP registers in the traditional way.  */
-      store_fpregs ();
+      store_fpregs (tid);
       return;
     }
 
@@ -597,6 +636,91 @@ store_inferior_registers (regno)
 }
 
 
+\f
+/* Interpreting register set info found in core files.  */
+
+/* Provide registers to GDB from a core file.
+
+   (We can't use the generic version of this function in
+   core-regset.c, because Linux has *three* different kinds of
+   register set notes.  core-regset.c would have to call
+   supply_xfpregset, which most platforms don't have.)
+
+   CORE_REG_SECT points to an array of bytes, which are the contents
+   of a `note' from a core file which BFD thinks might contain
+   register contents.  CORE_REG_SIZE is its size.
+
+   WHICH says which register set corelow suspects this is:
+   0 --- the general register set, in gregset format
+   2 --- the floating-point register set, in fpregset format
+   3 --- the extended floating-point register set, in struct
+         user_xfpregs_struct format
+
+   DUMMY isn't used on Linux.  */
+static void
+i386_linux_fetch_core_registers (char *core_reg_sect,
+                                unsigned core_reg_size,
+                                int which,
+                                CORE_ADDR dummy)
+{
+  gregset_t gregset;
+  fpregset_t fpregset;
+
+  switch (which)
+    {
+    case 0:
+      if (core_reg_size != sizeof (gregset))
+       warning ("wrong size gregset struct in core file");
+      else
+       {
+         memcpy (&gregset, core_reg_sect, sizeof (gregset));
+         supply_gregset (&gregset);
+       }
+      break;
+
+    case 2:
+      if (core_reg_size != sizeof (fpregset))
+       warning ("wrong size fpregset struct in core file");
+      else
+       {
+         memcpy (&fpregset, core_reg_sect, sizeof (fpregset));
+         supply_fpregset (&fpregset);
+       }
+      break;
+
+#ifdef HAVE_PTRACE_GETXFPREGS
+      {
+       struct user_xfpregs_struct xfpregset;
+      case 3:
+       if (core_reg_size != sizeof (struct user_xfpregs_struct))
+         warning ("wrong size user_xfpregs_struct in core file");
+       else
+         {
+           memcpy (&xfpregset, core_reg_sect, sizeof (xfpregset));
+           supply_xfpregset (&xfpregset);
+         }
+       break;
+      }
+#endif
+
+    default:
+      /* We've covered all the kinds of registers we know about here,
+         so this must be something we wouldn't know what to do with
+         anyway.  Just ignore it.  */
+      break;
+    }
+}
+
+
+static struct core_fns i386_linux_nat_core_fns =
+{
+  bfd_target_elf_flavour,              /* core_flavour */
+  default_check_format,                        /* check_format */
+  default_core_sniffer,                        /* core_sniffer */
+  i386_linux_fetch_core_registers,     /* core_read_registers */
+  NULL                                 /* next */
+};
+
 \f
 /* Calling functions in shared libraries.  */
 
@@ -686,3 +810,13 @@ i386_linux_skip_solib_resolver (CORE_ADDR pc)
 
   return 0;
 }
+
+
+\f
+/* Module initialization.  */
+
+void
+_initialize_i386_linux_nat ()
+{
+  add_core_fns (&i386_linux_nat_core_fns);
+}
This page took 0.029862 seconds and 4 git commands to generate.