From patchwork Fri May 25 11:41:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 27497 Received: (qmail 3769 invoked by alias); 25 May 2018 11:41:40 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 3754 invoked by uid 89); 25 May 2018 11:41:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-10.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.2 spammy=eight, hitting, uf, Former X-HELO: 9pmail.ess.barracuda.com Received: from 9pmail.ess.barracuda.com (HELO 9pmail.ess.barracuda.com) (64.235.154.211) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 25 May 2018 11:41:36 +0000 Received: from mipsdag02.mipstec.com (mail2.mips.com [12.201.5.32]) by mx1401.ess.rzc.cudaops.com (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA256 bits=128 verify=NO); Fri, 25 May 2018 11:41:21 +0000 Received: from [10.20.78.206] (10.20.78.206) by mipsdag02.mipstec.com (10.20.40.47) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1415.2; Fri, 25 May 2018 04:41:22 -0700 Date: Fri, 25 May 2018 12:41:12 +0100 From: "Maciej W. Rozycki" To: Subject: [committed] MIPS/Linux: Correct o32 core file FGR interpretation Message-ID: User-Agent: Alpine 2.00 (DEB 1167 2008-08-23) MIME-Version: 1.0 X-ClientProxiedBy: mipsdag02.mipstec.com (10.20.40.47) To mipsdag02.mipstec.com (10.20.40.47) X-BESS-ID: 1527248480-321457-26396-57638-1 X-BESS-VER: 2018.6-r1805181819 X-BESS-Apparent-Source-IP: 12.201.5.32 X-BESS-Outbound-Spam-Score: 1.00 X-BESS-Outbound-Spam-Report: Code version 3.2, rules version 3.2.2.193323 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------- 0.50 BSF_RULE7568M META: Custom Rule 7568M 0.50 BSF_RULE_7582B META: Custom Rule 7582B 0.00 BSF_BESS_OUTBOUND META: BESS Outbound X-BESS-Outbound-Spam-Status: SCORE=1.00 using account:ESS59374 scores of KILL_LEVEL=7.0 tests=BSF_RULE7568M, BSF_RULE_7582B, BSF_BESS_OUTBOUND X-BESS-BRTS-Status: 1 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. --- Hi, Verified native and native-gdbserver across o32, n32 and n64. Committed. Maciej --- gdb/mips-linux-nat.c | 12 -- gdb/mips-linux-tdep.c | 109 ++---------------- gdb/mips-linux-tdep.h | 2 gdb/testsuite/gdb.arch/mips-fpregset-core.c | 82 +++++++++++++ gdb/testsuite/gdb.arch/mips-fpregset-core.exp | 154 ++++++++++++++++++++++++++ 5 files changed, 251 insertions(+), 108 deletions(-) gdb-mips-linux-fpregset.diff Index: binutils/gdb/mips-linux-nat.c =================================================================== --- binutils.orig/gdb/mips-linux-nat.c 2018-05-23 17:10:05.000000000 +0100 +++ binutils/gdb/mips-linux-nat.c 2018-05-24 20:41:41.377061555 +0100 @@ -224,22 +224,14 @@ fill_gregset (const struct regcache *reg void supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp) { - if (mips_isa_regsize (regcache->arch ()) == 4) - mips_supply_fpregset (regcache, (const mips_elf_fpregset_t *) fpregsetp); - else - mips64_supply_fpregset (regcache, - (const mips64_elf_fpregset_t *) fpregsetp); + mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *) fpregsetp); } void fill_fpregset (const struct regcache *regcache, gdb_fpregset_t *fpregsetp, int regno) { - if (mips_isa_regsize (regcache->arch ()) == 4) - mips_fill_fpregset (regcache, (mips_elf_fpregset_t *) fpregsetp, regno); - else - mips64_fill_fpregset (regcache, - (mips64_elf_fpregset_t *) fpregsetp, regno); + mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *) fpregsetp, regno); } Index: binutils/gdb/mips-linux-tdep.c =================================================================== --- binutils.orig/gdb/mips-linux-tdep.c 2018-05-24 11:06:44.384139557 +0100 +++ binutils/gdb/mips-linux-tdep.c 2018-05-24 20:54:14.911206975 +0100 @@ -233,82 +233,6 @@ mips_fill_gregset_wrapper (const struct 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 struc 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 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 st } /* 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 regca 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_ 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 { 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 stru (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, Index: binutils/gdb/mips-linux-tdep.h =================================================================== --- binutils.orig/gdb/mips-linux-tdep.h 2018-02-23 14:14:31.000000000 +0000 +++ binutils/gdb/mips-linux-tdep.h 2018-05-24 20:42:43.391199979 +0100 @@ -52,8 +52,6 @@ typedef mips_elf_fpreg_t mips_elf_fpregs void mips_supply_gregset (struct regcache *, const mips_elf_gregset_t *); void mips_fill_gregset (const struct regcache *, mips_elf_gregset_t *, int); -void mips_supply_fpregset (struct regcache *, const mips_elf_fpregset_t *); -void mips_fill_fpregset (const struct regcache *, mips_elf_fpregset_t *, int); /* 64-bit support. */ Index: binutils/gdb/testsuite/gdb.arch/mips-fpregset-core.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ binutils/gdb/testsuite/gdb.arch/mips-fpregset-core.c 2018-05-24 13:52:43.065613141 +0100 @@ -0,0 +1,82 @@ +/* This test is part of GDB, the GNU debugger. + + Copyright 2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +int __attribute__ ((nomips16)) +main (void) +{ + /* We need to use a complex type to avoid hitting GCC's limit of + the number of `asm' operands: + + mips-fpregset-core.f: In function 'main': + mips-fpregset-core.f:66:3: error: more than 30 operands in 'asm' + asm ( + ^~~ + + and still have complete 32 FGR coverage with FP64 ABIs. Using + a complex type breaks o32 GCC though, so use plain `double' with + FP32. */ +#if _MIPS_FPSET == 32 + typedef double _Complex float_t; +#else + typedef double float_t; +#endif + union + { + uint64_t i[32]; + float_t f[256 / sizeof (float_t)]; + } + u = + { .i = + { + 0x0112233445566778, 0x899aabbccddeeff0, + 0x0213243546576879, 0x8a9bacbdcedfe0f1, + 0x031425364758697a, 0x8b9cadbecfd0e1f2, + 0x0415263748596a7b, 0x8c9daebfc0d1e2f3, + 0x05162738495a6b7c, 0x8d9eafb0c1d2e3f4, + 0x061728394a5b6c7d, 0x8e9fa0b1c2d3e4f5, + 0x0718293a4b5c6d7e, 0x8f90a1b2c3d4e5f6, + 0x08192a3b4c5d6e7f, 0x8091a2b3c4d5e6f7, + 0x091a2b3c4d5e6f70, 0x8192a3b4c5d6e7f8, + 0x0a1b2c3d4e5f6071, 0x8293a4b5c6d7e8f9, + 0x0b1c2d3e4f506172, 0x8394a5b6c7d8e9fa, + 0x0c1d2e3f40516273, 0x8495a6b7c8d9eafb, + 0x0d1e2f3041526374, 0x8596a7b8c9daebfc, + 0x0e1f203142536475, 0x8697a8b9cadbecfd, + 0x0f10213243546576, 0x8798a9bacbdcedfe, + 0x0011223344556677, 0x8899aabbccddeeff + } + }; + + asm ( + ".globl\tbreak_here\n\t" + ".aent\tbreak_here\n" + "break_here:\n\t" + "lb\t$0,0($0)\n" + : + : [f0] "f" (u.f[0]), [f2] "f" (u.f[1]), + [f4] "f" (u.f[2]), [f6] "f" (u.f[3]), + [f8] "f" (u.f[4]), [f10] "f" (u.f[5]), + [f12] "f" (u.f[6]), [f14] "f" (u.f[7]), + [f16] "f" (u.f[8]), [f18] "f" (u.f[9]), + [f20] "f" (u.f[10]), [f22] "f" (u.f[11]), + [f24] "f" (u.f[12]), [f26] "f" (u.f[13]), + [f28] "f" (u.f[14]), [f30] "f" (u.f[15])); + + return 0; +} Index: binutils/gdb/testsuite/gdb.arch/mips-fpregset-core.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ binutils/gdb/testsuite/gdb.arch/mips-fpregset-core.exp 2018-05-24 18:12:19.286363209 +0100 @@ -0,0 +1,154 @@ +# Copyright 2018 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test MIPS Floating Point General Register handling in core files. + +if { ![istarget "mips*-*-*"] } then { + verbose "Skipping MIPS Floating Point General Register tests." + return +} + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile}] } { + return +} + +# Procedure to get current content of all floating-point registers. +proc mips_fpregset_core_fetch_float_registers { test } { + global gdb_prompt + + set all_registers_lines {} + set bad -1 + # Former trailing `\[\r\n\]+' may eat just \r leaving \n in the buffer + # corrupting the next matches. + if { [gdb_test_multiple "info registers float" $test { + -re "info registers float\r\n" { + exp_continue + } + -ex "The program has no registers now" { + set bad 1 + exp_continue + } + -re "^\(?:fcsr\|fir\):\[ \t\]+\[^\r\n\]+\r\n" { + # Filter out control registers. They may or may not be a part + # of the float group depending on whether XML descriptions are + # used or not. + exp_continue + } + -re "^\[^ \t\]+\[ \t\]+\[^\r\n\]+\r\n" { + lappend all_registers_lines $expect_out(0,string) + exp_continue + } + -re "$gdb_prompt $" { + incr bad + } + -re "^\[^\r\n\]+\r\n" { + if { !$bad } { + warning "Unrecognized output: $expect_out(0,string)" + set bad 1 + } + exp_continue + } + }] != 0 } { + return {} + } + + if { $bad } { + fail $test + return {} + } + + pass $test + return $all_registers_lines +} + +# Generate a native core file. + +set corefile [core_find $binfile] +set core_supported [expr {$corefile != ""}] + +# Generate a core file with "gcore". + +clean_restart ${binfile} + +runto break_here + +# Check if we have an FPU available. +gdb_test_multiple "show mipsfpu" "check for MIPS floating-point coprocessor" { + -re "The MIPS floating-point coprocessor\ + .*\(absent\|unknown\).*$gdb_prompt $" { + unsupported "no MIPS floating-point coprocessor in the processor" + return + } + -re "The MIPS floating-point coprocessor .*$gdb_prompt $" { + verbose "MIPS floating-point coprocessor check successful." + } + default { + fail + return + } +} + +# Save live FGR register contents. +set live_fgr_contents [mips_fpregset_core_fetch_float_registers \ + "retrieve live FGR register contents"] + +set gcorefile [standard_output_file gcore.test] +set gcore_supported [gdb_gcore_cmd "$gcorefile" "gcore"] + +# Restart gdb and load COREFILE as a core file. SUPPORTED is true iff +# the core was generated successfully; otherwise, the tests are marked +# unsupported. +# +proc mips_fpregset_core_test { supported corefile } { + upvar live_fgr_contents live_fgr_contents + upvar target_triplet target_triplet + upvar host_triplet host_triplet + upvar binfile binfile + + clean_restart ${binfile} + + set test "load core file" + if { $supported } { + set core_loaded [gdb_core_cmd $corefile $test] + } else { + set core_loaded 0 + unsupported $test + } + + if { $core_loaded == 1 } { + set test "core file FGR register contents" + set core_fgr_contents \ + [mips_fpregset_core_fetch_float_registers "retrieve $test"] + if { $core_fgr_contents == $live_fgr_contents } then { + pass $test + } else { + fail $test + } + } else { + unsupported $test + } +} + +with_test_prefix "native" { + mips_fpregset_core_test $core_supported $corefile +} + +with_test_prefix "gcore" { + mips_fpregset_core_test $gcore_supported $gcorefile +} + +gdb_exit