Multi-target support
[deliverable/binutils-gdb.git] / gdb / amd64-linux-nat.c
index fca05c8a5aea5c7bd024a56fa5e521ec1f2dbb32..27748ff9860081f577de143b1b197ab314dc2e4f 100644 (file)
@@ -1,14 +1,13 @@
 /* Native-dependent code for GNU/Linux x86-64.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
+   Copyright (C) 2001-2020 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., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, 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"
-#include <sys/ptrace.h>
-#include <sys/debugreg.h>
-#include <sys/syscall.h>
-#include <sys/procfs.h>
+#include "elf/common.h"
+#include <sys/uio.h>
+#include "nat/gdb_ptrace.h"
 #include <asm/prctl.h>
-/* FIXME ezannoni-2003-07-09: we need <sys/reg.h> to be included after
-   <asm/ptrace.h> because the latter redefines FS and GS for no apparent
-   reason, and those definitions don't match the ones that libpthread_db
-   uses, which come from <sys/reg.h>.  */
-/* ezannoni-2003-07-09: I think this is fixed. The extraneous defs have
-   been removed from ptrace.h in the kernel.  However, better safe than
-   sorry.  */
-#include <asm/ptrace.h>
 #include <sys/reg.h>
-#include "gdb_proc_service.h"
-
-/* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
+#include "gdb_proc_service.h"
 
+#include "amd64-nat.h"
 #include "amd64-tdep.h"
+#include "amd64-linux-tdep.h"
 #include "i386-linux-tdep.h"
-#include "amd64-nat.h"
+#include "gdbsupport/x86-xstate.h"
 
-/* Mapping between the general-purpose registers in GNU/Linux x86-64
-   `struct user' format and GDB's register cache layout.  */
+#include "x86-linux-nat.h"
+#include "nat/linux-ptrace.h"
+#include "nat/amd64-linux-siginfo.h"
+
+/* This definition comes from prctl.h.  Kernels older than 2.5.64
+   do not have it.  */
+#ifndef PTRACE_ARCH_PRCTL
+#define PTRACE_ARCH_PRCTL      30
+#endif
 
-static int amd64_linux_gregset64_reg_offset[] =
+struct amd64_linux_nat_target final : public x86_linux_nat_target
 {
-  RAX * 8, RBX * 8,            /* %rax, %rbx */
-  RCX * 8, RDX * 8,            /* %rcx, %rdx */
-  RSI * 8, RDI * 8,            /* %rsi, %rdi */
-  RBP * 8, RSP * 8,            /* %rbp, %rsp */
-  R8 * 8, R9 * 8,              /* %r8 ... */
-  R10 * 8, R11 * 8,
-  R12 * 8, R13 * 8,
-  R14 * 8, R15 * 8,            /* ... %r15 */
-  RIP * 8, EFLAGS * 8,         /* %rip, %eflags */
-  CS * 8, SS * 8,              /* %cs, %ss */
-  DS * 8, ES * 8,              /* %ds, %es */
-  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
+  /* Add our register access methods.  */
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+
+  bool low_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, int direction)
+    override;
 };
-\f
+
+static amd64_linux_nat_target the_amd64_linux_nat_target;
 
 /* Mapping between the general-purpose registers in GNU/Linux x86-64
    `struct user' format and GDB's register cache layout for GNU/Linux
@@ -100,20 +79,91 @@ static int amd64_linux_gregset32_reg_offset[] =
   -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                 /* "orig_eax" */
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1,                /* MPX registers BND0 ... BND3.  */
+  -1, -1,                        /* MPX registers BNDCFGU, BNDSTATUS.  */
+  -1, -1, -1, -1, -1, -1, -1, -1, /* k0 ... k7 (AVX512)  */
+  -1, -1, -1, -1, -1, -1, -1, -1, /* zmm0 ... zmm7 (AVX512)  */
+  -1,                            /* PKEYS register PKRU  */
+  ORIG_RAX * 8                   /* "orig_eax"  */
 };
 \f
 
 /* Transfering the general-purpose registers between GDB, inferiors
    and core files.  */
 
