diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 43 | ||||
-rw-r--r-- | gdb/i386-tdep.c | 183 | ||||
-rw-r--r-- | gdb/i386-tdep.h | 22 | ||||
-rw-r--r-- | gdb/i387-tdep.c | 268 | ||||
-rw-r--r-- | gdb/i387-tdep.h | 29 | ||||
-rw-r--r-- | gdb/x86-64-tdep.c | 7 |
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 |