* spu-tdep.c: Update for unwinder changes.
[deliverable/binutils-gdb.git] / gdb / amd64-linux-nat.c
index c3b5765b842b0125ede3ab5c7da998e13dc501dc..497c4ed52c0a4ef7e1c991e31823915a8031509b 100644 (file)
@@ -1,13 +1,14 @@
 /* Native-dependent code for GNU/Linux x86-64.
 
-   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
    Contributed by Jiri Smid, SuSE Labs.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "inferior.h"
 #include "gdbcore.h"
 #include "regcache.h"
 #include "linux-nat.h"
+#include "amd64-linux-tdep.h"
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
@@ -48,7 +48,6 @@
 #include "gregset.h"
 
 #include "amd64-tdep.h"
-#include "amd64-linux-tdep.h"
 #include "i386-linux-tdep.h"
 #include "amd64-nat.h"
 
@@ -68,7 +67,12 @@ static int amd64_linux_gregset64_reg_offset[] =
   RIP * 8, EFLAGS * 8,         /* %rip, %eflags */
   CS * 8, SS * 8,              /* %cs, %ss */
   DS * 8, ES * 8,              /* %ds, %es */
-  FS * 8, GS * 8               /* %fs, %gs */
+  FS * 8, GS * 8,              /* %fs, %gs */
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  ORIG_RAX * 8
 };
 \f
 
@@ -96,12 +100,6 @@ static int amd64_linux_gregset32_reg_offset[] =
   -1, -1, -1, -1, -1, -1, -1, -1, -1,
   ORIG_RAX * 8                 /* "orig_eax" */
 };
-
-/* Which ptrace request retrieves which registers?
-   These apply to the corresponding SET requests as well.  */
-
-#define GETFPREGS_SUPPLIES(regno) \
-  (FP0_REGNUM <= (regno) && (regno) <= MXCSR_REGNUM)
 \f
 
 /* Transfering the general-purpose registers between GDB, inferiors
@@ -111,9 +109,9 @@ static int amd64_linux_gregset32_reg_offset[] =
    in *GREGSETP.  */
 
 void
-supply_gregset (elf_gregset_t *gregsetp)
+supply_gregset (struct regcache *regcache, const elf_gregset_t *gregsetp)
 {
-  amd64_supply_native_gregset (current_regcache, gregsetp, -1);
+  amd64_supply_native_gregset (regcache, gregsetp, -1);
 }
 
 /* Fill register REGNUM (if it is a general-purpose register) in
@@ -121,42 +119,11 @@ supply_gregset (elf_gregset_t *gregsetp)
    do this for all registers.  */
 
 void
-fill_gregset (elf_gregset_t *gregsetp, int regnum)
-{
-  amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
-}
-
-/* Fetch all general-purpose registers from process/thread TID and
-   store their values in GDB's register cache.  */
-
-static void
-fetch_regs (int tid)
-{
-  elf_gregset_t regs;
-
-  if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
-    perror_with_name ("Couldn't get registers");
-
-  supply_gregset (&regs);
-}
-
-/* Store all valid general-purpose registers in GDB's register cache
-   into the process/thread specified by TID.  */
-
-static void
-store_regs (int tid, int regnum)
+fill_gregset (const struct regcache *regcache,
+             elf_gregset_t *gregsetp, int regnum)
 {
-  elf_gregset_t regs;
-
-  if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
-    perror_with_name ("Couldn't get registers");
-
-  fill_gregset (&regs, regnum);
-
-  if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
-    perror_with_name ("Couldn't write registers");
+  amd64_collect_native_gregset (regcache, gregsetp, regnum);
 }
-\f
 
 /* Transfering floating-point registers between GDB, inferiors and cores.  */
 
@@ -164,9 +131,9 @@ store_regs (int tid, int regnum)
    values in *FPREGSETP.  */
 
 void
-supply_fpregset (elf_fpregset_t *fpregsetp)
+supply_fpregset (struct regcache *regcache, const elf_fpregset_t *fpregsetp)
 {
-  amd64_supply_fxsave (current_regcache, -1, fpregsetp);
+  amd64_supply_fxsave (regcache, -1, fpregsetp);
 }
 
 /* Fill register REGNUM (if it is a floating-point or SSE register) in
@@ -174,40 +141,10 @@ supply_fpregset (elf_fpregset_t *fpregsetp)
    -1, do this for all registers.  */
 
 void
-fill_fpregset (elf_fpregset_t *fpregsetp, int regnum)
+fill_fpregset (const struct regcache *regcache,
+              elf_fpregset_t *fpregsetp, int regnum)
 {
-  amd64_fill_fxsave ((char *) fpregsetp, regnum);
-}
-
-/* Fetch all floating-point registers from process/thread TID and store
-   thier values in GDB's register cache.  */
-
-static void
-fetch_fpregs (int tid)
-{
-  elf_fpregset_t fpregs;
-
-  if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
-    perror_with_name ("Couldn't get floating point status");
-
-  supply_fpregset (&fpregs);
-}
-
-/* Store all valid floating-point registers in GDB's register cache
-   into the process/thread specified by TID.  */
-
-static void
-store_fpregs (int tid, int regnum)
-{
-  elf_fpregset_t fpregs;
-
-  if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
-    perror_with_name ("Couldn't get floating point status");
-
-  fill_fpregset (&fpregs, regnum);
-
-  if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
-    perror_with_name ("Couldn't write floating point status");
+  amd64_collect_fxsave (regcache, regnum, fpregsetp);
 }
 \f
 
