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 <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+
+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 <http://www.gnu.org/licenses/>.
+
+# 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
