merge from gcc
[external/binutils.git] / gdb / i386v4-nat.c
index 8de253d..5744c81 100644 (file)
@@ -1,12 +1,13 @@
-/* Native-dependent code for SVR4 Unix running on i386's, for GDB.
-   Copyright 1988, 1989, 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+/* Native-dependent code for Unix SVR4 running on i386's.
+
+   Copyright (C) 1988, 1989, 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2001,
+   2002, 2004, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
    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,
@@ -15,9 +16,7 @@
    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 "value.h"
 #include <sys/reg.h>
 #endif
 
+#include "i386-tdep.h"
+#include "i387-tdep.h"
 
 #ifdef HAVE_SYS_PROCFS_H
 
 #include <sys/procfs.h>
 
-/* Prototypes for supply_gregset etc. */
+/* We must not compile this code for 64-bit Solaris x86.  */
+#if !defined (PR_MODEL_NATIVE) || (PR_MODEL_NATIVE == PR_MODEL_ILP32)
+
 #include "gregset.h"
 
-/*  The /proc interface divides the target machine's register set up into
-   two different sets, the general register set (gregset) and the floating
-   point register set (fpregset).  For each set, there is an ioctl to get
-   the current register set and another ioctl to set the current values.
+/* The `/proc' interface divides the target machine's register set up
+   into two different sets, the general purpose register set (gregset)
+   and the floating-point register set (fpregset).  For each set,
+   there is an ioctl to get the current register set and another ioctl
+   to set the current values.
 
-   The actual structure passed through the ioctl interface is, of course,
-   naturally machine dependent, and is different for each set of registers.
-   For the i386 for example, the general register set is typically defined
-   by:
+   The actual structure passed through the ioctl interface is, of
+   course, naturally machine dependent, and is different for each set
+   of registers.  For the i386 for example, the general-purpose
+   register set is typically defined by:
 
    typedef int gregset_t[19];           (in <sys/regset.h>)
 
    #define UESP 17
    #define SS   18
 
-   and the floating point set by:
-
-   typedef struct fpregset
-   {
-   union
-   {
-   struct fpchip_state  // fp extension state //
-   {
-   int state[27];       // 287/387 saved state //
-   int status;          // status word saved at exception //
-   } fpchip_state;
-   struct fp_emul_space // for emulators //
-   {
-   char fp_emul[246];
-   char fp_epad[2];
-   } fp_emul_space;
-   int f_fpregs[62];    // union of the above //
-   } fp_reg_set;
-   long f_wregs[33];            // saved weitek state //
+   and the floating-point set by:
+
+   typedef struct fpregset   {
+           union {
+                   struct fpchip_state            // fp extension state //
+                   {
+                           int     state[27];     // 287/387 saved state //
+                           int     status;        // status word saved at //
+                                                  // exception //
+                   } fpchip_state;
+                   struct fp_emul_space           // for emulators //
+                   {
+                           char    fp_emul[246];
+                           char    fp_epad[2];
+                   } fp_emul_space;
+                   int     f_fpregs[62];          // union of the above //
+           } fp_reg_set;
+           long            f_wregs[33];           // saved weitek state //
    } fpregset_t;
 
-   These routines provide the packing and unpacking of gregset_t and
-   fpregset_t formatted data.
+   Incidentally fpchip_state contains the FPU state in the same format
+   as used by the "fsave" instruction, and that's the only thing we
+   support here.  I don't know how the emulator stores it state.  The
+   Weitek stuff definitely isn't supported.
 
- */
+   The routines defined here, provide the packing and unpacking of
+   gregset_t and fpregset_t formatted data.  */
 
 #ifdef HAVE_GREGSET_T
 
-/* This is a duplicate of the table in i386-xdep.c. */
-
+/* Mapping between the general-purpose registers in `/proc'
+   format and GDB's register array layout.  */
 static int regmap[] =
 {
   EAX, ECX, EDX, EBX,
   UESP, EBP, ESI, EDI,
   EIP, EFL, CS, SS,
-  DS, ES, FS, GS,
+  DS, ES, FS, GS
 };
 
