diff options
author | Mark Kettenis <kettenis@gnu.org> | 2000-08-10 14:54:51 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@gnu.org> | 2000-08-10 14:54:51 +0000 |
commit | e2890f080481667b088d9909e43295ad7e26e15e (patch) | |
tree | 62ae6d6e6fffbd35cd16dc21042393afef324768 /gdb/i387-nat.c | |
parent | 2e685b93dfef9012b6b1c25dc92e79a4b0a18dcc (diff) | |
download | gdb-e2890f080481667b088d9909e43295ad7e26e15e.zip gdb-e2890f080481667b088d9909e43295ad7e26e15e.tar.gz gdb-e2890f080481667b088d9909e43295ad7e26e15e.tar.bz2 |
* 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.
Diffstat (limited to 'gdb/i387-nat.c')
-rw-r--r-- | gdb/i387-nat.c | 211 |
1 files changed, 209 insertions, 2 deletions
diff --git a/gdb/i387-nat.c b/gdb/i387-nat.c index 17e67b4..7698608 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); + } + } +} |