+/* See amd64_collect_native_gregset.  This linux specific version handles
+   issues with negative EAX values not being restored correctly upon syscall
+   return when debugging 32-bit targets.  It has no effect on 64-bit
+   targets.  */
+
+static void
+amd64_linux_collect_native_gregset (const struct regcache *regcache,
+                                   void *gregs, int regnum)
+{
+  amd64_collect_native_gregset (regcache, gregs, regnum);
+
+  struct gdbarch *gdbarch = regcache->arch ();
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    {
+      /* Sign extend EAX value to avoid potential syscall restart
+        problems.  
+
+        On Linux, when a syscall is interrupted by a signal, the
+        (kernel function implementing the) syscall may return
+        -ERESTARTSYS when a signal occurs.  Doing so indicates that
+        the syscall is restartable.  Then, depending on settings
+        associated with the signal handler, and after the signal
+        handler is called, the kernel can then either return -EINTR
+        or it can cause the syscall to be restarted.  We are
+        concerned with the latter case here.
+        
+        On (32-bit) i386, the status (-ERESTARTSYS) is placed in the
+        EAX register.  When debugging a 32-bit process from a 64-bit
+        (amd64) GDB, the debugger fetches 64-bit registers even
+        though the process being debugged is only 32-bit.  The
+        register cache is only 32 bits wide though; GDB discards the
+        high 32 bits when placing 64-bit values in the 32-bit
+        regcache.  Normally, this is not a problem since the 32-bit
+        process should only care about the lower 32-bit portions of
+        these registers.  That said, it can happen that the 64-bit
+        value being restored will be different from the 64-bit value
+        that was originally retrieved from the kernel.  The one place
+        (that we know of) where it does matter is in the kernel's
+        syscall restart code.  The kernel's code for restarting a
+        syscall after a signal expects to see a negative value
+        (specifically -ERESTARTSYS) in the 64-bit RAX register in
+        order to correctly cause a syscall to be restarted.
+        
+        The call to amd64_collect_native_gregset, above, is setting
+        the high 32 bits of RAX (and other registers too) to 0.  For
+        syscall restart, we need to sign extend EAX so that RAX will
+        appear as a negative value when EAX is set to -ERESTARTSYS. 
+        This in turn will cause the signal handling code in the
+        kernel to recognize -ERESTARTSYS which will in turn cause the
+        syscall to be restarted.
+
+        The test case gdb.base/interrupt.exp tests for this problem.
+        Without this sign extension code in place, it'll show
+        a number of failures when testing against unix/-m32.  */
+
+      if (regnum == -1 || regnum == I386_EAX_REGNUM)
+       {
+         void *ptr = ((gdb_byte *) gregs 
+                      + amd64_linux_gregset32_reg_offset[I386_EAX_REGNUM]);
+
+         *(int64_t *) ptr = *(int32_t *) ptr;
+       }
+    }
+}
+
 /* Fill GDB's register cache with the general-purpose register values
    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,9 +171,10 @@ supply_gregset (elf_gregset_t *gregsetp)
    do this for all registers.  */
 
 void
-fill_gregset (elf_gregset_t *gregsetp, int regnum)
+fill_gregset (const struct regcache *regcache,
+             elf_gregset_t *gregsetp, int regnum)
 {
-  amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
+  amd64_linux_collect_native_gregset (regcache, gregsetp, regnum);
 }
 
 /* Transfering floating-point registers between GDB, inferiors and cores.  */
@@ -132,9 +183,9 @@ fill_gregset (elf_gregset_t *gregsetp, 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
@@ -142,9 +193,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_collect_fxsave (current_regcache, regnum, fpregsetp);
+  amd64_collect_fxsave (regcache, regnum, fpregsetp);
 }
 \f
 
