* win32-nat.c (get_relocated_section_addrs): Reinstate.
[deliverable/binutils-gdb.git] / gdb / i386-linux-nat.c
index aa2fa6595abe65554ed3363b028ddd59539b49a0..47bcb236c567ac38576920cdd61cd7005aa5518a 100644 (file)
@@ -1,5 +1,7 @@
-/* Native-dependent code for Linux/x86.
-   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+/* Native-dependent code for GNU/Linux i386.
+
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "inferior.h"
 #include "gdbcore.h"
 #include "regcache.h"
+#include "target.h"
+#include "linux-nat.h"
 
 #include "gdb_assert.h"
+#include "gdb_string.h"
 #include <sys/ptrace.h>
 #include <sys/user.h>
 #include <sys/procfs.h>
 #include <sys/reg.h>
 #endif
 
+#ifndef ORIG_EAX
+#define ORIG_EAX -1
+#endif
+
 #ifdef HAVE_SYS_DEBUGREG_H
 #include <sys/debugreg.h>
 #endif
 /* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 
-/* Prototypes for i387_supply_fsave etc.  */
-#include "i387-nat.h"
-
-/* Defines for XMM0_REGNUM etc. */
+#include "i387-tdep.h"
 #include "i386-tdep.h"
+#include "i386-linux-tdep.h"
 
-/* Prototypes for local functions.  */
-static void dummy_sse_values (void);
-
+/* Defines ps_err_e, struct ps_prochandle.  */
+#include "gdb_proc_service.h"
 \f
 
-/* The register sets used in Linux ELF core-dumps are identical to the
-   register sets in `struct user' that is used for a.out core-dumps,
-   and is also used by `ptrace'.  The corresponding types are
-   `elf_gregset_t' for the general-purpose registers (with
+/* The register sets used in GNU/Linux ELF core-dumps are identical to
+   the register sets in `struct user' that is used for a.out
+   core-dumps, and is also used by `ptrace'.  The corresponding types
+   are `elf_gregset_t' for the general-purpose registers (with
    `elf_greg_t' the type of a single GP register) and `elf_fpregset_t'
    for the floating-point registers.
 
@@ -85,17 +91,25 @@ static int regmap[] =
   EAX, ECX, EDX, EBX,
   UESP, EBP, ESI, EDI,
   EIP, EFL, CS, SS,
-  DS, ES, FS, GS
+  DS, ES, FS, GS,
+  -1, -1, -1, -1,              /* st0, st1, st2, st3 */
+  -1, -1, -1, -1,              /* st4, st5, st6, st7 */
+  -1, -1, -1, -1,              /* fctrl, fstat, ftag, fiseg */
+  -1, -1, -1, -1,              /* fioff, foseg, fooff, fop */
+  -1, -1, -1, -1,              /* xmm0, xmm1, xmm2, xmm3 */
+  -1, -1, -1, -1,              /* xmm4, xmm5, xmm6, xmm6 */
+  -1,                          /* mxcsr */
+  ORIG_EAX
 };
 
 /* Which ptrace request retrieves which registers?
    These apply to the corresponding SET requests as well.  */
+
 #define GETREGS_SUPPLIES(regno) \
   ((0 <= (regno) && (regno) <= 15) || (regno) == I386_LINUX_ORIG_EAX_REGNUM)
-#define GETFPREGS_SUPPLIES(regno) \
-  (FP0_REGNUM <= (regno) && (regno) <= LAST_FPU_CTRL_REGNUM)
+
 #define GETFPXREGS_SUPPLIES(regno) \
-  (FP0_REGNUM <= (regno) && (regno) <= MXCSR_REGNUM)
+  (I386_ST0_REGNUM <= (regno) && (regno) < I386_SSE_NUM_REGS)
 
 /* Does the current host support the GETREGS request?  */
 int have_ptrace_getregs =
@@ -143,155 +157,60 @@ kernel_u_size (void)
 }
 \f
 