@@ -217,9 +154,10 @@ store_fpregs (int tid, int regnum)
    this for all registers (including the floating point and SSE
    registers).  */
 
-void
-fetch_inferior_registers (int regnum)
+static void
+amd64_linux_fetch_inferior_registers (struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int tid;
 
   /* GNU/Linux LWP ID's are process ID's.  */
@@ -227,30 +165,37 @@ fetch_inferior_registers (int regnum)
   if (tid == 0)
     tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
 
-  if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+  if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
-      fetch_regs (tid);
+      elf_gregset_t regs;
+
+      if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
+       perror_with_name (_("Couldn't get registers"));
+
+      amd64_supply_native_gregset (regcache, &regs, -1);
       if (regnum != -1)
        return;
     }
 
-  if (regnum == -1 || GETFPREGS_SUPPLIES (regnum))
+  if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
-      fetch_fpregs (tid);
-      return;
-    }
+      elf_fpregset_t fpregs;
+
+      if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+       perror_with_name (_("Couldn't get floating point status"));
 
-  internal_error (__FILE__, __LINE__,
-                 "Got request for bad register number %d.", regnum);
+      amd64_supply_fxsave (regcache, -1, &fpregs);
+    }
 }
 
 /* Store register REGNUM back into the child process.  If REGNUM is
    -1, do this for all registers (including the floating-point and SSE
    registers).  */
 
-void
-store_inferior_registers (int regnum)
+static void
+amd64_linux_store_inferior_registers (struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int tid;
 
   /* GNU/Linux LWP ID's are process ID's.  */
@@ -258,46 +203,63 @@ store_inferior_registers (int regnum)
   if (tid == 0)
     tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
 
-  if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+  if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
-      store_regs (tid, regnum);
+      elf_gregset_t regs;
+
+      if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
+       perror_with_name (_("Couldn't get registers"));
+
+      amd64_collect_native_gregset (regcache, &regs, regnum);
+
+      if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
+       perror_with_name (_("Couldn't write registers"));
+
       if (regnum != -1)
        return;
     }
 
-  if (regnum == -1 || GETFPREGS_SUPPLIES (regnum))
+  if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
-      store_fpregs (tid, regnum);
+      elf_fpregset_t fpregs;
+
+      if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+       perror_with_name (_("Couldn't get floating point status"));
+
+      amd64_collect_fxsave (regcache, regnum, &fpregs);
+
+      if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
+       perror_with_name (_("Couldn't write floating point status"));
+
       return;
     }
-
-  internal_error (__FILE__, __LINE__,
-                 "Got request to store bad register number %d.", regnum);
 }
 \f
+/* Support for debug registers.  */
+
+static unsigned long amd64_linux_dr[DR_CONTROL + 1];
 
 static unsigned long
-amd64_linux_dr_get (int regnum)
+amd64_linux_dr_get (ptid_t ptid, int regnum)
 {
   int tid;
   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_ptid);
+  tid = TIDGET (ptid);
+  if (tid == 0)
+    tid = PIDGET (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
+     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
@@ -306,47 +268,66 @@ amd64_linux_dr_get (int regnum)
 }
 
 static void
-amd64_linux_dr_set (int regnum, unsigned long value)
+amd64_linux_dr_set (ptid_t ptid, 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_ptid);
+  tid = TIDGET (ptid);
+  if (tid == 0)
+    tid = PIDGET (ptid);
 
   errno = 0;
-  ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
+  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
 amd64_linux_dr_set_control (unsigned long control)
 {
-  amd64_linux_dr_set (DR_CONTROL, control);
+  struct lwp_info *lp;
+  ptid_t ptid;
+
+  amd64_linux_dr[DR_CONTROL] = control;
+  ALL_LWPS (lp, ptid)
+    amd64_linux_dr_set (ptid, DR_CONTROL, control);
 }
 
 void
 amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
+  struct lwp_info *lp;
+  ptid_t ptid;
+
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
 
-  amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
+  amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
+  ALL_LWPS (lp, ptid)
+    amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
 }
 
 void
 amd64_linux_dr_reset_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
-
-  amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
+  amd64_linux_dr_set_addr (regnum, 0);
 }
 
 unsigned long
 amd64_linux_dr_get_status (void)
 {
-  return amd64_linux_dr_get (DR_STATUS);
+  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+}
+
+static void
+amd64_linux_new_thread (ptid_t ptid)
+{
+  int i;
+
+  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+    amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
+
+  amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
 }
 \f
 