@@ -154,36 +206,83 @@ fill_fpregset (elf_fpregset_t *fpregsetp, int regnum)
    this for all registers (including the floating point and SSE
    registers).  */
 
-static void
-amd64_linux_fetch_inferior_registers (int regnum)
+void
+amd64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = regcache->arch ();
   int tid;
 
   /* GNU/Linux LWP ID's are process ID's.  */
-  tid = TIDGET (inferior_ptid);
+  tid = regcache->ptid ().lwp ();
   if (tid == 0)
-    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
+    tid = regcache->ptid ().pid (); /* Not a threaded program.  */
 
-  if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+  if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
       elf_gregset_t regs;
 
       if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
        perror_with_name (_("Couldn't get registers"));
 
-      amd64_supply_native_gregset (current_regcache, &regs, -1);
+      amd64_supply_native_gregset (regcache, &regs, -1);
       if (regnum != -1)
        return;
     }
 
-  if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
+  if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
       elf_fpregset_t fpregs;
 
-      if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
-       perror_with_name (_("Couldn't get floating point status"));
+      if (have_ptrace_getregset == TRIBOOL_TRUE)
+       {
+         char xstateregs[X86_XSTATE_MAX_SIZE];
+         struct iovec iov;
+
+         /* Pre-4.14 kernels have a bug (fixed by commit 0852b374173b
+            "x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on
+            Intel Skylake CPUs") that sometimes causes the mxcsr location in
+            xstateregs not to be copied by PTRACE_GETREGSET.  Make sure that
+            the location is at least initialized with a defined value.  */
+         memset (xstateregs, 0, sizeof (xstateregs));
+         iov.iov_base = xstateregs;
+         iov.iov_len = sizeof (xstateregs);
+         if (ptrace (PTRACE_GETREGSET, tid,
+                     (unsigned int) NT_X86_XSTATE, (long) &iov) < 0)
+           perror_with_name (_("Couldn't get extended state status"));
+
+         amd64_supply_xsave (regcache, -1, xstateregs);
+       }
+      else
+       {
+         if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+           perror_with_name (_("Couldn't get floating point status"));
 
-      amd64_supply_fxsave (current_regcache, -1, &fpregs);
+         amd64_supply_fxsave (regcache, -1, &fpregs);
+       }
+#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
+      {
+       /* PTRACE_ARCH_PRCTL is obsolete since 2.6.25, where the
+          fs_base and gs_base fields of user_regs_struct can be
+          used directly.  */
+       unsigned long base;
+
+       if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM)
+         {
+           if (ptrace (PTRACE_ARCH_PRCTL, tid, &base, ARCH_GET_FS) < 0)
+             perror_with_name (_("Couldn't get segment register fs_base"));
+
+           regcache->raw_supply (AMD64_FSBASE_REGNUM, &base);
+         }
+
+       if (regnum == -1 || regnum == AMD64_GSBASE_REGNUM)
+         {
+           if (ptrace (PTRACE_ARCH_PRCTL, tid, &base, ARCH_GET_GS) < 0)
+             perror_with_name (_("Couldn't get segment register gs_base"));
+
+           regcache->raw_supply (AMD64_GSBASE_REGNUM, &base);
+         }
+      }
+#endif
     }
 }
 
@@ -191,24 +290,25 @@ amd64_linux_fetch_inferior_registers (int regnum)
    -1, do this for all registers (including the floating-point and SSE
    registers).  */
 
-static void
-amd64_linux_store_inferior_registers (int regnum)
+void
+amd64_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = regcache->arch ();
   int tid;
 
   /* GNU/Linux LWP ID's are process ID's.  */
-  tid = TIDGET (inferior_ptid);
+  tid = regcache->ptid ().lwp ();
   if (tid == 0)
-    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
+    tid = regcache->ptid ().pid (); /* Not a threaded program.  */
 