-/* Fetching registers directly from the U area, one at a time.  */
-
-/* FIXME: kettenis/2000-03-05: This duplicates code from `inptrace.c'.
-   The problem is that we define FETCH_INFERIOR_REGISTERS since we
-   want to use our own versions of {fetch,store}_inferior_registers
-   that use the GETREGS request.  This means that the code in
-   `infptrace.c' is #ifdef'd out.  But we need to fall back on that
-   code when GDB is running on top of a kernel that doesn't support
-   the GETREGS request.  I want to avoid changing `infptrace.c' right
-   now.  */
-
-#ifndef PT_READ_U
-#define PT_READ_U PTRACE_PEEKUSR
-#endif
-#ifndef PT_WRITE_U
-#define PT_WRITE_U PTRACE_POKEUSR
-#endif
-
-/* Default the type of the ptrace transfer to int.  */
-#ifndef PTRACE_XFER_TYPE
-#define PTRACE_XFER_TYPE int
-#endif
-
-/* Registers we shouldn't try to fetch.  */
-#define OLD_CANNOT_FETCH_REGISTER(regno) ((regno) >= NUM_GREGS)
+/* Accessing registers through the U area, one at a time.  */
 
 /* Fetch one register.  */
 
 static void
 fetch_register (int regno)
 {
-  /* This isn't really an address.  But ptrace thinks of it as one.  */
-  CORE_ADDR regaddr;
-  char mess[128];              /* For messages */
-  register int i;
-  unsigned int offset;         /* Offset of registers within the u area.  */
-  char buf[MAX_REGISTER_RAW_SIZE];
   int tid;
+  int val;
 
-  if (OLD_CANNOT_FETCH_REGISTER (regno))
+  gdb_assert (!have_ptrace_getregs);
+  if (cannot_fetch_register (regno))
     {
-      memset (buf, '\0', REGISTER_RAW_SIZE (regno));   /* Supply zeroes */
-      supply_register (regno, buf);
+      regcache_raw_supply (current_regcache, regno, NULL);
       return;
     }
 
-  /* Overload thread id onto process id */
-  if ((tid = TIDGET (inferior_ptid)) == 0)
-    tid = PIDGET (inferior_ptid);      /* no thread id, just use process id */
+  /* GNU/Linux LWP ID's are process ID's.  */
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
 
-  offset = U_REGS_OFFSET;
+  errno = 0;
+  val = ptrace (PTRACE_PEEKUSER, tid, register_addr (regno, 0), 0);
+  if (errno != 0)
+    error (_("Couldn't read register %s (#%d): %s."), REGISTER_NAME (regno),
+          regno, safe_strerror (errno));
 
-  regaddr = register_addr (regno, offset);
-  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
-    {
-      errno = 0;
-      *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
-                                              (PTRACE_ARG3_TYPE) regaddr, 0);
-      regaddr += sizeof (PTRACE_XFER_TYPE);
-      if (errno != 0)
-       {
-         sprintf (mess, "reading register %s (#%d)", 
-                  REGISTER_NAME (regno), regno);
-         perror_with_name (mess);
-       }
-    }
-  supply_register (regno, buf);
+  regcache_raw_supply (current_regcache, regno, &val);
 }
 
-/* Fetch register values from the inferior.
-   If REGNO is negative, do this for all registers.
-   Otherwise, REGNO specifies which register (so we can save time). */
-
-void
-old_fetch_inferior_registers (int regno)
-{
-  if (regno >= 0)
-    {
-      fetch_register (regno);
-    }
-  else
-    {
-      for (regno = 0; regno < NUM_REGS; regno++)
-       {
-         fetch_register (regno);
-       }
-    }
-}
-
-/* Registers we shouldn't try to store.  */
-#define OLD_CANNOT_STORE_REGISTER(regno) ((regno) >= NUM_GREGS)
-
 /* Store one register. */
 
 static void
 store_register (int regno)
 {
-  /* This isn't really an address.  But ptrace thinks of it as one.  */
-  CORE_ADDR regaddr;
-  char mess[128];              /* For messages */
-  register int i;
-  unsigned int offset;         /* Offset of registers within the u area.  */
   int tid;
+  int val;
 
-  if (OLD_CANNOT_STORE_REGISTER (regno))
-    {
-      return;
-    }
-
-  /* Overload thread id onto process id */
-  if ((tid = TIDGET (inferior_ptid)) == 0)
-    tid = PIDGET (inferior_ptid);      /* no thread id, just use process id */
-
-  offset = U_REGS_OFFSET;
+  gdb_assert (!have_ptrace_getregs);
+  if (cannot_store_register (regno))
+    return;
 
-  regaddr = register_addr (regno, offset);
-  for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
-    {
-      errno = 0;
-      ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
-             *(PTRACE_XFER_TYPE *) & registers[REGISTER_BYTE (regno) + i]);
-      regaddr += sizeof (PTRACE_XFER_TYPE);
-      if (errno != 0)
-       {
-         sprintf (mess, "writing register %s (#%d)", 
-                  REGISTER_NAME (regno), regno);
-         perror_with_name (mess);
-       }
-    }
-}
-
-/* Store our register values back into the inferior.
-   If REGNO is negative, do this for all registers.
-   Otherwise, REGNO specifies which register (so we can save time).  */
+  /* GNU/Linux LWP ID's are process ID's.  */
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
 
