From e2890f080481667b088d9909e43295ad7e26e15e Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Thu, 10 Aug 2000 14:54:51 +0000 Subject: [PATCH] * i387-nat.h (i387_supply_fsave, i387_fill_fsave): Make extern. (i387_supply_fxsave, i387_fill_fxsave): New prototypes. * i387-nat.c (i387_supply_fsave): Declare `val' as `unsigned int'. (fxsave_offset): New variable. (FXSAVE_ADDR): New macro. (i387_supply_fxsave, i387_fill_fxsave, i387_tag): New functions. --- gdb/ChangeLog | 9 +++ gdb/i387-nat.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++- gdb/i387-nat.h | 19 ++++- 3 files changed, 234 insertions(+), 5 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ac5e8c3b26..72fdad1ba8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2000-08-10 Mark Kettenis + + * i387-nat.h (i387_supply_fsave, i387_fill_fsave): Make extern. + (i387_supply_fxsave, i387_fill_fxsave): New prototypes. + * i387-nat.c (i387_supply_fsave): Declare `val' as `unsigned int'. + (fxsave_offset): New variable. + (FXSAVE_ADDR): New macro. + (i387_supply_fxsave, i387_fill_fxsave, i387_tag): New functions. + 2000-08-08 Tom Tromey * jv-valprint.c (java_value_print): Only print non-null Strings. diff --git a/gdb/i387-nat.c b/gdb/i387-nat.c index 17e67b47a3..76986080e1 100644 --- a/gdb/i387-nat.c +++ b/gdb/i387-nat.c @@ -1,5 +1,5 @@ /* Native-dependent code for the i387. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright 2000 Free Software Foundation, Inc. This file is part of GDB. @@ -71,7 +71,7 @@ i387_supply_fsave (char *fsave) if (i >= FIRST_FPU_CTRL_REGNUM && i != FCOFF_REGNUM && i != FDOFF_REGNUM) { - unsigned val = *(unsigned short *) (FSAVE_ADDR (fsave, i)); + unsigned int val = *(unsigned short *) (FSAVE_ADDR (fsave, i)); if (i == FOP_REGNUM) { @@ -123,3 +123,210 @@ i387_fill_fsave (char *fsave, int regno) REGISTER_RAW_SIZE (i)); } } + + +/* At fxsave_offset[REGNO] you'll find the offset to the location in + the data structure used by the "fxsave" instruction where GDB + register REGNO is stored. */ + +static int fxsave_offset[] = +{ + 32, /* FP0_REGNUM 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, /* FCS_REGNUM (16 bits). */ + 8, /* FCOFF_REGNUM. */ + 20, /* FDS_REGNUM (16 bits). */ + 16, /* FDOFF_REGNUM. */ + 6, /* FOP_REGNUM (bottom 11 bits). */ + 160, /* XMM0_REGNUM through ... */ + 176, + 192, + 208, + 224, + 240, + 256, + 272, /* ... XMM7_REGNUM (128 bits each). */ + 24, /* MXCSR_REGNUM. */ +}; + +#define FXSAVE_ADDR(fxsave, regnum) \ + (fxsave + fxsave_offset[regnum - FP0_REGNUM]) + +static int i387_tag (unsigned char *raw); + + +/* Fill GDB's register array with the floating-point and SSE register + values in *FXSAVE. This function masks off any of the reserved + bits in *FXSAVE. */ + +void +i387_supply_fxsave (char *fxsave) +{ + int i; + + for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++) + { + /* Most of the FPU control registers occupy only 16 bits in + the fxsave area. Give those a special treatment. */ + if (i >= FIRST_FPU_CTRL_REGNUM && i < XMM0_REGNUM + && i != FCOFF_REGNUM && i != FDOFF_REGNUM) + { + unsigned long val = *(unsigned short *) (FXSAVE_ADDR (fxsave, i)); + + if (i == FOP_REGNUM) + { + val &= ((1 << 11) - 1); + supply_register (i, (char *) &val); + } + else if (i== FTAG_REGNUM) + { + /* The fxsave area contains a simplified version of the + tag word. We have to look at the actual 80-bit FP + data to recreate the traditional i387 tag word. */ + + unsigned long ftag = 0; + unsigned long fstat; + int fpreg; + int top; + + fstat = *(unsigned short *) (FXSAVE_ADDR (fxsave, FSTAT_REGNUM)); + top = ((fstat >> 11) & 0x111); + + for (fpreg = 7; fpreg >= 0; fpreg--) + { + int tag = 0x11; + + if (val & (1 << fpreg)) + { + int regnum = (fpreg + 8 - top) % 8 + FP0_REGNUM; + tag = i387_tag (FXSAVE_ADDR (fxsave, regnum)); + } + + ftag |= tag << (2 * fpreg); + } + supply_register (i, (char *) &ftag); + } + else + supply_register (i, (char *) &val); + } + else + supply_register (i, FXSAVE_ADDR (fxsave, i)); + } +} + +/* Fill register REGNO (if it is a floating-point or SSE register) in + *FXSAVE with the value in GDB's register array. If REGNO is -1, do + this for all registers. This function doesn't touch any of the + reserved bits in *FXSAVE. */ + +void +i387_fill_fxsave (char *fxsave, int regno) +{ + int i; + + for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++) + if (regno == -1 || regno == i) + { + /* Most of the FPU control registers occupy only 16 bits in + the fxsave area. Give those a special treatment. */ + if (i >= FIRST_FPU_CTRL_REGNUM && i < XMM0_REGNUM + && i != FCOFF_REGNUM && i != FDOFF_REGNUM) + { + if (i == FOP_REGNUM) + { + unsigned short oldval, newval; + + /* The opcode occupies only 11 bits. */ + oldval = (*(unsigned short *) (FXSAVE_ADDR (fxsave, i))); + newval = *(unsigned short *) ®isters[REGISTER_BYTE (i)]; + newval &= ((1 << 11) - 1); + newval |= oldval & ~((1 << 11) - 1); + memcpy (FXSAVE_ADDR (fxsave, i), &newval, 2); + } + else if (i == FTAG_REGNUM) + { + /* Converting back is much easier. */ + + unsigned char val = 0; + unsigned short ftag; + int fpreg; + + ftag = *(unsigned short *) ®isters[REGISTER_BYTE (i)]; + + for (fpreg = 7; fpreg >= 0; fpreg--) + { + int tag = (ftag >> (fpreg * 2)) & 0x11; + + if (tag != 0x11) + val |= (1 << fpreg); + } + + memcpy (FXSAVE_ADDR (fxsave, i), &val, 2); + } + else + memcpy (FXSAVE_ADDR (fxsave, i), + ®isters[REGISTER_BYTE (i)], 2); + } + else + memcpy (FXSAVE_ADDR (fxsave, i), ®isters[REGISTER_BYTE (i)], + REGISTER_RAW_SIZE (i)); + } +} + +/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in + *RAW. */ + +static int +i387_tag (unsigned char *raw) +{ + int integer; + unsigned int exponent; + unsigned long fraction[2]; + + integer = raw[7] & 0x80; + exponent = (((raw[9] & 0x7f) << 8) | raw[8]); + fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); + fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) + | (raw[5] << 8) | raw[4]); + + if (exponent == 0x7fff) + { + /* Special. */ + return (0x10); + } + else if (exponent == 0x0000) + { + if (integer) + { + /* Valid. */ + return (0x00); + } + else + { + /* Special. */ + return (0x10); + } + } + else + { + if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) + { + /* Zero. */ + return (0x01); + } + else + { + /* Special. */ + return (0x10); + } + } +} diff --git a/gdb/i387-nat.h b/gdb/i387-nat.h index c23c267d8f..85efc8ecd8 100644 --- a/gdb/i387-nat.h +++ b/gdb/i387-nat.h @@ -1,5 +1,5 @@ /* Native-dependent code for the i387. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright 2000 Free Software Foundation, Inc. This file is part of GDB. @@ -25,13 +25,26 @@ in *FSAVE. This function masks off any of the reserved bits in *FSAVE. */ -void i387_supply_fsave (char *fsave); +extern void i387_supply_fsave (char *fsave); /* Fill register REGNO (if it is a floating-point register) in *FSAVE with the value in GDB's register array. If REGNO is -1, do this for all registers. This function doesn't touch any of the reserved bits in *FSAVE. */ -void i387_fill_fsave (char *fsave, int regno); +extern void i387_fill_fsave (char *fsave, int regno); + +/* Fill GDB's register array with the floating-point and SSE register + values in *FXSAVE. This function masks off any of the reserved + bits in *FXSAVE. */ + +extern void i387_supply_fxsave (char *fxsave); + +/* Fill register REGNO (if it is a floating-point or SSE register) in + *FXSAVE with the value in GDB's register array. If REGNO 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 regno); #endif /* i387-nat.h */