* 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.
This commit is contained in:
Mark Kettenis 2003-09-27 21:57:56 +00:00
parent 41d35cb0fe
commit 5716833cf8
6 changed files with 377 additions and 175 deletions

View File

@ -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.

View File

@ -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 (struct gdbarch *gdbarch, int regnum)
{
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);
}
/* SSE register? */
static int
i386_mmx_regnum_p (int regnum)
i386_sse_regnum_p (struct gdbarch *gdbarch, int regnum)
{
return (regnum >= MM0_REGNUM
&& regnum < MM0_REGNUM + i386_num_mmx_regs);
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
}
static int
i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int 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
}
#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_fp_regnum_p (int regnum)
{
return (regnum < NUM_REGS
&& (FP0_REGNUM && FP0_REGNUM <= regnum && regnum < FPC_REGNUM));
if (I387_ST0_REGNUM < 0)
return 0;
return (I387_ST0_REGNUM <= regnum && regnum < I387_FCTRL_REGNUM);
}
int
i386_fpc_regnum_p (int regnum)
{
return (regnum < NUM_REGS
&& (FPC_REGNUM <= regnum && regnum < XMM0_REGNUM));
}
if (I387_ST0_REGNUM < 0)
return 0;
/* SSE register? */
int
i386_sse_regnum_p (int regnum)
{
return (regnum < NUM_REGS
&& (XMM0_REGNUM <= regnum && regnum < MXCSR_REGNUM));
}
int
i386_mxcsr_regnum_p (int regnum)
{
return (regnum < NUM_REGS
&& regnum == MXCSR_REGNUM);
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 (FP0_REGNUM + fpi);
return (I387_ST0_REGNUM + fpreg);
#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.
/* 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-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.
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. */
FIXME: kettenis/20020614: They do include the FPU registers for
now, which probably is not quite right. */
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;
}

View File

@ -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 */

View File

@ -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;
if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
last_regnum = FOP_REGNUM;
gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
gdb_assert (tdep->num_xmm_regs > 0);
for (i = FP0_REGNUM; i <= last_regnum; i++)
/* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
proper definitions for REGCACHE's architecture. */
#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;
if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0)
last_regnum = FOP_REGNUM;
gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
gdb_assert (tdep->num_xmm_regs > 0);
for (i = FP0_REGNUM; i <= last_regnum; i++)
/* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the
proper definitions for REGCACHE's architecture. */
#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

View File

@ -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 */

View File

@ -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