-void
-old_store_inferior_registers (int regno)
-{
-  if (regno >= 0)
-    {
-      store_register (regno);
-    }
-  else
-    {
-      for (regno = 0; regno < NUM_REGS; regno++)
-       {
-         store_register (regno);
-       }
-    }
+  errno = 0;
+  regcache_raw_collect (current_regcache, regno, &val);
+  ptrace (PTRACE_POKEUSER, tid, register_addr (regno, 0), val);
+  if (errno != 0)
+    error (_("Couldn't write register %s (#%d): %s."), REGISTER_NAME (regno),
+          regno, safe_strerror (errno));
 }
 \f
 
@@ -307,10 +226,12 @@ supply_gregset (elf_gregset_t *gregsetp)
   elf_greg_t *regp = (elf_greg_t *) gregsetp;
   int i;
 
-  for (i = 0; i < NUM_GREGS; i++)
-    supply_register (i, (char *) (regp + regmap[i]));
+  for (i = 0; i < I386_NUM_GREGS; i++)
+    regcache_raw_supply (current_regcache, i, regp + regmap[i]);
 
-  supply_register (I386_LINUX_ORIG_EAX_REGNUM, (char *) (regp + ORIG_EAX));
+  if (I386_LINUX_ORIG_EAX_REGNUM < NUM_REGS)
+    regcache_raw_supply (current_regcache, I386_LINUX_ORIG_EAX_REGNUM,
+                        regp + ORIG_EAX);
 }
 
 /* Fill register REGNO (if it is a general-purpose register) in
@@ -323,12 +244,14 @@ fill_gregset (elf_gregset_t *gregsetp, int regno)
   elf_greg_t *regp = (elf_greg_t *) gregsetp;
   int i;
 
-  for (i = 0; i < NUM_GREGS; i++)
-    if ((regno == -1 || regno == i))
-      regcache_collect (i, regp + regmap[i]);
+  for (i = 0; i < I386_NUM_GREGS; i++)
+    if (regno == -1 || regno == i)
+      regcache_raw_collect (current_regcache, i, regp + regmap[i]);
 
-  if (regno == -1 || regno == I386_LINUX_ORIG_EAX_REGNUM)
-    regcache_collect (I386_LINUX_ORIG_EAX_REGNUM, regp + ORIG_EAX);
+  if ((regno == -1 || regno == I386_LINUX_ORIG_EAX_REGNUM)
+      && I386_LINUX_ORIG_EAX_REGNUM < NUM_REGS)
+    regcache_raw_collect (current_regcache, I386_LINUX_ORIG_EAX_REGNUM,
+                         regp + ORIG_EAX);
 }
 
 #ifdef HAVE_PTRACE_GETREGS
@@ -351,7 +274,7 @@ fetch_regs (int tid)
          return;
        }
 
-      perror_with_name ("Couldn't get registers");
+      perror_with_name (_("Couldn't get registers"));
     }
 
   supply_gregset (&regs);
@@ -366,12 +289,12 @@ store_regs (int tid, int regno)
   elf_gregset_t regs;
 
   if (ptrace (PTRACE_GETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name ("Couldn't get registers");
+    perror_with_name (_("Couldn't get registers"));
 
   fill_gregset (&regs, regno);
   
   if (ptrace (PTRACE_SETREGS, tid, 0, (int) &regs) < 0)
-    perror_with_name ("Couldn't write registers");
+    perror_with_name (_("Couldn't write registers"));
 }
 
 #else
@@ -390,8 +313,7 @@ static void store_regs (int tid, int regno) {}
 void 
 supply_fpregset (elf_fpregset_t *fpregsetp)
 {
-  i387_supply_fsave ((char *) fpregsetp);
-  dummy_sse_values ();
+  i387_supply_fsave (current_regcache, -1, fpregsetp);
 }
 
 /* Fill register REGNO (if it is a floating-point register) in
@@ -415,7 +337,7 @@ fetch_fpregs (int tid)
   elf_fpregset_t fpregs;
 
   if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name ("Couldn't get floating point status");
+    perror_with_name (_("Couldn't get floating point status"));
 
   supply_fpregset (&fpregs);
 }
@@ -429,12 +351,12 @@ store_fpregs (int tid, int regno)
   elf_fpregset_t fpregs;
 
   if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name ("Couldn't get floating point status");
+    perror_with_name (_("Couldn't get floating point status"));
 
   fill_fpregset (&fpregs, regno);
 
   if (ptrace (PTRACE_SETFPREGS, tid, 0, (int) &fpregs) < 0)
-    perror_with_name ("Couldn't write floating point status");
+    perror_with_name (_("Couldn't write floating point status"));
 }
 
 #else
@@ -455,7 +377,7 @@ static void store_fpregs (int tid, int regno) {}
 void
 supply_fpxregset (elf_fpxregset_t *fpxregsetp)
 {
-  i387_supply_fxsave ((char *) fpxregsetp);
+  i387_supply_fxsave (current_regcache, -1, fpxregsetp);
 }
 
 /* Fill register REGNO (if it is a floating-point or SSE register) in
@@ -488,7 +410,7 @@ fetch_fpxregs (int tid)
          return 0;
        }
 
-      perror_with_name ("Couldn't read floating-point and SSE registers");
+      perror_with_name (_("Couldn't read floating-point and SSE registers"));
     }
 
   supply_fpxregset (&fpxregs);
@@ -515,41 +437,21 @@ store_fpxregs (int tid, int regno)
          return 0;
        }
 
-      perror_with_name ("Couldn't read floating-point and SSE registers");
+      perror_with_name (_("Couldn't read floating-point and SSE registers"));
     }
 
   fill_fpxregset (&fpxregs, regno);
 
   if (ptrace (PTRACE_SETFPXREGS, tid, 0, &fpxregs) == -1)
-    perror_with_name ("Couldn't write floating-point and SSE registers");
+    perror_with_name (_("Couldn't write floating-point and SSE registers"));
 
   return 1;
 }
 
-/* Fill the XMM registers in the register array with dummy values.  For
-   cases where we don't have access to the XMM registers.  I think
-   this is cleaner than printing a warning.  For a cleaner solution,
-   we should gdbarchify the i386 family.  */
-
-static void
-dummy_sse_values (void)
-{
-  /* C doesn't have a syntax for NaN's, so write it out as an array of
-     longs.  */
-  static long dummy[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
-  static long mxcsr = 0x1f80;
-  int reg;
-
-  for (reg = 0; reg < 8; reg++)
-    supply_register (XMM0_REGNUM + reg, (char *) dummy);
-  supply_register (MXCSR_REGNUM, (char *) &mxcsr);
-}
-
 #else
 
 static int fetch_fpxregs (int tid) { return 0; }
 static int store_fpxregs (int tid, int regno) { return 0; }
-static void dummy_sse_values (void) {}
 
 #endif /* HAVE_PTRACE_GETFPXREGS */
 \f
@@ -564,38 +466,43 @@ static void dummy_sse_values (void) {}
 int
 cannot_fetch_register (int regno)
 {
-  if (! have_ptrace_getregs)
-    return OLD_CANNOT_FETCH_REGISTER (regno);
-  return 0;
+  gdb_assert (regno >= 0 && regno < NUM_REGS);
+  return (!have_ptrace_getregs && regmap[regno] == -1);
 }
+
 int
 cannot_store_register (int regno)
 {
-  if (! have_ptrace_getregs)
-    return OLD_CANNOT_STORE_REGISTER (regno);
-  return 0;
+  gdb_assert (regno >= 0 && regno < NUM_REGS);
+  return (!have_ptrace_getregs && regmap[regno] == -1);
 }
 
 /* Fetch register REGNO from the child process.  If REGNO is -1, do
    this for all registers (including the floating point and SSE
    registers).  */
 
-void
-fetch_inferior_registers (int regno)
+static void
+i386_linux_fetch_inferior_registers (int regno)
 {
   int tid;
 
   /* Use the old method of peeking around in `struct user' if the
      GETREGS request isn't available.  */
-  if (! have_ptrace_getregs)
+  if (!have_ptrace_getregs)
     {
-      old_fetch_inferior_registers (regno);
+      int i;
+
+      for (i = 0; i < NUM_REGS; i++)
+       if (regno == -1 || regno == i)
+         fetch_register (i);
+
       return;
     }
 
-  /* Linux LWP ID's are process ID's.  */
-  if ((tid = TIDGET (inferior_ptid)) == 0)
-    tid = PIDGET (inferior_ptid);              /* Not a threaded program.  */
+  /* GNU/Linux LWP ID's are process ID's.  */
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
 
   /* Use the PTRACE_GETFPXREGS request whenever possible, since it
      transfers more registers in one system call, and we'll cache the
@@ -606,9 +513,9 @@ fetch_inferior_registers (int regno)
       fetch_regs (tid);
 
       /* The call above might reset `have_ptrace_getregs'.  */
-      if (! have_ptrace_getregs)
+      if (!have_ptrace_getregs)
        {
-         old_fetch_inferior_registers (-1);
+         i386_linux_fetch_inferior_registers (regno);
          return;
        }
 
@@ -640,28 +547,34 @@ fetch_inferior_registers (int regno)
     }
 
   internal_error (__FILE__, __LINE__,
-                 "Got request for bad register number %d.", regno);
+                 _("Got request for bad register number %d."), regno);
 }
 
 /* Store register REGNO back into the child process.  If REGNO is -1,
    do this for all registers (including the floating point and SSE
    registers).  */
