aboutsummaryrefslogtreecommitdiff
path: root/gdb/i386-linux-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/i386-linux-nat.c')
-rw-r--r--gdb/i386-linux-nat.c291
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 *) &registers[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 *) &registers[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),
+ &registers[REGISTER_BYTE (FP0_REGNUM + i)],
+ REGISTER_RAW_SIZE(FP0_REGNUM + i));
+
+#define fill(MEMBER, REGNO) \
+ if (! valid || valid[(REGNO)]) \
+ memcpy (&fpregsetp->MEMBER, &registers[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 *) &registers[REGISTER_BYTE (FCS_REGNUM)] & 0xffff));
+
+ if (! valid || valid[FOP_REGNUM])
+ fpregsetp->fcs
+ = ((fpregsetp->fcs & 0xffff)
+ | ((*(int *) &registers[REGISTER_BYTE (FOP_REGNUM)] & ((1 << 11) - 1))
+ << 16));
+}
- to = (char *) &(fpregsetp->st_space[0]);
- for (regi = FPSTART_REGNUM ; regi <= FPEND_REGNUM ; regi++)
- {
- from = (char *) &registers[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 ();
}