diff options
author | Maciej W. Rozycki <macro@mips.com> | 2018-05-25 12:37:45 +0100 |
---|---|---|
committer | Maciej W. Rozycki <macro@mips.com> | 2018-05-25 12:37:45 +0100 |
commit | d8dab6c3bbe6432ff20237e621f2f3a3d30d4d4b (patch) | |
tree | b0ed461248f6415f6d719151730705cec70cf016 /gdb/mips-linux-tdep.c | |
parent | 3c69da406c72423afa4bd0e4fc4c805ec0b944a1 (diff) | |
download | gdb-d8dab6c3bbe6432ff20237e621f2f3a3d30d4d4b.zip gdb-d8dab6c3bbe6432ff20237e621f2f3a3d30d4d4b.tar.gz gdb-d8dab6c3bbe6432ff20237e621f2f3a3d30d4d4b.tar.bz2 |
MIPS/Linux: Correct o32 core file FGR interpretation
Our interpretation of the layout of floating-point general registers
(FGRs) in o32 MIPS/Linux core files is different from how the kernel
makes them, affecting the CP0 Status.FR=0 aka FP32 mode (we don't
currently support the CP0 Status.FR=1 aka FP64 mode with the o32 ABI).
In the FP32 mode pairs of consecutive even/odd-numbered 32-bit registers
are placed together as 64-bit values in even-indexed 64-bit slots
corresponding to the even index, leaving the odd-indexed 64-bit slots
unused. These 64-bit values are stored according to the endianness in
effect, which is how the MIPS II SDC1 instruction would store them.
It has always been like that with the Linux kernel for MIPS II and
higher ISA processors, which are the vast majority ever supported, as it
is indeed SDC1 that the kernel uses to store FGRs in a floating-point
context.
With MIPS I processors, which lack the SDC1 instruction, a layout that
we expect used to be used long ago, but it was corrected for consistency
with newer processors back in 2002, with `linux-mips.org' (LMO) commit
42533948caac ("Major pile of FP emulator changes."), the fix corrected
with LMO commit 849fa7a50dff ("R3k FPU ptrace() handling fixes."), and
then broken and fixed over and over again, until last time fixed with
commit 80cbfad79096 ("MIPS: Correct MIPS I FP context layout").
Consequently the values we see in FP32 core files or produce with the
`gcore' command are different from those obtained from the same FP
context of a live process, e.g. with a big-endian configuration these
live values:
(gdb) info registers float
f0: 0x4b5c6d7e flt: 14445950 dbl: 1.7446153562345001e-274
f1: 0x0718293a flt: 1.14473244e-34
f2: 0xc3d4e5f6 flt: -425.79657 dbl: -1.046160437414959e-233
f3: 0x8f90a1b2 flt: -1.42617791e-29
f4: 0x4c5d6e7f flt: 58046972 dbl: 1.1908587841220294e-269
f5: 0x08192a3b flt: 4.60914044e-34
f6: 0xc4d5e6f7 flt: -1711.21765 dbl: -6.2784661835068965e-306
f7: 0x8091a2b3 flt: -1.33745124e-38
f8: 0x45566778 flt: 3430.4668 dbl: 1.6530355595710607e-303
f9: 0x01122334 flt: 2.68412219e-38
f10: 0xcddeeff0 flt: -467533312 dbl: -2.1174864564135575e-262
f11: 0x899aabbc flt: -3.72356497e-33
f12: 0x46576879 flt: 13786.1182 dbl: 1.143296486773654e-298
f13: 0x02132435 flt: 1.08102453e-37
f14: 0xcedfe0f1 flt: -1.87803046e+09 dbl: -1.4399511533369862e-257
f15: 0x8a9bacbd flt: -1.4990934e-32
f16: 0x4758697a flt: 55401.4766 dbl: 7.8856820439568725e-294
f17: 0x03142536 flt: 4.3536007e-37
f18: 0xcfd0e1f2 flt: -7.00893696e+09 dbl: -9.7791926757340559e-253
f19: 0x8b9cadbe flt: -6.03504325e-32
f20: 0x48596a7b flt: 222633.922 dbl: 5.4255001483306113e-289
f21: 0x04152637 flt: 1.75324132e-36
f22: 0xc0d1e2f3 flt: -6.55895376 dbl: -6.6332401002310683e-248
f23: 0x8c9daebf flt: -2.42948516e-31
f24: 0x495a6b7c flt: 894647.75 dbl: 3.7244369058749787e-284
f25: 0x05162738 flt: 7.06016945e-36
f26: 0xc1d2e3f4 flt: -26.3613052 dbl: -4.4941535759306202e-243
f27: 0x8d9eafb0 flt: -9.77979703e-31
f28: 0x4a5b6c7d flt: 3595039.25 dbl: 2.5514593711161396e-279
f29: 0x06172839 flt: 2.84294945e-35
f30: 0xc2d3e4f5 flt: -105.947182 dbl: -3.035646690850097e-238
f31: 0x8e9fa0b1 flt: -3.93512664e-30
fcsr: 0x0
fir: 0xf30000
(gdb)
show up in a core file as these:
(gdb) info registers float
f0: 0x0718293a flt: 1.14473244e-34 dbl: nan
f1: 0x7ff80000 flt: nan
f2: 0x8f90a1b2 flt: -1.42617791e-29 dbl: nan
f3: 0x7ff80000 flt: nan
f4: 0x08192a3b flt: 4.60914044e-34 dbl: nan
f5: 0x7ff80000 flt: nan
f6: 0x8091a2b3 flt: -1.33745124e-38 dbl: nan
f7: 0x7ff80000 flt: nan
f8: 0x01122334 flt: 2.68412219e-38 dbl: nan
f9: 0x7ff80000 flt: nan
f10: 0x899aabbc flt: -3.72356497e-33 dbl: nan
f11: 0x7ff80000 flt: nan
f12: 0x02132435 flt: 1.08102453e-37 dbl: nan
f13: 0x7ff80000 flt: nan
f14: 0x8a9bacbd flt: -1.4990934e-32 dbl: nan
f15: 0x7ff80000 flt: nan
f16: 0x03142536 flt: 4.3536007e-37 dbl: nan
f17: 0x7ff80000 flt: nan
f18: 0x8b9cadbe flt: -6.03504325e-32 dbl: nan
f19: 0x7ff80000 flt: nan
f20: 0x04152637 flt: 1.75324132e-36 dbl: nan
f21: 0x7ff80000 flt: nan
f22: 0x8c9daebf flt: -2.42948516e-31 dbl: nan
f23: 0x7ff80000 flt: nan
f24: 0x05162738 flt: 7.06016945e-36 dbl: nan
f25: 0x7ff80000 flt: nan
f26: 0x8d9eafb0 flt: -9.77979703e-31 dbl: nan
f27: 0x7ff80000 flt: nan
f28: 0x06172839 flt: 2.84294945e-35 dbl: nan
f29: 0x7ff80000 flt: nan
f30: 0x8e9fa0b1 flt: -3.93512664e-30 dbl: nan
f31: 0x7ff80000 flt: nan
(gdb)
Notice how values from odd-numbered registers are shown in corresponding
even-numbered registers and how dummy 0x7ff80000 NaN values, which the
kernel places in unused slots, are reported in odd-numbered registers.
Correct our intepretation then, to match the kernel's. As it happens
the o32 FGR core file representation matches that used by the `ptrace'
PTRACE_GETFPREGS request, which means our 64-bit handlers can be readily
used, as they already correctly handle the differences between o32 FP32
mode vs n32/n64 representations.
Adjust comments accordingly throughout, in particular remove a reference
to the r3000/tx39 MIPS I processor peculiarity, long irrelevant.
Add a test case to verify correctness. Avoid GCC bugs and limitations
in the test case where possible; the test case still fails to build with
GCC 8 and the o32 FP64 mode (i.e. with `-mips32r2 -mfp64' options)
giving:
mips-fpregset-core.c: In function 'main':
mips-fpregset-core.c:66:3: error: inconsistent operand constraints in an 'asm'
asm (
^~~
(GCC PR target/85909), but that is not a concern for us as yet, because
as noted above we do not currently support the o32 FP64 mode anyway.
gdb/
* mips-linux-tdep.h (mips_supply_fpregset, mips_fill_fpregset):
Remove prototypes.
* mips-linux-nat.c (supply_fpregset): Always call
`mips64_supply_fpregset' rather than `mips_supply_fpregset'.
(fill_fpregset): Always call `mips64_fill_fpregset' rather than
`mips_fill_fpregset'.
* mips-linux-tdep.c (mips_supply_fpregset)
(mips_supply_fpregset_wrapper, mips_fill_fpregset)
(mips_fill_fpregset_wrapper): Remove functions.
(mips64_supply_fpregset, mips64_fill_fpregset): Update comments.
(mips_linux_fpregset): Remove variable.
(mips_linux_iterate_over_regset_sections): Use
`mips64_linux_fpregset' in place of `mips_linux_fpregset'.
(mips_linux_o32_sigframe_init): Remove comment.
gdb/testsuite/
* gdb.arch/mips-fpregset-core.exp: New test.
* gdb.arch/mips-fpregset-core.c: New test source.
Diffstat (limited to 'gdb/mips-linux-tdep.c')
-rw-r--r-- | gdb/mips-linux-tdep.c | 109 |
1 files changed, 13 insertions, 96 deletions
diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 175b402..e580424 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -233,82 +233,6 @@ mips_fill_gregset_wrapper (const struct regset *regset, mips_fill_gregset (regcache, (mips_elf_gregset_t *)gregs, regnum); } -/* Likewise, unpack an elf_fpregset_t. */ - -void -mips_supply_fpregset (struct regcache *regcache, - const mips_elf_fpregset_t *fpregsetp) -{ - struct gdbarch *gdbarch = regcache->arch (); - int regi; - - for (regi = 0; regi < 32; regi++) - regcache_raw_supply (regcache, - gdbarch_fp0_regnum (gdbarch) + regi, - *fpregsetp + regi); - - regcache_raw_supply (regcache, - mips_regnum (gdbarch)->fp_control_status, - *fpregsetp + 32); - - /* FIXME: how can we supply FCRIR? The ABI doesn't tell us. */ - regcache->raw_supply_zeroed - (mips_regnum (gdbarch)->fp_implementation_revision); -} - -static void -mips_supply_fpregset_wrapper (const struct regset *regset, - struct regcache *regcache, - int regnum, const void *gregs, size_t len) -{ - gdb_assert (len >= sizeof (mips_elf_fpregset_t)); - - mips_supply_fpregset (regcache, (const mips_elf_fpregset_t *)gregs); -} - -/* Likewise, pack one or all floating point registers into an - elf_fpregset_t. */ - -void -mips_fill_fpregset (const struct regcache *regcache, - mips_elf_fpregset_t *fpregsetp, int regno) -{ - struct gdbarch *gdbarch = regcache->arch (); - char *to; - - if ((regno >= gdbarch_fp0_regnum (gdbarch)) - && (regno < gdbarch_fp0_regnum (gdbarch) + 32)) - { - to = (char *) (*fpregsetp + regno - gdbarch_fp0_regnum (gdbarch)); - regcache_raw_collect (regcache, regno, to); - } - else if (regno == mips_regnum (gdbarch)->fp_control_status) - { - to = (char *) (*fpregsetp + 32); - regcache_raw_collect (regcache, regno, to); - } - else if (regno == -1) - { - int regi; - - for (regi = 0; regi < 32; regi++) - mips_fill_fpregset (regcache, fpregsetp, - gdbarch_fp0_regnum (gdbarch) + regi); - mips_fill_fpregset (regcache, fpregsetp, - mips_regnum (gdbarch)->fp_control_status); - } -} - -static void -mips_fill_fpregset_wrapper (const struct regset *regset, - const struct regcache *regcache, - int regnum, void *gregs, size_t len) -{ - gdb_assert (len >= sizeof (mips_elf_fpregset_t)); - - mips_fill_fpregset (regcache, (mips_elf_fpregset_t *)gregs, regnum); -} - /* Support for 64-bit ABIs. */ /* Figure out where the longjmp will land. @@ -473,7 +397,16 @@ mips64_fill_gregset_wrapper (const struct regset *regset, mips64_fill_gregset (regcache, (mips64_elf_gregset_t *)gregs, regnum); } -/* Likewise, unpack an elf_fpregset_t. */ +/* Likewise, unpack an elf_fpregset_t. Linux only uses even-numbered + FPR slots in the Status.FR=0 mode, storing even-odd FPR pairs as the + SDC1 instruction would. When run on MIPS I architecture processors + all FPR slots used to be used, unusually, holding the respective FPRs + in the first 4 bytes, but that was corrected for consistency, with + `linux-mips.org' (LMO) commit 42533948caac ("Major pile of FP emulator + changes."), the fix corrected with LMO commit 849fa7a50dff ("R3k FPU + ptrace() handling fixes."), and then broken and fixed over and over + again, until last time fixed with commit 80cbfad79096 ("MIPS: Correct + MIPS I FP context layout"). */ void mips64_supply_fpregset (struct regcache *regcache, @@ -482,8 +415,6 @@ mips64_supply_fpregset (struct regcache *regcache, struct gdbarch *gdbarch = regcache->arch (); int regi; - /* See mips_linux_o32_sigframe_init for a description of the - peculiar FP register layout. */ if (register_size (gdbarch, gdbarch_fp0_regnum (gdbarch)) == 4) for (regi = 0; regi < 32; regi++) { @@ -523,7 +454,8 @@ mips64_supply_fpregset_wrapper (const struct regset *regset, } /* Likewise, pack one or all floating point registers into an - elf_fpregset_t. */ + elf_fpregset_t. See `mips_supply_fpregset' for an explanation + of the layout. */ void mips64_fill_fpregset (const struct regcache *regcache, @@ -535,8 +467,6 @@ mips64_fill_fpregset (const struct regcache *regcache, if ((regno >= gdbarch_fp0_regnum (gdbarch)) && (regno < gdbarch_fp0_regnum (gdbarch) + 32)) { - /* See mips_linux_o32_sigframe_init for a description of the - peculiar FP register layout. */ if (register_size (gdbarch, regno) == 4) { int regi = regno - gdbarch_fp0_regnum (gdbarch); @@ -597,11 +527,6 @@ static const struct regset mips64_linux_gregset = NULL, mips64_supply_gregset_wrapper, mips64_fill_gregset_wrapper }; -static const struct regset mips_linux_fpregset = - { - NULL, mips_supply_fpregset_wrapper, mips_fill_fpregset_wrapper - }; - static const struct regset mips64_linux_fpregset = { NULL, mips64_supply_fpregset_wrapper, mips64_fill_fpregset_wrapper @@ -617,7 +542,7 @@ mips_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, { cb (".reg", sizeof (mips_elf_gregset_t), &mips_linux_gregset, NULL, cb_data); - cb (".reg2", sizeof (mips_elf_fpregset_t), &mips_linux_fpregset, + cb (".reg2", sizeof (mips64_elf_fpregset_t), &mips64_linux_fpregset, NULL, cb_data); } else @@ -1076,14 +1001,6 @@ mips_linux_o32_sigframe_init (const struct tramp_frame *self, (regs_base + SIGCONTEXT_REGS + ireg * SIGCONTEXT_REG_SIZE)); - /* The way that floating point registers are saved, unfortunately, - depends on the architecture the kernel is built for. For the r3000 and - tx39, four bytes of each register are at the beginning of each of the - 32 eight byte slots. For everything else, the registers are saved - using double precision; only the even-numbered slots are initialized, - and the high bits are the odd-numbered register. Assume the latter - layout, since we can't tell, and it's much more common. Which bits are - the "high" bits depends on endianness. */ for (ireg = 0; ireg < 32; ireg++) if ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) != (ireg & 1)) trad_frame_set_reg_addr (this_cache, |