-void
-store_inferior_registers (int regno)
+static void
+i386_linux_store_inferior_registers (int regno)
 {
   int tid;
 
   /* Use the old method of poking around in `struct user' if the
      SETREGS request isn't available.  */
-  if (! have_ptrace_getregs)
+  if (!have_ptrace_getregs)
     {
-      old_store_inferior_registers (regno);
+      int i;
+
+      for (i = 0; i < NUM_REGS; i++)
+       if (regno == -1 || regno == i)
+         store_register (i);
+
       return;
     }
 
-  /* Linux LWP ID's are process ID's.  */
-  if ((tid = TIDGET (inferior_ptid)) == 0)
-    tid = PIDGET (inferior_ptid);      /* Not a threaded program.  */
+  /* GNU/Linux LWP ID's are process ID's.  */
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
 
   /* Use the PTRACE_SETFPXREGS requests whenever possible, since it
      transfers more registers in one system call.  But remember that
@@ -694,10 +607,12 @@ store_inferior_registers (int regno)
     }
 
   internal_error (__FILE__, __LINE__,
-                 "Got request to store bad register number %d.", regno);
+                 _("Got request to store bad register number %d."), regno);
 }
 \f
 
+/* Support for debug registers.  */
+
 static unsigned long
 i386_linux_dr_get (int regnum)
 {
@@ -712,14 +627,14 @@ i386_linux_dr_get (int regnum)
   /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
      ptrace call fails breaks debugging remote targets.  The correct
      way to fix this is to add the hardware breakpoint and watchpoint
-     stuff to the target vectore.  For now, just return zero if the
+     stuff to the target vector.  For now, just return zero if the
      ptrace call fails.  */
   errno = 0;
-  value = ptrace (PT_READ_U, tid,
+  value = ptrace (PTRACE_PEEKUSER, tid,
                  offsetof (struct user, u_debugreg[regnum]), 0);
   if (errno != 0)
 #if 0
-    perror_with_name ("Couldn't read debug register");
+    perror_with_name (_("Couldn't read debug register"));
 #else
     return 0;
 #endif
@@ -738,10 +653,10 @@ i386_linux_dr_set (int regnum, unsigned long value)
   tid = PIDGET (inferior_ptid);
 
   errno = 0;
-  ptrace (PT_WRITE_U, tid,
+  ptrace (PTRACE_POKEUSER, tid,
          offsetof (struct user, u_debugreg[regnum]), value);
   if (errno != 0)
-    perror_with_name ("Couldn't write debug register");
+    perror_with_name (_("Couldn't write debug register"));
 }
 
 void
@@ -773,81 +688,47 @@ i386_linux_dr_get_status (void)
 }
 \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_fpxregset, 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-purpose register set, in elf_gregset_t format
-     2 --- the floating-point register set, in elf_fpregset_t format
-     3 --- the extended floating-point register set, in elf_fpxregset_t format
-
-   REG_ADDR isn't used on Linux.  */
-
-static void
-fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
-                     int which, CORE_ADDR reg_addr)
-{
-  elf_gregset_t gregset;
-  elf_fpregset_t fpregset;
-
-  switch (which)
-    {
-    case 0:
-      if (core_reg_size != sizeof (gregset))
-       warning ("Wrong size gregset 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 in core file.");
-      else
-       {
-         memcpy (&fpregset, core_reg_sect, sizeof (fpregset));
-         supply_fpregset (&fpregset);
-       }
-      break;
-
-#ifdef HAVE_PTRACE_GETFPXREGS
-      {
-       elf_fpxregset_t fpxregset;
-
-      case 3:
-       if (core_reg_size != sizeof (fpxregset))
-         warning ("Wrong size fpxregset in core file.");
-       else
-         {
-           memcpy (&fpxregset, core_reg_sect, sizeof (fpxregset));
-           supply_fpxregset (&fpxregset);
-         }
-       break;
-      }
+/* Called by libthread_db.  Returns a pointer to the thread local
+   storage (or its descriptor).  */
+
+ps_err_e
+ps_get_thread_area (const struct ps_prochandle *ph, 
+                   lwpid_t lwpid, int idx, void **base)
+{
+  /* NOTE: cagney/2003-08-26: The definition of this buffer is found
+     in the kernel header <asm-i386/ldt.h>.  It, after padding, is 4 x
+     4 byte integers in size: `entry_number', `base_addr', `limit',
+     and a bunch of status bits.
+
+     The values returned by this ptrace call should be part of the
+     regcache buffer, and ps_get_thread_area should channel its
+     request through the regcache.  That way remote targets could
+     provide the value using the remote protocol and not this direct
+     call.
+
+     Is this function needed?  I'm guessing that the `base' is the
+     address of a a descriptor that libthread_db uses to find the
+     thread local address base that GDB needs.  Perhaps that
+     descriptor is defined by the ABI.  Anyway, given that
+     libthread_db calls this function without prompting (gdb
+     requesting tls base) I guess it needs info in there anyway.  */
+  unsigned int desc[4];
+  gdb_assert (sizeof (int) == 4);
+
+#ifndef PTRACE_GET_THREAD_AREA
+#define PTRACE_GET_THREAD_AREA 25
 #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;
-    }
+  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid,
+             (void *) idx, (unsigned long) &desc) < 0)
+    return PS_ERR;
+
+  *(int *)base = desc[1];
+  return PS_OK;
 }
 \f
 