@@ -357,35 +338,31 @@ ps_err_e
 ps_get_thread_area (const struct ps_prochandle *ph,
                     lwpid_t lwpid, int idx, void **base)
 {
-  switch (gdbarch_ptr_bit (current_gdbarch) == 32)
+  if (gdbarch_ptr_bit (current_gdbarch) == 32)
     {
-    case bfd_mach_i386_i386:
-    case bfd_mach_i386_i386_intel_syntax:
-      {
-       /* The full structure is found in <asm-i386/ldt.h>.  The
-          second integer is the LDT's base_address and that is used
-          to locate the thread's local storage.  See i386-linux-nat.c
-          more info.  */
-       unsigned int desc[4];
-
-       /* This code assumes that "int" is 32 bits and that
-           GET_THREAD_AREA returns no more than 4 int values.  */
-       gdb_assert (sizeof (int) == 4); 
+      /* The full structure is found in <asm-i386/ldt.h>.  The second
+        integer is the LDT's base_address and that is used to locate
+        the thread's local storage.  See i386-linux-nat.c more
+        info.  */
+      unsigned int desc[4];
+
+      /* This code assumes that "int" is 32 bits and that
+        GET_THREAD_AREA returns no more than 4 int values.  */
+      gdb_assert (sizeof (int) == 4);  
 #ifndef PTRACE_GET_THREAD_AREA
 #define PTRACE_GET_THREAD_AREA 25
 #endif
-       if  (ptrace (PTRACE_GET_THREAD_AREA, 
-                    lwpid, (void *) (long) idx, (unsigned long) &desc) < 0)
-         return PS_ERR;
+      if  (ptrace (PTRACE_GET_THREAD_AREA, 
+                  lwpid, (void *) (long) idx, (unsigned long) &desc) < 0)
+       return PS_ERR;
       
-       /* Extend the value to 64 bits.  Here it's assumed that a
-           "long" and a "void *" are the same.  */
-       (*base) = (void *) (long) desc[1];
-       return PS_OK;
-      }
-
-    case bfd_mach_x86_64:
-    case bfd_mach_x86_64_intel_syntax:
+      /* Extend the value to 64 bits.  Here it's assumed that a "long"
+        and a "void *" are the same.  */
+      (*base) = (void *) (long) desc[1];
+      return PS_OK;
+    }
+  else
+    {
       /* This definition comes from prctl.h, but some kernels may not
          have it.  */
 #ifndef PTRACE_ARCH_PRCTL
@@ -408,21 +385,18 @@ ps_get_thread_area (const struct ps_prochandle *ph,
        default:                   /* Should not happen.  */
          return PS_BADADDR;
        }
-      return PS_ERR;               /* ptrace failed.  */
-      
-    case bfd_mach_i386_i8086:
-      internal_error (__FILE__, __LINE__, "bad i8086 machine");
-    default:
-      internal_error (__FILE__, __LINE__, "bad_switch");
     }
+  return PS_ERR;               /* ptrace failed.  */
 }
 \f
 
-void
-child_post_startup_inferior (ptid_t ptid)
+static void (*super_post_startup_inferior) (ptid_t ptid);
+
+static void
+amd64_linux_child_post_startup_inferior (ptid_t ptid)
 {
   i386_cleanup_dregs ();
-  linux_child_post_startup_inferior (ptid);
+  super_post_startup_inferior (ptid);
 }
 \f
 
@@ -432,12 +406,32 @@ void _initialize_amd64_linux_nat (void);
 void
 _initialize_amd64_linux_nat (void)
 {
+  struct target_ops *t;
+
   amd64_native_gregset32_reg_offset = amd64_linux_gregset32_reg_offset;
   amd64_native_gregset32_num_regs = I386_LINUX_NUM_REGS;
   amd64_native_gregset64_reg_offset = amd64_linux_gregset64_reg_offset;
+  amd64_native_gregset64_num_regs = AMD64_LINUX_NUM_REGS;
 
   gdb_assert (ARRAY_SIZE (amd64_linux_gregset32_reg_offset)
              == amd64_native_gregset32_num_regs);
   gdb_assert (ARRAY_SIZE (amd64_linux_gregset64_reg_offset)
              == amd64_native_gregset64_num_regs);
+
+  /* Fill in the generic GNU/Linux methods.  */
+  t = linux_target ();
+
+  i386_use_watchpoints (t);
+
+  /* Override the GNU/Linux inferior startup hook.  */
+  super_post_startup_inferior = t->to_post_startup_inferior;
+  t->to_post_startup_inferior = amd64_linux_child_post_startup_inferior;
+
+  /* Add our register access methods.  */
+  t->to_fetch_registers = amd64_linux_fetch_inferior_registers;
+  t->to_store_registers = amd64_linux_store_inferior_registers;
+
+  /* Register the target.  */
+  linux_nat_add_target (t);
+  linux_nat_set_new_thread (t, amd64_linux_new_thread);
 }
This page took 0.031229 seconds and 4 git commands to generate.