-/* Prototypes for local functions */
-
-void fill_gregset (gregset_t *, int);
-
-void supply_gregset (gregset_t *);
-
-void supply_fpregset (fpregset_t *);
-
-void fill_fpregset (fpregset_t *, int);
-
-
-/*  FIXME:  These routine absolutely depends upon (NUM_REGS - NUM_FREGS)
-   being less than or equal to the number of registers that can be stored
-   in a gregset_t.  Note that with the current scheme there will typically
-   be more registers actually stored in a gregset_t that what we know
-   about.  This is bogus and should be fixed. */
-
-/*  Given a pointer to a general register set in /proc format (gregset_t *),
-   unpack the register contents and supply them as gdb's idea of the current
-   register values. */
+/* Fill GDB's register array with the general-purpose register values
+   in *GREGSETP.  */
 
 void
-supply_gregset (gregset_t *gregsetp)
+supply_gregset (struct regcache *regcache, const gregset_t *gregsetp)
 {
-  register int regi;
-  register greg_t *regp = (greg_t *) gregsetp;
-  extern int regmap[];
-
-  for (regi = 0; regi < (NUM_REGS - NUM_FREGS); regi++)
-    {
-      supply_register (regi, (char *) (regp + regmap[regi]));
-    }
+  const greg_t *regp = (const greg_t *) gregsetp;
+  int regnum;
+
+  for (regnum = 0; regnum < I386_NUM_GREGS; regnum++)
+    regcache_raw_supply (regcache, regnum, regp + regmap[regnum]);
 }
 
+/* Fill register REGNUM (if it is a general-purpose register) in
+   *GREGSETPS with the value in GDB's register array.  If REGNUM is -1,
+   do this for all registers.  */
+
 void
-fill_gregset (gregset_t *gregsetp, int regno)
+fill_gregset (const struct regcache *regcache,
+             gregset_t *gregsetp, int regnum)
 {
-  int regi;
-  register greg_t *regp = (greg_t *) gregsetp;
-  extern int regmap[];
-
-  for (regi = 0; regi < (NUM_REGS - NUM_FREGS); regi++)
-    {
-      if ((regno == -1) || (regno == regi))
-       {
-         *(regp + regmap[regi]) = *(int *) &registers[REGISTER_BYTE (regi)];
-       }
-    }
+  greg_t *regp = (greg_t *) gregsetp;
+  int i;
+
+  for (i = 0; i < I386_NUM_GREGS; i++)
+    if (regnum == -1 || regnum == i)
+      regcache_raw_collect (regcache, i, regp + regmap[i]);
 }
 
 #endif /* HAVE_GREGSET_T */
 
-#if defined (HAVE_FPREGSET_T)
-
-/*  Given a pointer to a floating point register set in /proc format
-   (fpregset_t *), unpack the register contents and supply them as gdb's
-   idea of the current floating point register values. */
+#ifdef HAVE_FPREGSET_T
 
-/* FIXME: Assumes that fpregsetp contains an i387 FSAVE area. */
-static const int freg_offset_map[] =
-{
-#if !defined(FPREGSET_FSAVE_OFFSET)
-#define FPREGSET_FSAVE_OFFSET  0
-#endif
-  FPREGSET_FSAVE_OFFSET + 28 + 0 * 10,
-  FPREGSET_FSAVE_OFFSET + 28 + 1 * 10,
-  FPREGSET_FSAVE_OFFSET + 28 + 2 * 10,
-  FPREGSET_FSAVE_OFFSET + 28 + 3 * 10,
-  FPREGSET_FSAVE_OFFSET + 28 + 4 * 10,
-  FPREGSET_FSAVE_OFFSET + 28 + 5 * 10,
-  FPREGSET_FSAVE_OFFSET + 28 + 6 * 10,
-  FPREGSET_FSAVE_OFFSET + 28 + 7 * 10,
-  FPREGSET_FSAVE_OFFSET + 0,
-  FPREGSET_FSAVE_OFFSET + 4,
-  FPREGSET_FSAVE_OFFSET + 8,
-  FPREGSET_FSAVE_OFFSET + 16,
-  FPREGSET_FSAVE_OFFSET + 12,
-  FPREGSET_FSAVE_OFFSET + 24,
-  FPREGSET_FSAVE_OFFSET + 20,
-  FPREGSET_FSAVE_OFFSET + 16
-};
+/* Fill GDB's register array with the floating-point register values in
+   *FPREGSETP.  */
 
 void