-/* The instruction for a Linux system call is:
+/* The instruction for a GNU/Linux system call is:
        int $0x80
    or 0xcd 0x80.  */
 
@@ -856,7 +737,7 @@ static const unsigned char linux_syscall[] = { 0xcd, 0x80 };
 #define LINUX_SYSCALL_LEN (sizeof linux_syscall)
 
 /* The system call number is stored in the %eax register.  */
-#define LINUX_SYSCALL_REGNUM 0 /* %eax */
+#define LINUX_SYSCALL_REGNUM I386_EAX_REGNUM
 
 /* We are specifically interested in the sigreturn and rt_sigreturn
    system calls.  */
@@ -875,8 +756,8 @@ static const unsigned char linux_syscall[] = { 0xcd, 0x80 };
    If STEP is nonzero, single-step it.
    If SIGNAL is nonzero, give it that signal.  */
 
-void
-child_resume (ptid_t ptid, int step, enum target_signal signal)
+static void
+i386_linux_resume (ptid_t ptid, int step, enum target_signal signal)
 {
   int pid = PIDGET (ptid);
 
@@ -891,7 +772,7 @@ child_resume (ptid_t ptid, int step, enum target_signal signal)
   if (step)
     {
       CORE_ADDR pc = read_pc_pid (pid_to_ptid (pid));
-      unsigned char buf[LINUX_SYSCALL_LEN];
+      gdb_byte buf[LINUX_SYSCALL_LEN];
 
       request = PTRACE_SINGLESTEP;
 
@@ -904,7 +785,7 @@ child_resume (ptid_t ptid, int step, enum target_signal signal)
          that's about to be restored, and set the trace flag there.  */
 
       /* First check if PC is at a system call.  */
-      if (read_memory_nobpt (pc, (char *) buf, LINUX_SYSCALL_LEN) == 0
+      if (deprecated_read_memory_nobpt (pc, buf, LINUX_SYSCALL_LEN) == 0
          && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0)
        {
          int syscall = read_register_pid (LINUX_SYSCALL_REGNUM,
@@ -913,7 +794,7 @@ child_resume (ptid_t ptid, int step, enum target_signal signal)
          /* Then check the system call number.  */
          if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn)
            {
-             CORE_ADDR sp = read_register (SP_REGNUM);
+             CORE_ADDR sp = read_register (I386_ESP_REGNUM);
              CORE_ADDR addr = sp;
              unsigned long int eflags;
 
@@ -923,31 +804,45 @@ child_resume (ptid_t ptid, int step, enum target_signal signal)
              /* Set the trace flag in the context that's about to be
                  restored.  */
              addr += LINUX_SIGCONTEXT_EFLAGS_OFFSET;
-             read_memory (addr, (char *) &eflags, 4);
+             read_memory (addr, (gdb_byte *) &eflags, 4);
              eflags |= 0x0100;
-             write_memory (addr, (char *) &eflags, 4);
+             write_memory (addr, (gdb_byte *) &eflags, 4);
            }
        }
     }
 
   if (ptrace (request, pid, 0, target_signal_to_host (signal)) == -1)
-    perror_with_name ("ptrace");
+    perror_with_name (("ptrace"));
 }
-\f
 
-/* Register that we are able to handle Linux ELF core file formats.  */
+static void (*super_post_startup_inferior) (ptid_t ptid);
 
-static struct core_fns linux_elf_core_fns =
+static void
+i386_linux_child_post_startup_inferior (ptid_t ptid)
 {
-  bfd_target_elf_flavour,              /* core_flavour */
-  default_check_format,                        /* check_format */
-  default_core_sniffer,                        /* core_sniffer */
-  fetch_core_registers,                        /* core_read_registers */
-  NULL                                 /* next */
-};
+  i386_cleanup_dregs ();
+  super_post_startup_inferior (ptid);
+}
 
 void
 _initialize_i386_linux_nat (void)
 {
-  add_core_fns (&linux_elf_core_fns);
+  struct target_ops *t;
+
+  /* Fill in the generic GNU/Linux methods.  */
+  t = linux_target ();
+
+  /* Override the default ptrace resume method.  */
+  t->to_resume = i386_linux_resume;
+
+  /* Override the GNU/Linux inferior startup hook.  */
+  super_post_startup_inferior = t->to_post_startup_inferior;
+  t->to_post_startup_inferior = i386_linux_child_post_startup_inferior;
+
+  /* Add our register access methods.  */
+  t->to_fetch_registers = i386_linux_fetch_inferior_registers;
+  t->to_store_registers = i386_linux_store_inferior_registers;
+
+  /* Register the target.  */
+  add_target (t);
 }
This page took 0.073438 seconds and 4 git commands to generate.