summaryrefslogtreecommitdiff
path: root/gdb/i386v4-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/i386v4-nat.c')
-rw-r--r--gdb/i386v4-nat.c91
1 files changed, 87 insertions, 4 deletions
diff --git a/gdb/i386v4-nat.c b/gdb/i386v4-nat.c
index 10802cb730b..3ed273e7b13 100644
--- a/gdb/i386v4-nat.c
+++ b/gdb/i386v4-nat.c
@@ -31,6 +31,9 @@
#include <sys/procfs.h>
+/* Prototypes for supply_gregset etc. */
+#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
@@ -142,17 +145,65 @@ fill_gregset (gregsetp, regno)
#endif /* HAVE_GREGSET_T */
-#if defined (FP0_REGNUM) && defined (HAVE_FPREGSET_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. */
+/* 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
+};
+
void
supply_fpregset (fpregsetp)
fpregset_t *fpregsetp;
{
- /* FIXME: see m68k-tdep.c for an example, for the m68k. */
+ int regi;
+
+ if (NUM_FREGS == 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);
+ }
}
/* Given a pointer to a floating point register set in /proc format
@@ -165,9 +216,41 @@ fill_fpregset (fpregsetp, regno)
fpregset_t *fpregsetp;
int regno;
{
- /* FIXME: see m68k-tdep.c for an example, for the m68k. */
+ int regi;
+
+ if (NUM_FREGS == 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));
+ }
+ }
+ }
}
-#endif /* defined (FP0_REGNUM) && defined (HAVE_FPREGSET_T) */
+#endif /* defined (HAVE_FPREGSET_T) */
#endif /* HAVE_SYS_PROCFS_H */