-supply_fpregset (fpregset_t *fpregsetp)
+supply_fpregset (struct regcache *regcache, const fpregset_t *fpregsetp)
 {
-  int regi;
-  
-  if (NUM_FREGS == 0)
+  if (gdbarch_fp0_regnum (get_regcache_arch (regcache)) == 0)
     return;
-  for (regi = FP0_REGNUM; regi <= LAST_FPU_CTRL_REGNUM; regi++)
-    {
-      char tbuf[4];
-      ULONGEST tval;
-      char *from = (char *) fpregsetp + freg_offset_map[regi - FP0_REGNUM];
-
-      if (regi == FCS_REGNUM)
-       {
-         tval = extract_unsigned_integer (from, 4) & 0xffff;
-         store_unsigned_integer (tbuf, 4, tval);
-         supply_register (regi, tbuf);
-       }
-      else if (regi == FOP_REGNUM)
-       {
-         tval = (extract_unsigned_integer (from, 4) >> 16) & ((1 << 11) - 1);
-         store_unsigned_integer (tbuf, 4, tval);
-         supply_register (regi, tbuf);
-       }
-      else
-       supply_register (regi, from);
-    }
+
+  i387_supply_fsave (regcache, -1, fpregsetp);
 }
 
-/*  Given a pointer to a floating point register set in /proc format
-   (fpregset_t *), update the register specified by REGNO from gdb's idea
-   of the current floating point register set.  If REGNO is -1, update
-   them all. */
+/* Fill register REGNO (if it is a floating-point register) in
+   *FPREGSETP with the value in GDB's register array.  If REGNO is -1,
+   do this for all registers.  */
 
 void
-fill_fpregset (fpregset_t *fpregsetp, int regno)
+fill_fpregset (const struct regcache *regcache,
+              fpregset_t *fpregsetp, int regno)
 {
-  int regi;
-
-  if (NUM_FREGS == 0)
+  if (gdbarch_fp0_regnum (get_regcache_arch (regcache)) == 0)
     return;
-  for (regi = FP0_REGNUM; regi <= LAST_FPU_CTRL_REGNUM; regi++)
-    {
-      if ((regno == -1) || (regno == regi))
-       {
-         char *to = (char *) fpregsetp + freg_offset_map[regi - FP0_REGNUM];
-         char *from = (char *) &registers[REGISTER_BYTE (regi)];
-         ULONGEST valto;
-         ULONGEST valfrom;
-
-         if (regi == FCS_REGNUM)
-           {
-             valto = extract_unsigned_integer (to, 4);
-             valfrom = extract_unsigned_integer (from, 4);
-             valto = (valto & ~0xffff) | (valfrom & 0xffff);
-             store_unsigned_integer (to, 4, valto);
-           }
-         else if (regi == FOP_REGNUM)
-           {
-             valto = extract_unsigned_integer (to, 4);
-             valfrom = extract_unsigned_integer (from, 4);
-             valto = (valto & 0xffff) | ((valfrom & ((1 << 11) - 1)) << 16);
-             store_unsigned_integer (to, 4, valto);
-           }
-         else
-           {
-             memcpy (to, from, REGISTER_RAW_SIZE (regi));
-           }
-       }
-    }
+
+  i387_collect_fsave (regcache, regno, fpregsetp);
 }
 
-#endif /* defined (HAVE_FPREGSET_T) */
+#endif /* HAVE_FPREGSET_T */
+
+#endif /* not 64-bit.  */
 
 #endif /* HAVE_SYS_PROCFS_H */