diff options
Diffstat (limited to 'gdb/i386-linux-nat.c')
-rw-r--r-- | gdb/i386-linux-nat.c | 291 |
1 files changed, 160 insertions, 131 deletions
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 8c63a94..12fbe3e 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -45,16 +45,9 @@ static int regmap[] = }; -/* FIXME: These routine absolutely depends upon (NUM_REGS - NUM_FREGS) - being less than or equal to the number of registers that can be stored - in a gregset_t. Note that with the current scheme there will typically - be more registers actually stored in a gregset_t that what we know - about. This is bogus and should be fixed. */ - -/* Given a pointer to a general register set in /proc format (gregset_t *), - unpack the register contents and supply them as gdb's idea of the current - register values. */ - +/* Given a pointer to a general register set in struct user format + (gregset_t *), unpack the register contents and supply them as + gdb's idea of the current register values. */ void supply_gregset (gregsetp) gregset_t *gregsetp; @@ -62,197 +55,234 @@ supply_gregset (gregsetp) register int regi; register greg_t *regp = (greg_t *) gregsetp; - for (regi = 0 ; regi < (NUM_REGS - NUM_FREGS) ; regi++) + for (regi = 0; regi < NUM_GREGS; regi++) { supply_register (regi, (char *) (regp + regmap[regi])); } } +/* Fill in a gregset_t object with selected data from a gdb-format + register file. + - GREGSETP points to the gregset_t object to be filled. + - GDB_REGS points to the GDB-style register file providing the data. + - VALID is an array indicating which registers in GDB_REGS are + valid; the parts of *GREGSETP that would hold registers marked + invalid in GDB_REGS are left unchanged. If VALID is zero, all + registers are assumed to be valid. */ void -fill_gregset (gregsetp, regno) - gregset_t *gregsetp; - int regno; +convert_to_gregset (gregset_t *gregsetp, + char *gdb_regs, + signed char *valid) { int regi; register greg_t *regp = (greg_t *) gregsetp; - for (regi = 0 ; regi < (NUM_REGS - NUM_FREGS) ; regi++) + for (regi = 0; regi < NUM_GREGS; regi++) + if (! valid || valid[regi]) + *(regp + regmap[regi]) = * (int *) ®isters[REGISTER_BYTE (regi)]; +} + +void +fill_gregset (gregset_t *gregsetp, + int regno) +{ + if (regno == -1) + convert_to_gregset (gregsetp, registers, 0); + else { - if ((regno == -1) || (regno == regi)) - { - *(regp + regmap[regi]) = *(int *) ®isters[REGISTER_BYTE (regi)]; - } + signed char valid[NUM_GREGS]; + memset (valid, 0, sizeof (valid)); + valid[regno] = 1; + convert_to_gregset (gregsetp, valid, valid); } } -/* Given a pointer to a floating point register set in (fpregset_t *) - format, unpack the register contents and supply them as gdb's - idea of the current floating point register values. */ +/* Where does st(N) start in the fpregset_t structure F? */ +#define FPREGSET_T_FPREG_OFFSET(f, n) \ + ((char *) &(f)->st_space + (n) * 10) +/* Fill GDB's register file with the floating-point register values in + *FPREGSETP. */ void -supply_fpregset (fpregsetp) - fpregset_t *fpregsetp; +supply_fpregset (fpregset_t *fpregsetp) { - register int regi; - char *from; - from = (char *) &(fpregsetp->st_space[0]); - for (regi = FPSTART_REGNUM ; regi <= FPEND_REGNUM ; regi++) - { - supply_register(regi, from); - from += REGISTER_RAW_SIZE(regi); - } + int i; + + /* Supply the floating-point registers. */ + for (i = 0; i < 8; i++) + supply_register (FP0_REGNUM + i, FPREGSET_T_FPREG_OFFSET (fpregsetp, i)); + + supply_register (FCTRL_REGNUM, (char *) &fpregsetp->cwd); + supply_register (FSTAT_REGNUM, (char *) &fpregsetp->swd); + supply_register (FTAG_REGNUM, (char *) &fpregsetp->twd); + supply_register (FCOFF_REGNUM, (char *) &fpregsetp->fip); + supply_register (FDS_REGNUM, (char *) &fpregsetp->fos); + supply_register (FDOFF_REGNUM, (char *) &fpregsetp->foo); + + /* Extract the code segment and opcode from the "fcs" member. */ + { + long l; + + l = fpregsetp->fcs & 0xffff; + supply_register (FCS_REGNUM, (char *) &l); + + l = (fpregsetp->fcs >> 16) & ((1 << 11) - 1); + supply_register (FOP_REGNUM, (char *) &l); + } } -/* Given a pointer to a floating point register set in (fpregset_t *) - format, update all of the registers from gdb's idea - of the current floating point register set. */ +/* Fill in an fpregset_t structure with selected data from a + gdb-format register file. + - FPREGSETP points to the structure to be filled. + - GDB_REGS points to the GDB-style register file providing the data. + - VALID is an array indicating which registers in GDB_REGS are + valid; the parts of *FPREGSETP that would hold registers marked + invalid in GDB_REGS are left unchanged. If VALID is zero, all + registers are assumed to be valid. */ void -fill_fpregset (fpregsetp, regno) - fpregset_t *fpregsetp; - int regno; +convert_to_fpregset (fpregset_t *fpregsetp, + char *gdb_regs, + signed char *valid) { - int regi; - char *to; - char *from; + int i; + + /* Fill in the floating-point registers. */ + for (i = 0; i < 8; i++) + if (!valid || valid[i]) + memcpy (FPREGSET_T_FPREG_OFFSET (fpregsetp, i), + ®isters[REGISTER_BYTE (FP0_REGNUM + i)], + REGISTER_RAW_SIZE(FP0_REGNUM + i)); + +#define fill(MEMBER, REGNO) \ + if (! valid || valid[(REGNO)]) \ + memcpy (&fpregsetp->MEMBER, ®isters[REGISTER_BYTE (REGNO)], \ + sizeof (fpregsetp->MEMBER)) + + fill (cwd, FCTRL_REGNUM); + fill (swd, FSTAT_REGNUM); + fill (twd, FTAG_REGNUM); + fill (fip, FCOFF_REGNUM); + fill (foo, FDOFF_REGNUM); + fill (fos, FDS_REGNUM); + +#undef fill + + if (! valid || valid[FCS_REGNUM]) + fpregsetp->fcs + = ((fpregsetp->fcs & ~0xffff) + | (* (int *) ®isters[REGISTER_BYTE (FCS_REGNUM)] & 0xffff)); + + if (! valid || valid[FOP_REGNUM]) + fpregsetp->fcs + = ((fpregsetp->fcs & 0xffff) + | ((*(int *) ®isters[REGISTER_BYTE (FOP_REGNUM)] & ((1 << 11) - 1)) + << 16)); +} - to = (char *) &(fpregsetp->st_space[0]); - for (regi = FPSTART_REGNUM ; regi <= FPEND_REGNUM ; regi++) - { - from = (char *) ®isters[REGISTER_BYTE (regi)]; - memcpy (to, from, REGISTER_RAW_SIZE (regi)); - to += REGISTER_RAW_SIZE(regi); - } + +/* Given a pointer to a floating point register set in (fpregset_t *) + format, update all of the registers from gdb's idea of the current + floating point register set. */ + +void +fill_fpregset (fpregset_t *fpregsetp, + int regno) +{ + convert_to_fpregset (fpregsetp, registers, 0); } -/* - Get the whole floating point state of the process and - store the floating point stack into registers[]. - */ + +/* Get the whole floating point state of the process and store the + floating point stack into registers[]. */ static void -fetch_fpregs(void) +fetch_fpregs () { int ret, regno; - char buf[FPREG_BYTES]; + fpregset_t buf; - ret = ptrace (PTRACE_GETFPREGS, inferior_pid, 0, (int)buf); - if ( ret < 0 ) + ret = ptrace (PTRACE_GETFPREGS, inferior_pid, 0, (int) &buf); + if (ret < 0) { warning ("Couldn't get floating point status"); return; } - for ( regno = 0; regno < NUM_FREGS; regno++ ) - { - if ( regno < 7 ) - supply_register (NUM_REGS-NUM_FREGS+regno, buf + regno*4); - else - supply_register (NUM_REGS-NUM_FREGS+regno, - buf + FPENV_BYTES + (regno-7)*FPREG_RAW_SIZE); - } - + /* ptrace fills an fpregset_t, so we can use the same function we do + for core files. */ + supply_fpregset (&buf); } -/* - Get the whole floating point state of the process and - replace the contents from registers[]. - */ +/* Set the inferior's floating-point registers to the values in + registers[] --- but only those registers marked valid. */ static void -store_fpregs(void) +store_fpregs () { - int ret, regno; - char buf[FPREG_BYTES]; + int ret; + fpregset_t buf; - ret = ptrace (PTRACE_GETFPREGS, inferior_pid, 0, (int)buf); - if ( ret < 0 ) + ret = ptrace (PTRACE_GETFPREGS, inferior_pid, 0, (int) &buf); + if (ret < 0) { warning ("Couldn't get floating point status"); return; } - for ( regno = 0; regno < NUM_FREGS; regno++ ) - { - if ( register_valid[regno] ) - { - if ( regno < 7 ) - { - read_register_gen (NUM_REGS-NUM_FREGS+regno, - buf + regno*4); - } - else - { - read_register_gen (NUM_REGS-NUM_FREGS+regno, - buf + FPENV_BYTES + (regno-7)*FPREG_RAW_SIZE); - } - } - } + convert_to_fpregset (&buf, registers, register_valid); - ret = ptrace (PTRACE_SETFPREGS, inferior_pid, 0, (int)buf); - if ( ret < 0 ) + ret = ptrace (PTRACE_SETFPREGS, inferior_pid, 0, (int) &buf); + if (ret < 0) { warning ("Couldn't write floating point status"); return; } - } -/* - Get state of all non-fp registers of the process and - store into registers[]. - */ +/* Read the general registers from the process, and store them + in registers[]. */ static void -fetch_regs(void) +fetch_regs () { int ret, regno; - char buf[17*sizeof(unsigned int)]; + gregset_t buf; - ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int)buf); - if ( ret < 0 ) + ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int) &buf); + if (ret < 0) { warning ("Couldn't get registers"); return; } - for ( regno = 0; regno < NUM_REGS-NUM_FREGS; regno++ ) - supply_register (regno, buf + register_addr (regno, U_REGS_OFFSET)); - + supply_gregset (&buf); } -/* - Get the whole non-floating-point register state of the process and - replace them in the process from registers[]. - */ +/* Set the inferior's general registers to the values in registers[] + --- but only those registers marked as valid. */ static void -store_regs(void) +store_regs () { int ret, regno; - char buf[17*sizeof(unsigned int)]; + gregset_t buf; - ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int)buf); - if ( ret < 0 ) + ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int) &buf); + if (ret < 0) { warning ("Couldn't get registers"); return; } - for ( regno = 0; regno < NUM_REGS-NUM_FREGS; regno++ ) - { - if ( register_valid[regno] ) - read_register_gen (regno, buf + register_addr (regno, U_REGS_OFFSET)); - } + convert_to_gregset (&buf, registers, register_valid); ret = ptrace (PTRACE_SETREGS, inferior_pid, 0, (int)buf); - - if ( ret < 0 ) + if (ret < 0) { - warning ("Couldn't write floating point status"); + warning ("Couldn't write registers"); return; } - } @@ -262,14 +292,13 @@ store_regs(void) upon the value of regno. */ void -fetch_inferior_registers (regno) - int regno; +fetch_inferior_registers (int regno) { - if ( (regno < NUM_REGS - NUM_FREGS) || (regno == -1) ) - fetch_regs(); + if (regno < NUM_GREGS || regno == -1) + fetch_regs (); - if ( (regno >= NUM_REGS - NUM_FREGS) || (regno == -1) ) - fetch_fpregs(); + if (regno >= NUM_GREGS || regno == -1) + fetch_fpregs (); } @@ -283,11 +312,11 @@ void store_inferior_registers (regno) int regno; { - if ( (regno < NUM_REGS - NUM_FREGS) || (regno == -1) ) - store_regs(); + if (regno < NUM_GREGS || regno == -1) + store_regs (); - if ( (regno >= NUM_REGS - NUM_FREGS) || (regno == -1) ) - store_fpregs(); + if (regno >= NUM_GREGS || regno == -1) + store_fpregs (); } |