-  if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+  if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, 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 (current_regcache, &regs, regnum);
+      amd64_linux_collect_native_gregset (regcache, &regs, regnum);
 
       if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
        perror_with_name (_("Couldn't write registers"));
@@ -217,94 +317,62 @@ amd64_linux_store_inferior_registers (int regnum)
        return;
     }
 
-  if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
+  if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, 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 (current_regcache, regnum, &fpregs);
-
-      if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
-       perror_with_name (_("Couldn't write floating point status"));
-
-      return;
-    }
-}
-\f
-
-static unsigned long
-amd64_linux_dr_get (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);
-
-  /* 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,
-                 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
-amd64_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_ptid);
+      if (have_ptrace_getregset == TRIBOOL_TRUE)
+       {
+         char xstateregs[X86_XSTATE_MAX_SIZE];
+         struct iovec iov;
 
-  errno = 0;
-  ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
-  if (errno != 0)
-    perror_with_name (_("Couldn't write debug register"));
-}
+         iov.iov_base = xstateregs;
+         iov.iov_len = sizeof (xstateregs);
+         if (ptrace (PTRACE_GETREGSET, tid,
+                     (unsigned int) NT_X86_XSTATE, (long) &iov) < 0)
+           perror_with_name (_("Couldn't get extended state status"));
 
-void
-amd64_linux_dr_set_control (unsigned long control)
-{
-  amd64_linux_dr_set (DR_CONTROL, control);
-}
+         amd64_collect_xsave (regcache, regnum, xstateregs, 0);
 
-void
-amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
-{
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+         if (ptrace (PTRACE_SETREGSET, tid,
+                     (unsigned int) NT_X86_XSTATE, (long) &iov) < 0)
+           perror_with_name (_("Couldn't write extended state status"));
+       }
+      else
+       {
+         if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+           perror_with_name (_("Couldn't get floating point status"));
 
-  amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
-}
+         amd64_collect_fxsave (regcache, regnum, &fpregs);
 
-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);
-}
+         if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
+           perror_with_name (_("Couldn't write floating point status"));
+       }
 
-unsigned long
-amd64_linux_dr_get_status (void)
-{
-  return amd64_linux_dr_get (DR_STATUS);
+#ifndef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
+      {
+       /* PTRACE_ARCH_PRCTL is obsolete since 2.6.25, where the
+          fs_base and gs_base fields of user_regs_struct can be
+          used directly.  */
+       void *base;
+
+       if (regnum == -1 || regnum == AMD64_FSBASE_REGNUM)
+         {
+           regcache->raw_collect (AMD64_FSBASE_REGNUM, &base);
+
+           if (ptrace (PTRACE_ARCH_PRCTL, tid, base, ARCH_SET_FS) < 0)
+             perror_with_name (_("Couldn't write segment register fs_base"));
+         }
+       if (regnum == -1 || regnum == AMD64_GSBASE_REGNUM)
+         {
+
+           regcache->raw_collect (AMD64_GSBASE_REGNUM, &base);
+           if (ptrace (PTRACE_ARCH_PRCTL, tid, base, ARCH_SET_GS) < 0)
+             perror_with_name (_("Couldn't write segment register gs_base"));
+         }
+      }
+#endif
+    }
 }
 \f
 
@@ -312,39 +380,27 @@ amd64_linux_dr_get_status (void)
    a request for a thread's local storage address.  */
 
 ps_err_e
