* dw2gencfi.c, dw2gencfi.h: New files.
[binutils-gdb.git] / gdb / i386-linux-nat.c
index aac928963431d28d312ffa6b82e624f877e35ee8..cf769d87edceccd2f94b3e22d42776c0fedb8741 100644 (file)
@@ -1,5 +1,6 @@
-/* Native-dependent code for Linux/x86.
-   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+/* Native-dependent code for GNU/Linux x86.
+
+   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -24,6 +25,7 @@
 #include "regcache.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
 #include "gregset.h"
 
 /* Prototypes for i387_supply_fsave etc.  */
-#include "i387-nat.h"
+#include "i387-tdep.h"
 
-/* Prototypes for local functions.  */
-static void dummy_sse_values (void);
+/* Defines for XMM0_REGNUM etc. */
+#include "i386-tdep.h"
 
-/* On Linux, threads are 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.  These definitions should be overridden
-   if thread support is included.  */
+/* Defines I386_LINUX_ORIG_EAX_REGNUM.  */
+#include "i386-linux-tdep.h"
 
-#if !defined (PIDGET)  /* Default definition for PIDGET/TIDGET.  */
-#define PIDGET(PID)    PID
-#define TIDGET(PID)    0
-#endif
+/* Prototypes for local functions.  */
+static void dummy_sse_values (void);
 \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.
 
@@ -93,15 +93,26 @@ 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)
+  ((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)
 
@@ -151,155 +162,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);
+      supply_register (regno, NULL);
       return;
     }
 
-  /* Overload thread id onto process id */
-  if ((tid = TIDGET (inferior_pid)) == 0)
-    tid = inferior_pid;                /* no thread id, just use process id */
-
-  offset = U_REGS_OFFSET;
+  /* GNU/Linux LWP ID's are process ID's.  */
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
 
-  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);
-}
-
-/* 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). */
+  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));
 
-void
-old_fetch_inferior_registers (int regno)
-{
-  if (regno >= 0)
-    {
-      fetch_register (regno);
-    }
-  else
-    {
-      for (regno = 0; regno < NUM_REGS; regno++)
-       {
-         fetch_register (regno);
-       }
-    }
+  supply_register (regno, &val);
 }
 
-/* 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_pid)) == 0)
-    tid = inferior_pid;                /* no thread id, just use process id */
-
-  offset = U_REGS_OFFSET;
-
-  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);
-       }
-    }
-}
+  gdb_assert (!have_ptrace_getregs);
+  if (cannot_store_register (regno))
+    return;
 
-/* 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_collect (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
 
@@ -315,8 +231,11 @@ 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++)
+    supply_register (i, regp + regmap[i]);
+
+  if (I386_LINUX_ORIG_EAX_REGNUM < NUM_REGS)
+    supply_register (I386_LINUX_ORIG_EAX_REGNUM, regp + ORIG_EAX);
 }
 
 /* Fill register REGNO (if it is a general-purpose register) in
@@ -329,9 +248,13 @@ 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))
-      *(regp + regmap[i]) = *(elf_greg_t *) &registers[REGISTER_BYTE (i)];
+  for (i = 0; i < I386_NUM_GREGS; i++)
+    if (regno == -1 || regno == i)
+      regcache_collect (i, regp + regmap[i]);
+
+  if ((regno == -1 || regno == I386_LINUX_ORIG_EAX_REGNUM)
+      && I386_LINUX_ORIG_EAX_REGNUM < NUM_REGS)
+    regcache_collect (I386_LINUX_ORIG_EAX_REGNUM, regp + ORIG_EAX);
 }
 
 #ifdef HAVE_PTRACE_GETREGS
@@ -455,7 +378,7 @@ static void store_fpregs (int tid, int regno) {}
 /* Fill GDB's register array with the floating-point and SSE register
    values in *FPXREGSETP.  */
 
