summaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog43
-rw-r--r--gdb/i386-tdep.c183
-rw-r--r--gdb/i386-tdep.h22
-rw-r--r--gdb/i387-tdep.c268
-rw-r--r--gdb/i387-tdep.h29
-rw-r--r--gdb/x86-64-tdep.c7
6 files changed, 377 insertions, 175 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 6bf05490bcb..c0e544aaf66 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,48 @@
2003-09-27 Mark Kettenis <kettenis@gnu.org>
+ * i386-tdep.h: Put opaque declarations in alphabetical
+ order. Remove spurious whitespace.
+ (struct gdbarch_tdep): add st0_regnum and mm0_regnum members.
+ (i386_sse_regnum_p, i386_mxcsr_regnum_p): Remove prototypes.
+ * i386-tdep.c (MM0_REGNUM): Remove define.
+ (i386_mmx_regnum_p): Add gdbarch argument.
+ (i386_sse_regnum_p, i386_mxcsr_regnum_p): Add gdbarch argument.
+ Rewrite using new macro definitions for FPU/SSE registers.
+ (i386_fp_regnum_p, i386_fpc_regnum_p): Rewrite using new macro
+ definitions from i387-tdep.h.
+ (i386_register_name): Update.
+ (i386_stab_reg_to_regnum, i386_dwarf_reg_to_regnum): Update to use
+ new macro definitions for FPU/SSE registers.
+ (i386_extract_return_value): Determine whether floating-point
+ registers are present by examining REGCACHE's architecture.
+ (i386_store_return_value): Likewise. Use I386_MAX_REGISTER_SIZE
+ instead of FPU_REG_RAW_SIZE. Use new macro definitions for
+ FPU/SSE registers.
+ (i386_register_type): Update.
+ (i386_mmx_regnum_to_fp_regnum): Rewrite using new macro
+ definitions for FPU registers. Use REGCACHE's architecture to
+ determine the appropriate register numbers.
+ (i386_pseudo_register_read, i386_pseudo_register_write,
+ i386_register_reggroup_p): Update.
+ (i386_gdbarch_init): Initialize TDEP->st0_regnum and
+ TDEP->mm0_regnum.
+ * i387-tdep.h (I387_FCTRL_REGNUM, I387_FSTAT_REGNUM,
+ I387_FTAG_REGNUM, I387_FISEG_REGNUM, I387_FIOFF_REGNUM,
+ I387_FOSEG_REGNUM, I387_FOOFF_REGNUM, I387_FOP_REGNUM,
+ I387_XMM0_REGNUM, I387_MXCSR_REGNUM): New defines.
+ (i387_supply_fsave, i387_fill_fsave, i387_supply_fxsave,
+ i387_fill_fxsave): Change type of fsave/fxsave argument from `char
+ *' to `void *'.
+ * i387-tdep.c (i387_print_float_info, fsave_offset, FSAVE_ADDR,
+ i387_supply_fsave, i387_fill_fsave, fxsave_offset, FXSAVE_ADDR,
+ i387_supply_fxsave, i387_fill_fxsave): Update to use new macro
+ definitions for FPU/SSE registers.
+ (FXSAVE_MXCSR_ADDR): New define.
+ * x86-64-tdep.c (x86_64_init_abi): Override TDEP->st0_regnum and
+ TDEP->mm0_regnum.
+ (I387_FISEG_REGNUM, I387_FOSEG_REGNUM): Remove defines.
+ (I387_ST0_REGNUM): Define.
+
* regcache.h (get_regcache_arch): New prototype.
* regcache.c (get_regcache_arch): New function.
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index f4cbc347c8a..d3e33576cd6 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -79,45 +79,75 @@ static char *i386_mmx_names[] =
static const int i386_num_mmx_regs = ARRAY_SIZE (i386_mmx_names);
-#define MM0_REGNUM NUM_REGS
-
static int
-i386_mmx_regnum_p (int regnum)
+i386_mmx_regnum_p (struct gdbarch *gdbarch, int regnum)
{
- return (regnum >= MM0_REGNUM
- && regnum < MM0_REGNUM + i386_num_mmx_regs);
+ int mm0_regnum = gdbarch_tdep (gdbarch)->mm0_regnum;
+
+ if (mm0_regnum < 0)
+ return 0;
+
+ return (regnum >= mm0_regnum && regnum < mm0_regnum + i386_num_mmx_regs);
}
-/* FP register? */
+/* SSE register? */
-int
-i386_fp_regnum_p (int regnum)
+static int
+i386_sse_regnum_p (struct gdbarch *gdbarch, int regnum)
{
- return (regnum < NUM_REGS
- && (FP0_REGNUM && FP0_REGNUM <= regnum && regnum < FPC_REGNUM));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ if (I387_NUM_XMM_REGS == 0)
+ return 0;
+
+ return (I387_XMM0_REGNUM <= regnum && regnum < I387_MXCSR_REGNUM);
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
}
-int
-i386_fpc_regnum_p (int regnum)
+static int
+i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int regnum)
{
- return (regnum < NUM_REGS
- && (FPC_REGNUM <= regnum && regnum < XMM0_REGNUM));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ if (I387_NUM_XMM_REGS == 0)
+ return 0;
+
+ return (regnum == I387_MXCSR_REGNUM);
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
}
-/* SSE register? */
+#define I387_ST0_REGNUM (gdbarch_tdep (current_gdbarch)->st0_regnum)
+#define I387_MM0_REGNUM (gdbarch_tdep (current_gdbarch)->mm0_regnum)
+#define I387_NUM_XMM_REGS (gdbarch_tdep (current_gdbarch)->num_xmm_regs)
+
+/* FP register? */
int
-i386_sse_regnum_p (int regnum)
+i386_fp_regnum_p (int regnum)
{
- return (regnum < NUM_REGS
- && (XMM0_REGNUM <= regnum && regnum < MXCSR_REGNUM));
+ if (I387_ST0_REGNUM < 0)
+ return 0;
+
+ return (I387_ST0_REGNUM <= regnum && regnum < I387_FCTRL_REGNUM);
}
int
-i386_mxcsr_regnum_p (int regnum)
+i386_fpc_regnum_p (int regnum)
{
- return (regnum < NUM_REGS
- && regnum == MXCSR_REGNUM);
+ if (I387_ST0_REGNUM < 0)
+ return 0;
+
+ return (I387_FCTRL_REGNUM <= regnum && regnum < I387_XMM0_REGNUM);
}
/* Return the name of register REG. */
@@ -125,8 +155,8 @@ i386_mxcsr_regnum_p (int regnum)
const char *
i386_register_name (int reg)
{
- if (i386_mmx_regnum_p (reg))
- return i386_mmx_names[reg - MM0_REGNUM];
+ if (i386_mmx_regnum_p (current_gdbarch, reg))
+ return i386_mmx_names[reg - I387_MM0_REGNUM];
if (reg >= 0 && reg < i386_num_register_names)
return i386_register_names[reg];
@@ -149,17 +179,17 @@ i386_stab_reg_to_regnum (int reg)
else if (reg >= 12 && reg <= 19)
{
/* Floating-point registers. */
- return reg - 12 + FP0_REGNUM;
+ return reg - 12 + I387_ST0_REGNUM;
}
else if (reg >= 21 && reg <= 28)
{
/* SSE registers. */
- return reg - 21 + XMM0_REGNUM;
+ return reg - 21 + I387_XMM0_REGNUM;
}
else if (reg >= 29 && reg <= 36)
{
/* MMX registers. */
- return reg - 29 + MM0_REGNUM;
+ return reg - 29 + I387_MM0_REGNUM;
}
/* This will hopefully provoke a warning. */
@@ -182,7 +212,7 @@ i386_dwarf_reg_to_regnum (int reg)
else if (reg >= 11 && reg <= 18)
{
/* Floating-point registers. */
- return reg - 11 + FP0_REGNUM;
+ return reg - 11 + I387_ST0_REGNUM;
}
else if (reg >= 21)
{
@@ -193,6 +223,10 @@ i386_dwarf_reg_to_regnum (int reg)
/* This will hopefully provoke a warning. */
return NUM_REGS + NUM_PSEUDO_REGS;
}
+
+#undef I387_ST0_REGNUM
+#undef I387_MM0_REGNUM
+#undef I387_NUM_XMM_REGS
/* This is the variable that is set with "set disassembly-flavor", and
@@ -1121,6 +1155,7 @@ static void
i386_extract_return_value (struct type *type, struct regcache *regcache,
void *dst)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
bfd_byte *valbuf = dst;
int len = TYPE_LENGTH (type);
char buf[I386_MAX_REGISTER_SIZE];
@@ -1134,7 +1169,7 @@ i386_extract_return_value (struct type *type, struct regcache *regcache,
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
- if (FP0_REGNUM < 0)
+ if (tdep->st0_regnum < 0)
{
warning ("Cannot find floating-point return value.");
memset (valbuf, 0, len);
@@ -1178,8 +1213,13 @@ static void
i386_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
int len = TYPE_LENGTH (type);
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for the architecture. */
+#define I387_ST0_REGNUM I386_ST0_REGNUM
+
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) == 1)
{
@@ -1190,9 +1230,9 @@ i386_store_return_value (struct type *type, struct regcache *regcache,
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
ULONGEST fstat;
- char buf[FPU_REG_RAW_SIZE];
+ char buf[I386_MAX_REGISTER_SIZE];
- if (FP0_REGNUM < 0)
+ if (tdep->st0_regnum < 0)
{
warning ("Cannot set floating-point return value.");
return;
@@ -1213,14 +1253,14 @@ i386_store_return_value (struct type *type, struct regcache *regcache,
actual value doesn't really matter, but 7 is what a normal
function return would end up with if the program started out
with a freshly initialized FPU. */
- regcache_raw_read_unsigned (regcache, FSTAT_REGNUM, &fstat);
+ regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
fstat |= (7 << 11);
- regcache_raw_write_unsigned (regcache, FSTAT_REGNUM, fstat);
+ regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
/* Mark %st(1) through %st(7) as empty. Since we set the top of
the floating-point register stack to 7, the appropriate value
for the tag word is 0x3fff. */
- regcache_raw_write_unsigned (regcache, FTAG_REGNUM, 0x3fff);
+ regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
}
else
{
@@ -1239,6 +1279,8 @@ i386_store_return_value (struct type *type, struct regcache *regcache,
internal_error (__FILE__, __LINE__,
"Cannot store return value of %d bytes long.", len);
}
+
+#undef I387_ST0_REGNUM
}
/* Extract from REGCACHE, which contains the (raw) register state, the
@@ -1300,10 +1342,10 @@ i386_register_type (struct gdbarch *gdbarch, int regnum)
if (i386_fp_regnum_p (regnum))
return builtin_type_i387_ext;
- if (i386_sse_regnum_p (regnum))
+ if (i386_sse_regnum_p (gdbarch, regnum))
return builtin_type_vec128i;
- if (i386_mmx_regnum_p (regnum))
+ if (i386_mmx_regnum_p (gdbarch, regnum))
return builtin_type_vec64i;
return builtin_type_int;
@@ -1315,24 +1357,30 @@ i386_register_type (struct gdbarch *gdbarch, int regnum)
static int
i386_mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
{
- int mmxi;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ int mmxreg, fpreg;
ULONGEST fstat;
int tos;
- int fpi;
- mmxi = regnum - MM0_REGNUM;
- regcache_raw_read_unsigned (regcache, FSTAT_REGNUM, &fstat);
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ mmxreg = regnum - tdep->mm0_regnum;
+ regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
tos = (fstat >> 11) & 0x7;
- fpi = (mmxi + tos) % 8;
+ fpreg = (mmxreg + tos) % 8;
+
+ return (I387_ST0_REGNUM + fpreg);
- return (FP0_REGNUM + fpi);
+#undef I387_ST0_REGNUM
}
static void
i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, void *buf)
{
- if (i386_mmx_regnum_p (regnum))
+ if (i386_mmx_regnum_p (gdbarch, regnum))
{
char mmx_buf[MAX_REGISTER_SIZE];
int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
@@ -1349,7 +1397,7 @@ static void
i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, const void *buf)
{
- if (i386_mmx_regnum_p (regnum))
+ if (i386_mmx_regnum_p (gdbarch, regnum))
{
char mmx_buf[MAX_REGISTER_SIZE];
int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
@@ -1708,11 +1756,11 @@ int
i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
- int sse_regnum_p = (i386_sse_regnum_p (regnum)
- || i386_mxcsr_regnum_p (regnum));
+ int sse_regnum_p = (i386_sse_regnum_p (gdbarch, regnum)
+ || i386_mxcsr_regnum_p (gdbarch, regnum));
int fp_regnum_p = (i386_fp_regnum_p (regnum)
|| i386_fpc_regnum_p (regnum));
- int mmx_regnum_p = (i386_mmx_regnum_p (regnum));
+ int mmx_regnum_p = (i386_mmx_regnum_p (gdbarch, regnum));
if (group == i386_mmx_reggroup)
return mmx_regnum_p;
@@ -1755,22 +1803,28 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
- /* The i386 default settings now include the SSE registers.
- I386_NUM_XREGS includes mxcsr, and we don't want to count
- this as one of the xmm regs -- which is why we subtract one.
-
- Note: kevinb/2003-07-14: Whatever Mark's concerns are about the
- FPU registers in the FIXME below apply to the SSE registers as well.
- The only problem that I see is that these registers will show up
- in "info all-registers" even on CPUs where they don't exist. IMO,
- however, if it's a choice between printing them always (even when
- they don't exist) or never showing them to the user (even when they
- do exist), I prefer the former over the latter. Ideally, of course,
- we'd somehow autodetect that we have them (or not) and display them
- when we have them and suppress them when we don't.
-
- FIXME: kettenis/20020614: They do include the FPU registers for
- now, which probably is not quite right. */
+ /* The default settings include the FPU registers, the MMX registers
+ and the SSE registers. This can be overidden for a specific ABI
+ by adjusting the members `st0_regnum', `mm0_regnum' and
+ `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
+ will show up in the output of "info all-registers". Ideally we
+ should try to autodetect whether they are available, such that we
+ can prevent "info all-registers" from displaying registers that
+ aren't available.
+
+ NOTE: kevinb/2003-07-13: ... if it's a choice between printing
+ [the SSE registers] always (even when they don't exist) or never
+ showing them to the user (even when they do exist), I prefer the
+ former over the latter. */
+
+ tdep->st0_regnum = I386_ST0_REGNUM;
+
+ /* The MMX registers are implemented as pseudo-registers. Put off
+ caclulating the register number for %mm0 until we know the number
+ of raw registers. */
+ tdep->mm0_regnum = 0;
+
+ /* I386_NUM_XREGS includes %mxcsr, so substract one. */
tdep->num_xmm_regs = I386_NUM_XREGS - 1;
tdep->jb_pc_offset = -1;
@@ -1874,6 +1928,11 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
frame_unwind_append_sniffer (gdbarch, i386_sigtramp_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, i386_frame_sniffer);
+ /* Unless support for MMX has been disabled, make %mm0 the first
+ pseudo-register. */
+ if (tdep->mm0_regnum == 0)
+ tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
+
return gdbarch;
}
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 7412b8ea867..6c4cf73a36a 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -1,4 +1,5 @@
-/* Target-dependent code for GDB, the GNU debugger.
+/* Target-dependent code for the i386.
+
Copyright 2001, 2002, 2003
Free Software Foundation, Inc.
@@ -22,9 +23,9 @@
#ifndef I386_TDEP_H
#define I386_TDEP_H
-struct reggroup;
-struct gdbarch;
struct frame_info;
+struct gdbarch;
+struct reggroup;
/* GDB's i386 target supports both the 32-bit Intel Architecture
(IA-32) and the 64-bit AMD x86-64 architecture. Internally it uses
@@ -55,6 +56,15 @@ enum struct_return
/* i386 architecture specific information. */
struct gdbarch_tdep
{
+ /* Register number for %st(0). The register numbers for the other
+ registers follow from this one. Set this to -1 to indicate the
+ absence of an FPU. */
+ int st0_regnum;
+
+ /* Register number for %mm0. Set this to -1 to indicate the absence
+ of MMX support. */
+ int mm0_regnum;
+
/* Number of SSE registers. */
int num_xmm_regs;
@@ -131,11 +141,6 @@ extern int i386_fpc_regnum_p (int regnum);
#define MXCSR_REGNUM \
(XMM0_REGNUM + gdbarch_tdep (current_gdbarch)->num_xmm_regs)
-/* Return non-zero if REGNUM matches the SSE register and the SSE
- register set is active. */
-extern int i386_sse_regnum_p (int regnum);
-extern int i386_mxcsr_regnum_p (int regnum);
-
/* FIXME: kettenis/2001-11-24: Obsolete macro's. */
#define FCS_REGNUM FISEG_REGNUM
#define FCOFF_REGNUM FIOFF_REGNUM
@@ -194,4 +199,3 @@ extern int i386obsd_sc_reg_offset[];
extern int i386bsd_sc_reg_offset[];
#endif /* i386-tdep.h */
-
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
index 6feb39285f5..63943e7b2d7 100644
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -205,6 +205,7 @@ void
i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, const char *args)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
char buf[4];
ULONGEST fctrl;
ULONGEST fstat;
@@ -217,20 +218,26 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
int fpreg;
int top;
- fctrl = get_frame_register_unsigned (frame, FCTRL_REGNUM);
- fstat = get_frame_register_unsigned (frame, FSTAT_REGNUM);
- ftag = get_frame_register_unsigned (frame, FTAG_REGNUM);
- fiseg = get_frame_register_unsigned (frame, FISEG_REGNUM);
- fioff = get_frame_register_unsigned (frame, FIOFF_REGNUM);
- foseg = get_frame_register_unsigned (frame, FOSEG_REGNUM);
- fooff = get_frame_register_unsigned (frame, FOOFF_REGNUM);
- fop = get_frame_register_unsigned (frame, FOP_REGNUM);
+ gdb_assert (gdbarch == get_frame_arch (frame));
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for FRAME's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ fctrl = get_frame_register_unsigned (frame, I387_FCTRL_REGNUM);
+ fstat = get_frame_register_unsigned (frame, I387_FSTAT_REGNUM);
+ ftag = get_frame_register_unsigned (frame, I387_FTAG_REGNUM);
+ fiseg = get_frame_register_unsigned (frame, I387_FISEG_REGNUM);
+ fioff = get_frame_register_unsigned (frame, I387_FIOFF_REGNUM);
+ foseg = get_frame_register_unsigned (frame, I387_FOSEG_REGNUM);
+ fooff = get_frame_register_unsigned (frame, I387_FOOFF_REGNUM);
+ fop = get_frame_register_unsigned (frame, I387_FOP_REGNUM);
top = ((fstat >> 11) & 7);
for (fpreg = 7; fpreg >= 0; fpreg--)
{
- unsigned char raw[FPU_REG_RAW_SIZE];
+ unsigned char raw[I386_MAX_REGISTER_SIZE];
int tag = (ftag >> (fpreg * 2)) & 3;
int i;
@@ -252,7 +259,7 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
break;
}
- get_frame_register (frame, (fpreg + 8 - top) % 8 + FP0_REGNUM, raw);
+ get_frame_register (frame, (fpreg + 8 - top) % 8 + I387_ST0_REGNUM, raw);
fputs_filtered ("0x", file);
for (i = 9; i >= 0; i--)
@@ -278,6 +285,8 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
fprintf_filtered (file, "%s\n", local_hex_string_custom (fooff, "08"));
fprintf_filtered (file, "Opcode: %s\n",
local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04"));
+
+#undef I387_ST0_REGNUM
}
@@ -331,34 +340,42 @@ i387_value_to_register (struct frame_info *frame, int regnum,
put_frame_register (frame, regnum, to);
}
+
/* Handle FSAVE and FXSAVE formats. */
+/* FIXME: kettenis/20030927: The functions below should accept a
+ `regcache' argument, but I don't want to change the function
+ signature just yet. There's some band-aid in the functions below
+ in the form of the `regcache' local variables. This will ease the
+ transition later on. */
+
/* At fsave_offset[REGNUM] you'll find the offset to the location in
the data structure used by the "fsave" instruction where GDB
register REGNUM is stored. */
static int fsave_offset[] =
{
- 28 + 0 * FPU_REG_RAW_SIZE, /* FP0_REGNUM through ... */
- 28 + 1 * FPU_REG_RAW_SIZE,
- 28 + 2 * FPU_REG_RAW_SIZE,
- 28 + 3 * FPU_REG_RAW_SIZE,
- 28 + 4 * FPU_REG_RAW_SIZE,
- 28 + 5 * FPU_REG_RAW_SIZE,
- 28 + 6 * FPU_REG_RAW_SIZE,
- 28 + 7 * FPU_REG_RAW_SIZE, /* ... FP7_REGNUM. */
- 0, /* FCTRL_REGNUM (16 bits). */
- 4, /* FSTAT_REGNUM (16 bits). */
- 8, /* FTAG_REGNUM (16 bits). */
- 16, /* FISEG_REGNUM (16 bits). */
- 12, /* FIOFF_REGNUM. */
- 24, /* FOSEG_REGNUM. */
- 20, /* FOOFF_REGNUM. */
- 18 /* FOP_REGNUM (bottom 11 bits). */
+ 28 + 0 * 10, /* %st(0) ... */
+ 28 + 1 * 10,
+ 28 + 2 * 10,
+ 28 + 3 * 10,
+ 28 + 4 * 10,
+ 28 + 5 * 10,
+ 28 + 6 * 10,
+ 28 + 7 * 10, /* ... %st(7). */
+ 0, /* `fctrl' (16 bits). */
+ 4, /* `fstat' (16 bits). */
+ 8, /* `ftag' (16 bits). */
+ 16, /* `fiseg' (16 bits). */
+ 12, /* `fioff'. */
+ 24, /* `foseg' (16 bits). */
+ 20, /* `fooff'. */
+ 18 /* `fop' (bottom 11 bits). */
};
-#define FSAVE_ADDR(fsave, regnum) (fsave + fsave_offset[regnum - FP0_REGNUM])
+#define FSAVE_ADDR(fsave, regnum) \
+ (fsave + fsave_offset[regnum - I387_ST0_REGNUM])
/* Fill register REGNUM in GDB's register cache with the appropriate
@@ -366,35 +383,45 @@ static int fsave_offset[] =
bits in *FSAVE. */
void
-i387_supply_fsave (const char *fsave, int regnum)
+i387_supply_fsave (const void *fsave, int regnum)
{
+ struct regcache *regcache = current_regcache;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ const char *regs = fsave;
int i;
- for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
if (regnum == -1 || regnum == i)
{
if (fsave == NULL)
{
- supply_register (i, NULL);
- return;
+ regcache_raw_supply (regcache, i, NULL);
+ continue;
}
/* Most of the FPU control registers occupy only 16 bits in the
fsave area. Give those a special treatment. */
- if (i >= FPC_REGNUM
- && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
+ if (i >= I387_FCTRL_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
{
unsigned char val[4];
- memcpy (val, FSAVE_ADDR (fsave, i), 2);
+ memcpy (val, FSAVE_ADDR (regs, i), 2);
val[2] = val[3] = 0;
- if (i == FOP_REGNUM)
+ if (i == I387_FOP_REGNUM)
val[1] &= ((1 << 3) - 1);
- supply_register (i, val);
+ regcache_raw_supply (regcache, i, val);
}
else
- supply_register (i, FSAVE_ADDR (fsave, i));
+ regcache_raw_supply (regcache, i, FSAVE_ADDR (regs, i));
}
+#undef I387_ST0_REGNUM
}
/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
@@ -403,34 +430,44 @@ i387_supply_fsave (const char *fsave, int regnum)
bits in *FSAVE. */
void
-i387_fill_fsave (char *fsave, int regnum)
+i387_fill_fsave (void *fsave, int regnum)
{
+ struct regcache *regcache = current_regcache;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ char *regs = fsave;
int i;
- for (i = FP0_REGNUM; i < XMM0_REGNUM; i++)
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#define I387_ST0_REGNUM tdep->st0_regnum
+
+ for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++)
if (regnum == -1 || regnum == i)
{
/* Most of the FPU control registers occupy only 16 bits in
the fsave area. Give those a special treatment. */
- if (i >= FPC_REGNUM
- && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
+ if (i >= I387_FCTRL_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
{
unsigned char buf[4];
- regcache_collect (i, buf);
+ regcache_raw_collect (regcache, i, buf);
- if (i == FOP_REGNUM)
+ if (i == I387_FOP_REGNUM)
{
/* The opcode occupies only 11 bits. Make sure we
don't touch the other bits. */
buf[1] &= ((1 << 3) - 1);
- buf[1] |= ((FSAVE_ADDR (fsave, i))[1] & ~((1 << 3) - 1));
+ buf[1] |= ((FSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
}
- memcpy (FSAVE_ADDR (fsave, i), buf, 2);
+ memcpy (FSAVE_ADDR (regs, i), buf, 2);
}
else
- regcache_collect (i, FSAVE_ADDR (fsave, i));
+ regcache_raw_collect (regcache, i, FSAVE_ADDR (regs, i));
}
+#undef I387_ST0_REGNUM
}
@@ -440,23 +477,23 @@ i387_fill_fsave (char *fsave, int regnum)
static int fxsave_offset[] =
{
- 32, /* FP0_REGNUM through ... */
+ 32, /* %st(0) through ... */
48,
64,
80,
96,
112,
128,
- 144, /* ... FP7_REGNUM (80 bits each). */
- 0, /* FCTRL_REGNUM (16 bits). */
- 2, /* FSTAT_REGNUM (16 bits). */
- 4, /* FTAG_REGNUM (16 bits). */
- 12, /* FISEG_REGNUM (16 bits). */
- 8, /* FIOFF_REGNUM. */
- 20, /* FOSEG_REGNUM (16 bits). */
- 16, /* FOOFF_REGNUM. */
- 6, /* FOP_REGNUM (bottom 11 bits). */
- 160 + 0 * 16, /* XMM0_REGNUM through ... */
+ 144, /* ... %st(7) (80 bits each). */
+ 0, /* `fctrl' (16 bits). */
+ 2, /* `fstat' (16 bits). */
+ 4, /* `ftag' (16 bits). */
+ 12, /* `fiseg' (16 bits). */
+ 8, /* `fioff'. */
+ 20, /* `foseg' (16 bits). */
+ 16, /* `fooff'. */
+ 6, /* `fop' (bottom 11 bits). */
+ 160 + 0 * 16, /* %xmm0 through ... */
160 + 1 * 16,
160 + 2 * 16,
160 + 3 * 16,
@@ -471,19 +508,18 @@ static int fxsave_offset[] =
160 + 12 * 16,
160 + 13 * 16,
160 + 14 * 16,
- 160 + 15 * 16, /* ... XMM15_REGNUM (128 bits each). */
- 24 /* MXCSR_REGNUM. */
+ 160 + 15 * 16, /* ... %xmm15 (128 bits each). */
};
-/* FIXME: kettenis/20030430: We made an unfortunate choice in putting
- %mxcsr after the SSE registers %xmm0-%xmm7 instead of before, since
- it makes supporting the registers %xmm8-%xmm15 on x86-64 a bit
- involved. Hack around it by explicitly overriding the offset for
- %mxcsr here. */
-
#define FXSAVE_ADDR(fxsave, regnum) \
- ((regnum == MXCSR_REGNUM) ? (fxsave + 24) : \
- (fxsave + fxsave_offset[regnum - FP0_REGNUM]))
+ (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM])
+
+/* We made an unfortunate choice in putting %mxcsr after the SSE
+ registers %xmm0-%xmm7 instead of before, since it makes supporting
+ the registers %xmm8-%xmm15 on AMD64 a bit involved. Therefore we
+ don't include the offset for %mxcsr here above. */
+
+#define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24)
static int i387_tag (const unsigned char *raw);
@@ -493,34 +529,43 @@ static int i387_tag (const unsigned char *raw);
masks off any of the reserved bits in *FXSAVE. */
void
-i387_supply_fxsave (const char *fxsave, int regnum)
+i387_supply_fxsave (const void *fxsave, int regnum)
{
- int i, last_regnum = MXCSR_REGNUM;
+ struct regcache *regcache = current_regcache;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ const char *regs = fxsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+ gdb_assert (tdep->num_xmm_regs > 0);
- if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
- last_regnum = FOP_REGNUM;
+ /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
+ proper definitions for REGCACHE's architecture. */
- for (i = FP0_REGNUM; i <= last_regnum; i++)
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
if (regnum == -1 || regnum == i)
{
- if (fxsave == NULL)
+ if (regs == NULL)
{
- supply_register (i, NULL);
+ regcache_raw_supply (regcache, i, NULL);
continue;
}
/* Most of the FPU control registers occupy only 16 bits in
the fxsave area. Give those a special treatment. */
- if (i >= FPC_REGNUM && i < XMM0_REGNUM
- && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
+ if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
{
unsigned char val[4];
- memcpy (val, FXSAVE_ADDR (fxsave, i), 2);
+ memcpy (val, FXSAVE_ADDR (regs, i), 2);
val[2] = val[3] = 0;
- if (i == FOP_REGNUM)
+ if (i == I387_FOP_REGNUM)
val[1] &= ((1 << 3) - 1);
- else if (i== FTAG_REGNUM)
+ else if (i== I387_FTAG_REGNUM)
{
/* The fxsave area contains a simplified version of
the tag word. We have to look at the actual 80-bit
@@ -530,7 +575,8 @@ i387_supply_fxsave (const char *fxsave, int regnum)
int fpreg;
int top;
- top = (((FXSAVE_ADDR (fxsave, FSTAT_REGNUM))[1] >> 3) & 0x7);
+ top = ((FXSAVE_ADDR (regs, I387_FSTAT_REGNUM))[1] >> 3);
+ top &= 0x7;
for (fpreg = 7; fpreg >= 0; fpreg--)
{
@@ -538,8 +584,8 @@ i387_supply_fxsave (const char *fxsave, int regnum)
if (val[0] & (1 << fpreg))
{
- int regnum = (fpreg + 8 - top) % 8 + FP0_REGNUM;
- tag = i387_tag (FXSAVE_ADDR (fxsave, regnum));
+ int regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM;
+ tag = i387_tag (FXSAVE_ADDR (regs, regnum));
}
else
tag = 3; /* Empty */
@@ -549,11 +595,23 @@ i387_supply_fxsave (const char *fxsave, int regnum)
val[0] = ftag & 0xff;
val[1] = (ftag >> 8) & 0xff;
}
- supply_register (i, val);
+ regcache_raw_supply (regcache, i, val);
}
else
- supply_register (i, FXSAVE_ADDR (fxsave, i));
+ regcache_raw_supply (regcache, i, FXSAVE_ADDR (regs, i));
}
+
+ if (regnum == I387_MXCSR_REGNUM || regnum == -1)
+ {
+ if (regs == NULL)
+ regcache_raw_supply (regcache, I387_MXCSR_REGNUM, NULL);
+ else
+ regcache_raw_supply (regcache, I387_MXCSR_REGNUM,
+ FXSAVE_MXCSR_ADDR (regs));
+ }
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
}
/* Fill register REGNUM (if it is a floating-point or SSE register) in
@@ -562,33 +620,42 @@ i387_supply_fxsave (const char *fxsave, int regnum)
reserved bits in *FXSAVE. */
void
-i387_fill_fxsave (char *fxsave, int regnum)
+i387_fill_fxsave (void *fxsave, int regnum)
{
- int i, last_regnum = MXCSR_REGNUM;
+ struct regcache *regcache = current_regcache;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ char *regs = fxsave;
+ int i;
+
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+ gdb_assert (tdep->num_xmm_regs > 0);
- if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
- last_regnum = FOP_REGNUM;
+ /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
+ proper definitions for REGCACHE's architecture. */
- for (i = FP0_REGNUM; i <= last_regnum; i++)
+#define I387_ST0_REGNUM tdep->st0_regnum
+#define I387_NUM_XMM_REGS tdep->num_xmm_regs
+
+ for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++)
if (regnum == -1 || regnum == i)
{
/* Most of the FPU control registers occupy only 16 bits in
the fxsave area. Give those a special treatment. */
- if (i >= FPC_REGNUM && i < XMM0_REGNUM
- && i != FIOFF_REGNUM && i != FOOFF_REGNUM)
+ if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM
+ && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM)
{
unsigned char buf[4];
- regcache_collect (i, buf);
+ regcache_raw_collect (regcache, i, buf);
- if (i == FOP_REGNUM)
+ if (i == I387_FOP_REGNUM)
{
/* The opcode occupies only 11 bits. Make sure we
don't touch the other bits. */
buf[1] &= ((1 << 3) - 1);
- buf[1] |= ((FXSAVE_ADDR (fxsave, i))[1] & ~((1 << 3) - 1));
+ buf[1] |= ((FXSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1));
}
- else if (i == FTAG_REGNUM)
+ else if (i == I387_FTAG_REGNUM)
{
/* Converting back is much easier. */
@@ -607,11 +674,18 @@ i387_fill_fxsave (char *fxsave, int regnum)
buf[0] |= (1 << fpreg);
}
}
- memcpy (FXSAVE_ADDR (fxsave, i), buf, 2);
+ memcpy (FXSAVE_ADDR (regs, i), buf, 2);
}
else
- regcache_collect (i, FXSAVE_ADDR (fxsave, i));
+ regcache_raw_collect (regcache, i, FXSAVE_ADDR (regs, i));
}
+
+ if (regnum == I387_MXCSR_REGNUM || regnum == -1)
+ regcache_raw_collect (regcache, I387_MXCSR_REGNUM,
+ FXSAVE_MXCSR_ADDR (regs));
+
+#undef I387_ST0_REGNUM
+#undef I387_NUM_XMM_REGS
}
/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
index 654b4a5a2a7..41e695b30db 100644
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -27,6 +27,27 @@ struct ui_file;
struct frame_info;
struct type;
+/* Because the number of general-purpose registers is different for
+ AMD64, the floating-point registers and SSE registers get shifted.
+ The following definitions are intended to help writing code that
+ needs the register numbers of floating-point registers and SSE
+ registers. In order to use these, one should provide a definition
+ for I387_ST0_REGNUM, and possibly I387_NUM_XMM_REGS, preferably by
+ using a local "#define" in the body of the function that uses this.
+ Please "#undef" them before the end of the function. */
+
+#define I387_FCTRL_REGNUM (I387_ST0_REGNUM + 8)
+#define I387_FSTAT_REGNUM (I387_FCTRL_REGNUM + 1)
+#define I387_FTAG_REGNUM (I387_FCTRL_REGNUM + 2)
+#define I387_FISEG_REGNUM (I387_FCTRL_REGNUM + 3)
+#define I387_FIOFF_REGNUM (I387_FCTRL_REGNUM + 4)
+#define I387_FOSEG_REGNUM (I387_FCTRL_REGNUM + 5)
+#define I387_FOOFF_REGNUM (I387_FCTRL_REGNUM + 6)
+#define I387_FOP_REGNUM (I387_FCTRL_REGNUM + 7)
+#define I387_XMM0_REGNUM (I387_ST0_REGNUM + 16)
+#define I387_MXCSR_REGNUM (I387_XMM0_REGNUM + I387_NUM_XMM_REGS)
+
+
/* Print out the i387 floating point state. */
extern void i387_print_float_info (struct gdbarch *gdbarch,
@@ -56,26 +77,26 @@ extern void i387_value_to_register (struct frame_info *frame, int regnum,
value from *FSAVE. This function masks off any of the reserved
bits in *FSAVE. */
-extern void i387_supply_fsave (const char *fsave, int regnum);
+extern void i387_supply_fsave (const void *fsave, int regnum);
/* Fill register REGNUM (if it is a floating-point register) in *FSAVE
with the value in GDB's register cache. If REGNUM is -1, do this
for all registers. This function doesn't touch any of the reserved
bits in *FSAVE. */
-extern void i387_fill_fsave (char *fsave, int regnum);
+extern void i387_fill_fsave (void *fsave, int regnum);
/* Fill register REGNUM in GDB's register cache with the appropriate
floating-point or SSE register value from *FXSAVE. This function
masks off any of the reserved bits in *FXSAVE. */
-extern void i387_supply_fxsave (const char *fxsave, int regnum);
+extern void i387_supply_fxsave (const void *fxsave, int regnum);
/* Fill register REGNUM (if it is a floating-point or SSE register) in
*FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
this for all registers. This function doesn't touch any of the
reserved bits in *FXSAVE. */
-extern void i387_fill_fxsave (char *fxsave, int regnum);
+extern void i387_fill_fxsave (void *fxsave, int regnum);
#endif /* i387-tdep.h */
diff --git a/gdb/x86-64-tdep.c b/gdb/x86-64-tdep.c
index 038ebd2b27d..13fc5d2f822 100644
--- a/gdb/x86-64-tdep.c
+++ b/gdb/x86-64-tdep.c
@@ -1209,7 +1209,8 @@ x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- /* The x86-64 has 16 SSE registers. */
+ /* AMD64 has an FPU and 16 SSE registers. */
+ tdep->st0_regnum = X86_64_ST0_REGNUM;
tdep->num_xmm_regs = 16;
/* This is what all the fuss is about. */
@@ -1264,6 +1265,7 @@ x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
/* Avoid wiring in the MMX registers for now. */
set_gdbarch_num_pseudo_regs (gdbarch, 0);
+ tdep->mm0_regnum = -1;
set_gdbarch_unwind_dummy_id (gdbarch, x86_64_unwind_dummy_id);
@@ -1278,8 +1280,7 @@ x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
}
-#define I387_FISEG_REGNUM FISEG_REGNUM
-#define I387_FOSEG_REGNUM FOSEG_REGNUM
+#define I387_ST0_REGNUM X86_64_ST0_REGNUM
/* The 64-bit FXSAVE format differs from the 32-bit format in the
sense that the instruction pointer and data pointer are simply