-ps_get_thread_area (const struct ps_prochandle *ph,
+ps_get_thread_area (struct ps_prochandle *ph,
                     lwpid_t lwpid, int idx, void **base)
 {
-  if (gdbarch_ptr_bit (current_gdbarch) == 32)
+  if (gdbarch_bfd_arch_info (ph->thread->inf->gdbarch)->bits_per_word == 32)
     {
-      /* 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;
-      
-      /* 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;
+      unsigned int base_addr;
+      ps_err_e result;
+
+      result = x86_linux_get_thread_area (lwpid, (void *) (long) idx,
+                                         &base_addr);
+      if (result == PS_OK)
+       {
+         /* Extend the value to 64 bits.  Here it's assumed that
+            a "long" and a "void *" are the same.  */
+         (*base) = (void *) (long) base_addr;
+       }
+      return result;
     }
   else
     {
-      /* This definition comes from prctl.h, but some kernels may not
-         have it.  */
-#ifndef PTRACE_ARCH_PRCTL
-#define PTRACE_ARCH_PRCTL      30
-#endif
+
       /* FIXME: ezannoni-2003-07-09 see comment above about include
         file order.  We could be getting bogus values for these two.  */
       gdb_assert (FS < ELF_NGREG);
@@ -352,10 +408,39 @@ ps_get_thread_area (const struct ps_prochandle *ph,
       switch (idx)
        {
        case FS:
+#ifdef HAVE_STRUCT_USER_REGS_STRUCT_FS_BASE
+           {
+             /* PTRACE_ARCH_PRCTL is obsolete since 2.6.25, where the
+                fs_base and gs_base fields of user_regs_struct can be
+                used directly.  */
+             unsigned long fs;
+             errno = 0;
+             fs = ptrace (PTRACE_PEEKUSER, lwpid,
+                          offsetof (struct user_regs_struct, fs_base), 0);
+             if (errno == 0)
+               {
+                 *base = (void *) fs;
+                 return PS_OK;
+               }
+           }
+#endif
          if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
            return PS_OK;
          break;
        case GS:
+#ifdef HAVE_STRUCT_USER_REGS_STRUCT_GS_BASE
+           {
+             unsigned long gs;
+             errno = 0;
+             gs = ptrace (PTRACE_PEEKUSER, lwpid,
+                          offsetof (struct user_regs_struct, gs_base), 0);
+             if (errno == 0)
+               {
+                 *base = (void *) gs;
+                 return PS_OK;
+               }
+           }
+#endif
          if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
            return PS_OK;
          break;
@@ -367,45 +452,45 @@ ps_get_thread_area (const struct ps_prochandle *ph,
 }
 \f
 
-static void (*super_post_startup_inferior) (ptid_t ptid);
+/* Convert a ptrace/host siginfo object, into/from the siginfo in the
+   layout of the inferiors' architecture.  Returns true if any
+   conversion was done; false otherwise.  If DIRECTION is 1, then copy
+   from INF to PTRACE.  If DIRECTION is 0, copy from PTRACE to
+   INF.  */
 
-static void
-amd64_linux_child_post_startup_inferior (ptid_t ptid)
+bool
+amd64_linux_nat_target::low_siginfo_fixup (siginfo_t *ptrace,
+                                          gdb_byte *inf,
+                                          int direction)
 {
-  i386_cleanup_dregs ();
-  super_post_startup_inferior (ptid);
+  struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
+
+  /* Is the inferior 32-bit?  If so, then do fixup the siginfo
+     object.  */
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    return amd64_linux_siginfo_fixup_common (ptrace, inf, direction,
+                                            FIXUP_32);
+  /* No fixup for native x32 GDB.  */
+  else if (gdbarch_addr_bit (gdbarch) == 32 && sizeof (void *) == 8)
+    return amd64_linux_siginfo_fixup_common (ptrace, inf, direction,
+                                            FIXUP_X32);
+  else
+    return false;
 }
-\f
-
-/* Provide a prototype to silence -Wmissing-prototypes.  */
-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_reg_offset = amd64_linux_gregset_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 ();
-
-  /* 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;
+  linux_target = &the_amd64_linux_nat_target;
 
-  /* Register the target.  */
-  linux_nat_add_target (t);
+  /* Add the target.  */
+  add_inf_child_target (linux_target);
 }
This page took 0.058102 seconds and 4 git commands to generate.