-static void
+void
 supply_fpxregset (elf_fpxregset_t *fpxregsetp)
 {
   i387_supply_fxsave ((char *) fpxregsetp);
@@ -465,7 +388,7 @@ supply_fpxregset (elf_fpxregset_t *fpxregsetp)
    *FPXREGSETP with the value in GDB's register array.  If REGNO is
    -1, do this for all registers.  */
 
-static void
+void
 fill_fpxregset (elf_fpxregset_t *fpxregsetp, int regno)
 {
   i387_fill_fxsave ((char *) fpxregsetp, regno);
@@ -537,15 +460,17 @@ store_fpxregs (int tid, int regno)
 static void
 dummy_sse_values (void)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   /* 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++)
+  for (reg = 0; reg < tdep->num_xmm_regs; reg++)
     supply_register (XMM0_REGNUM + reg, (char *) dummy);
-  supply_register (MXCSR_REGNUM, (char *) &mxcsr);
+  if (tdep->num_xmm_regs > 0)
+    supply_register (MXCSR_REGNUM, (char *) &mxcsr);
 }
 
 #else
@@ -567,16 +492,15 @@ 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
@@ -590,15 +514,21 @@ fetch_inferior_registers (int regno)
 
   /* 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_pid)) == 0)
-    tid = inferior_pid;                /* 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
@@ -609,9 +539,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);
+         fetch_inferior_registers (regno);
          return;
        }
 
@@ -656,15 +586,21 @@ store_inferior_registers (int regno)
 
   /* 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_pid)) == 0)
-    tid = inferior_pid;                /* 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
@@ -701,45 +637,54 @@ store_inferior_registers (int regno)
 }
 \f
 
-static long
+static unsigned long
 i386_linux_dr_get (int regnum)
 {
   int tid;
-  long value;
+  unsigned long value;
 
   /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
      multi-threaded processes here.  For now, pretend there is just
      one thread.  */
-  tid = PIDGET (inferior_pid);
+  tid = PIDGET (inferior_ptid);
 
+  /* 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
+     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");
+#else
+    return 0;
+#endif
 
   return value;
 }
 
 static void
-i386_linux_dr_set (int regnum, long value)
+i386_linux_dr_set (int regnum, unsigned long value)
 {
   int tid;
 
   /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
      multi-threaded processes here.  For now, pretend there is just
      one thread.  */
-  tid = PIDGET (inferior_pid);
+  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");
 }
 
 void
-i386_linux_dr_set_control (long control)
+i386_linux_dr_set_control (unsigned long control)
 {
   i386_linux_dr_set (DR_CONTROL, control);
 }
@@ -760,7 +705,7 @@ i386_linux_dr_reset_addr (int regnum)
   i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
 }
 
-long
+unsigned long
 i386_linux_dr_get_status (void)
 {
   return i386_linux_dr_get (DR_STATUS);
@@ -772,7 +717,7 @@ i386_linux_dr_get_status (void)
 /* 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
+   core-regset.c, because GNU/Linux has *three* different kinds of
    register set notes.  core-regset.c would have to call
    supply_fpxregset, which most platforms don't have.)
 
@@ -785,7 +730,7 @@ i386_linux_dr_get_status (void)
      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.  */
+   REG_ADDR isn't used on GNU/Linux.  */
 
 static void
 fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
@@ -841,7 +786,7 @@ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
 }
 \f
 
-/* The instruction for a Linux system call is:
+/* The instruction for a GNU/Linux system call is:
        int $0x80
    or 0xcd 0x80.  */
 
@@ -870,19 +815,21 @@ static const unsigned char linux_syscall[] = { 0xcd, 0x80 };
    If SIGNAL is nonzero, give it that signal.  */
 
 void
-child_resume (int pid, int step, enum target_signal signal)
+child_resume (ptid_t ptid, int step, enum target_signal signal)
 {
+  int pid = PIDGET (ptid);
+
   int request = PTRACE_CONT;
 
   if (pid == -1)
     /* Resume all threads.  */
     /* I think this only gets used in the non-threaded case, where "resume
-       all threads" and "resume inferior_pid" are the same.  */
-    pid = inferior_pid;
+       all threads" and "resume inferior_ptid" are the same.  */
+    pid = PIDGET (inferior_ptid);
 
   if (step)
     {
-      CORE_ADDR pc = read_pc_pid (pid);
+      CORE_ADDR pc = read_pc_pid (pid_to_ptid (pid));
       unsigned char buf[LINUX_SYSCALL_LEN];
 
       request = PTRACE_SINGLESTEP;
@@ -899,7 +846,8 @@ child_resume (int pid, int step, enum target_signal signal)
       if (read_memory_nobpt (pc, (char *) buf, LINUX_SYSCALL_LEN) == 0
          && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0)
        {
-         int syscall = read_register_pid (LINUX_SYSCALL_REGNUM, pid);
+         int syscall = read_register_pid (LINUX_SYSCALL_REGNUM,
+                                          pid_to_ptid (pid));
 
          /* Then check the system call number.  */
          if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn)
@@ -907,7 +855,7 @@ child_resume (int pid, int step, enum target_signal signal)
              CORE_ADDR sp = read_register (SP_REGNUM);
              CORE_ADDR addr = sp;
              unsigned long int eflags;
-             
+
              if (syscall == SYS_rt_sigreturn)
                addr = read_memory_integer (sp + 8, 4) + 20;
 
@@ -926,7 +874,8 @@ child_resume (int pid, int step, enum target_signal signal)
 }
 \f
 
-/* Register that we are able to handle Linux ELF core file formats.  */
+/* Register that we are able to handle GNU/Linux ELF core file
+   formats.  */
 
 static struct core_fns linux_elf_core_fns =
 {