Power4 should treat mftb as extended mfspr mnemonic
[platform/upstream/binutils.git] / gdb / sparc-tdep.c
index 2b87d77..7eb3b18 100644 (file)
@@ -1,7 +1,6 @@
 /* Target-dependent code for SPARC.
 
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 2003-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "target.h"
 #include "value.h"
 
-#include "gdb_assert.h"
-#include "gdb_string.h"
-
 #include "sparc-tdep.h"
+#include "sparc-ravenscar-thread.h"
 
 struct regset;
 
@@ -63,7 +60,7 @@ struct regset;
    sparc64-tdep.c; don't add any here.  */
 
 /* The SPARC Floating-Point Quad-Precision format is similar to
-   big-endian IA-64 Quad-recision format.  */
+   big-endian IA-64 Quad-Precision format.  */
 #define floatformats_sparc_quad floatformats_ia64_quad
 
 /* The stack pointer is offset from the stack frame by a BIAS of 2047
@@ -86,7 +83,11 @@ struct regset;
 /* Sign extension macros.  */
 #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
 #define X_DISP19(i) ((((i) & 0x7ffff) ^ 0x40000) - 0x40000)
+#define X_DISP10(i) ((((((i) >> 11) && 0x300) | (((i) >> 5) & 0xff)) ^ 0x200) - 0x200)
 #define X_SIMM13(i) ((((i) & 0x1fff) ^ 0x1000) - 0x1000)
+/* Macros to identify some instructions.  */
+/* RETURN (RETT in V8) */
+#define X_RETTURN(i) ((X_OP (i) == 0x2) && (X_OP3 (i) == 0x39))
 
 /* Fetch the instruction at PC.  Instructions are always big-endian
    even if the processor operates in little-endian mode.  */
@@ -120,6 +121,37 @@ sparc_is_unimp_insn (CORE_ADDR pc)
   return ((insn & 0xc1c00000) == 0);
 }
 
+/* Return non-zero if the instruction corresponding to PC is an
+   "annulled" branch, i.e. the annul bit is set.  */
+
+int
+sparc_is_annulled_branch_insn (CORE_ADDR pc)
+{
+  /* The branch instructions featuring an annul bit can be identified
+     by the following bit patterns:
+
+     OP=0
+      OP2=1: Branch on Integer Condition Codes with Prediction (BPcc).
+      OP2=2: Branch on Integer Condition Codes (Bcc).
+      OP2=5: Branch on FP Condition Codes with Prediction (FBfcc).
+      OP2=6: Branch on FP Condition Codes (FBcc).
+      OP2=3 && Bit28=0:
+             Branch on Integer Register with Prediction (BPr).
+
+     This leaves out ILLTRAP (OP2=0), SETHI/NOP (OP2=4) and the V8
+     coprocessor branch instructions (Op2=7).  */
+
+  const unsigned long insn = sparc_fetch_instruction (pc);
+  const unsigned op2 = X_OP2 (insn);
+
+  if ((X_OP (insn) == 0)
+      && ((op2 == 1) || (op2 == 2) || (op2 == 5) || (op2 == 6)
+         || ((op2 == 3) && ((insn & 0x10000000) == 0))))
+    return X_A (insn);
+  else
+    return 0;
+}
+
 /* OpenBSD/sparc includes StackGhost, which according to the author's
    website http://stackghost.cerias.purdue.edu "... transparently and
    automatically protects applications' stack frames; more
@@ -145,15 +177,16 @@ sparc_is_unimp_insn (CORE_ADDR pc)
 
    More information on StackGuard can be found on in:
 
-   Mike Frantzen and Mike Shuey. "StackGhost: Hardware Facilitated
+   Mike Frantzen and Mike Shuey.  "StackGhost: Hardware Facilitated
    Stack Protection."  2001.  Published in USENIX Security Symposium
    '01.  */
 
 /* Fetch StackGhost Per-Process XOR cookie.  */
 
 ULONGEST
-sparc_fetch_wcookie (void)
+sparc_fetch_wcookie (struct gdbarch *gdbarch)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   struct target_ops *ops = &current_target;
   gdb_byte buf[8];
   int len;
@@ -165,7 +198,7 @@ sparc_fetch_wcookie (void)
   /* We should have either an 32-bit or an 64-bit cookie.  */
   gdb_assert (len == 4 || len == 8);
 
-  return extract_unsigned_integer (buf, len);
+  return extract_unsigned_integer (buf, len, byte_order);
 }
 \f
 
@@ -220,7 +253,30 @@ sparc_floating_p (const struct type *type)
   return 0;
 }
 
-/* Check whether TYPE is "Structure or Union".  */
+/* Check whether TYPE is "Complex Floating".  */
+
+static int
+sparc_complex_floating_p (const struct type *type)
+{
+  switch (TYPE_CODE (type))
+    {
+    case TYPE_CODE_COMPLEX:
+      {
+       int len = TYPE_LENGTH (type);
+       return (len == 8 || len == 16 || len == 32);
+      }
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+/* Check whether TYPE is "Structure or Union".
+
+   In terms of Ada subprogram calls, arrays are treated the same as
+   struct and union types.  So this function also returns non-zero
+   for array types.  */
 
 static int
 sparc_structure_or_union_p (const struct type *type)
@@ -229,6 +285,7 @@ sparc_structure_or_union_p (const struct type *type)
     {
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
+    case TYPE_CODE_ARRAY:
       return 1;
     default:
       break;
@@ -341,7 +398,7 @@ sparc_fsr_type (struct gdbarch *gdbarch)
 }
 
 /* Return the GDB type object for the "standard" data type of data in
-   register REGNUM. */
+   register REGNUM.  */
 
 static struct type *
 sparc32_register_type (struct gdbarch *gdbarch, int regnum)
@@ -367,16 +424,20 @@ sparc32_register_type (struct gdbarch *gdbarch, int regnum)
   return builtin_type (gdbarch)->builtin_int32;
 }
 
-static void
+static enum register_status
 sparc32_pseudo_register_read (struct gdbarch *gdbarch,
                              struct regcache *regcache,
                              int regnum, gdb_byte *buf)
 {
+  enum register_status status;
+
   gdb_assert (regnum >= SPARC32_D0_REGNUM && regnum <= SPARC32_D30_REGNUM);
 
   regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC32_D0_REGNUM);
-  regcache_raw_read (regcache, regnum, buf);
-  regcache_raw_read (regcache, regnum + 1, buf + 4);
+  status = regcache_raw_read (regcache, regnum, buf);
+  if (status == REG_VALID)
+    status = regcache_raw_read (regcache, regnum + 1, buf + 4);
+  return status;
 }
 
 static void
@@ -391,6 +452,36 @@ sparc32_pseudo_register_write (struct gdbarch *gdbarch,
   regcache_raw_write (regcache, regnum + 1, buf + 4);
 }
 \f
+/* Implement "in_function_epilogue_p".  */
+
+int
+sparc_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  /* This function must return true if we are one instruction after an
+     instruction that destroyed the stack frame of the current
+     function.  The SPARC instructions used to restore the callers
+     stack frame are RESTORE and RETURN/RETT.
+
+     Of these RETURN/RETT is a branch instruction and thus we return
+     true if we are in its delay slot.
+
+     RESTORE is almost always found in the delay slot of a branch
+     instruction that transfers control to the caller, such as JMPL.
+     Thus the next instruction is in the caller frame and we don't
+     need to do anything about it.  */
+
+  unsigned int insn = sparc_fetch_instruction (pc - 4);
+
+  return X_RETTURN (insn);
+}
+\f
+
+static CORE_ADDR
+sparc32_frame_align (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+  /* The ABI requires double-word alignment.  */
+  return address & ~0x7;
+}
 
 static CORE_ADDR
 sparc32_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
@@ -400,6 +491,8 @@ sparc32_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
                         CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
                         struct regcache *regcache)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
   *bp_addr = sp - 4;
   *real_pc = funcaddr;
 
@@ -408,7 +501,8 @@ sparc32_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
       gdb_byte buf[4];
 
       /* This is an UNIMP instruction.  */
-      store_unsigned_integer (buf, 4, TYPE_LENGTH (value_type) & 0x1fff);
+      store_unsigned_integer (buf, 4, byte_order,
+                             TYPE_LENGTH (value_type) & 0x1fff);
       write_memory (sp - 8, buf, 4);
       return sp - 8;
     }
@@ -422,6 +516,7 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
                         int struct_return, CORE_ADDR struct_addr)
 {
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   /* Number of words in the "parameter array".  */
   int num_elements = 0;
   int element = 0;
@@ -433,7 +528,8 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
       int len = TYPE_LENGTH (type);
 
       if (sparc_structure_or_union_p (type)
-         || (sparc_floating_p (type) && len == 16))
+         || (sparc_floating_p (type) && len == 16)
+         || sparc_complex_floating_p (type))
        {
          /* Structure, Union and Quad-Precision Arguments.  */
          sp -= len;
@@ -504,7 +600,7 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
     {
       gdb_byte buf[4];
 
-      store_unsigned_integer (buf, 4, struct_addr);
+      store_unsigned_integer (buf, 4, byte_order, struct_addr);
       write_memory (sp, buf, 4);
     }
 
@@ -561,7 +657,6 @@ static struct sparc_frame_cache *
 sparc_alloc_frame_cache (void)
 {
   struct sparc_frame_cache *cache;
-  int i;
 
   cache = FRAME_OBSTACK_ZALLOC (struct sparc_frame_cache);
 
@@ -571,7 +666,9 @@ sparc_alloc_frame_cache (void)
 
   /* Frameless until proven otherwise.  */
   cache->frameless_p = 1;
-
+  cache->frame_offset = 0;
+  cache->saved_regs_mask = 0;
+  cache->copied_regs_mask = 0;
   cache->struct_return_p = 0;
 
   return cache;
@@ -588,19 +685,46 @@ sparc_skip_stack_check (const CORE_ADDR start_pc)
   CORE_ADDR pc = start_pc;
   unsigned long insn;
   int offset_stack_checking_sequence = 0;
+  int probing_loop = 0;
 
   /* With GCC, all stack checking sequences begin with the same two
-     instructions.  */
+     instructions, plus an optional one in the case of a probing loop:
+
+         sethi <some immediate>, %g1
+         sub %sp, %g1, %g1
+
+     or:
+
+         sethi <some immediate>, %g1
+         sethi <some immediate>, %g4
+         sub %sp, %g1, %g1
 
-  /* sethi <some immediate>,%g1 */
+     or:
+
+         sethi <some immediate>, %g1
+         sub %sp, %g1, %g1
+         sethi <some immediate>, %g4
+
+     If the optional instruction is found (setting g4), assume that a
+     probing loop will follow.  */
+
+  /* sethi <some immediate>, %g1 */
   insn = sparc_fetch_instruction (pc);
   pc = pc + 4;
   if (!(X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 1))
     return start_pc;
 
-  /* sub %sp, %g1, %g1 */
+  /* optional: sethi <some immediate>, %g4 */
   insn = sparc_fetch_instruction (pc);
   pc = pc + 4;
+  if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+    {
+      probing_loop = 1;
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+    }
+
+  /* sub %sp, %g1, %g1 */
   if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
         && X_RD (insn) == 1 && X_RS1 (insn) == 14 && X_RS2 (insn) == 1))
     return start_pc;
@@ -608,6 +732,14 @@ sparc_skip_stack_check (const CORE_ADDR start_pc)
   insn = sparc_fetch_instruction (pc);
   pc = pc + 4;
 
+  /* optional: sethi <some immediate>, %g4 */
+  if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+    {
+      probing_loop = 1;
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+    }
+
   /* First possible sequence:
          [first two instructions above]
          clr [%g1 - some immediate]  */
@@ -659,22 +791,21 @@ sparc_skip_stack_check (const CORE_ADDR start_pc)
     }
   
   /* Third sequence: A probing loop.
-         [first two instructions above]
-         sethi  <some immediate>, %g4
+         [first three instructions above]
          sub  %g1, %g4, %g4
          cmp  %g1, %g4
          be  <disp>
          add  %g1, -<some immediate>, %g1
          ba  <disp>
          clr  [%g1]
+
+     And an optional last probe for the remainder:
+
          clr [%g4 - some immediate]  */
 
-  /* sethi  <some immediate>, %g4 */
-  else if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+  if (probing_loop)
     {
       /* sub  %g1, %g4, %g4 */
-      insn = sparc_fetch_instruction (pc);
-      pc = pc + 4;
       if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
             && X_RD (insn) == 4 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
         return start_pc;
@@ -705,28 +836,55 @@ sparc_skip_stack_check (const CORE_ADDR start_pc)
       if (!(X_OP (insn) == 0 && X_COND (insn) == 0x8))
         return start_pc;
 
-      /* clr  [%g1] */
+      /* clr  [%g1] (st %g0, [%g1] or st %g0, [%g1+0]) */
       insn = sparc_fetch_instruction (pc);
       pc = pc + 4;
-      if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
-            && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+      if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4
+            && X_RD (insn) == 0 && X_RS1 (insn) == 1
+           && (!X_I(insn) || X_SIMM13 (insn) == 0)))
         return start_pc;
 
-      /* clr [%g4 - some immediate]  */
+      /* We found a valid stack-check sequence, return the new PC.  */
+
+      /* optional: clr [%g4 - some immediate]  */
       insn = sparc_fetch_instruction (pc);
       pc = pc + 4;
       if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
             && X_RS1 (insn) == 4 && X_RD (insn) == 0))
-        return start_pc;
-
-      /* We found a valid stack-check sequence, return the new PC.  */
-      return pc;
+        return pc - 4;
+      else
+       return pc;
     }
 
   /* No stack check code in our prologue, return the start_pc.  */
   return start_pc;
 }
 
+/* Record the effect of a SAVE instruction on CACHE.  */
+
+void
+sparc_record_save_insn (struct sparc_frame_cache *cache)
+{
+  /* The frame is set up.  */
+  cache->frameless_p = 0;
+
+  /* The frame pointer contains the CFA.  */
+  cache->frame_offset = 0;
+
+  /* The `local' and `in' registers are all saved.  */
+  cache->saved_regs_mask = 0xffff;
+
+  /* The `out' registers are all renamed.  */
+  cache->copied_regs_mask = 0xff;
+}
+
+/* Do a full analysis of the prologue at PC and update CACHE accordingly.
+   Bail out early if CURRENT_PC is reached.  Return the address where
+   the analysis stopped.
+
+   We handle both the traditional register window model and the single
+   register window (aka flat) model.  */
+
 CORE_ADDR
 sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
                        CORE_ADDR current_pc, struct sparc_frame_cache *cache)
@@ -751,18 +909,45 @@ sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
      dynamic linker patches up the first PLT with some code that
      starts with a SAVE instruction.  Patch up PC such that it points
      at the start of our PLT entry.  */
-  if (tdep->plt_entry_size > 0 && in_plt_section (current_pc, NULL))
+  if (tdep->plt_entry_size > 0 && in_plt_section (current_pc))
     pc = current_pc - ((current_pc - pc) % tdep->plt_entry_size);
 
   insn = sparc_fetch_instruction (pc);
 
+  /* Recognize store insns and record their sources.  */
+  while (X_OP (insn) == 3
+        && (X_OP3 (insn) == 0x4     /* stw */
+            || X_OP3 (insn) == 0x7  /* std */
+            || X_OP3 (insn) == 0xe) /* stx */
+        && X_RS1 (insn) == SPARC_SP_REGNUM)
+    {
+      int regnum = X_RD (insn);
+
+      /* Recognize stores into the corresponding stack slots.  */
+      if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM
+         && ((X_I (insn)
+              && X_SIMM13 (insn) == (X_OP3 (insn) == 0xe
+                                     ? (regnum - SPARC_L0_REGNUM) * 8 + BIAS
+                                     : (regnum - SPARC_L0_REGNUM) * 4))
+             || (!X_I (insn) && regnum == SPARC_L0_REGNUM)))
+       {
+         cache->saved_regs_mask |= (1 << (regnum - SPARC_L0_REGNUM));
+         if (X_OP3 (insn) == 0x7)
+           cache->saved_regs_mask |= (1 << (regnum + 1 - SPARC_L0_REGNUM));
+       }
+
+      offset += 4;
+
+      insn = sparc_fetch_instruction (pc + offset);
+    }
+
   /* Recognize a SETHI insn and record its destination.  */
   if (X_OP (insn) == 0 && X_OP2 (insn) == 0x04)
     {
       dest = X_RD (insn);
       offset += 4;
 
-      insn = sparc_fetch_instruction (pc + 4);
+      insn = sparc_fetch_instruction (pc + offset);
     }
 
   /* Allow for an arithmetic operation on DEST or %g1.  */
@@ -771,14 +956,62 @@ sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
     {
       offset += 4;
 
-      insn = sparc_fetch_instruction (pc + 8);
+      insn = sparc_fetch_instruction (pc + offset);
     }
 
   /* Check for the SAVE instruction that sets up the frame.  */
   if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3c)
     {
-      cache->frameless_p = 0;
-      return pc + offset + 4;
+      sparc_record_save_insn (cache);
+      offset += 4;
+      return pc + offset;
+    }
+
+  /* Check for an arithmetic operation on %sp.  */
+  if (X_OP (insn) == 2
+      && (X_OP3 (insn) == 0 || X_OP3 (insn) == 0x4)
+      && X_RS1 (insn) == SPARC_SP_REGNUM
+      && X_RD (insn) == SPARC_SP_REGNUM)
+    {
+      if (X_I (insn))
+       {
+         cache->frame_offset = X_SIMM13 (insn);
+         if (X_OP3 (insn) == 0)
+           cache->frame_offset = -cache->frame_offset;
+       }
+      offset += 4;
+
+      insn = sparc_fetch_instruction (pc + offset);
+
+      /* Check for an arithmetic operation that sets up the frame.  */
+      if (X_OP (insn) == 2
+         && (X_OP3 (insn) == 0 || X_OP3 (insn) == 0x4)
+         && X_RS1 (insn) == SPARC_SP_REGNUM
+         && X_RD (insn) == SPARC_FP_REGNUM)
+       {
+         cache->frameless_p = 0;
+         cache->frame_offset = 0;
+         /* We could check that the amount subtracted to %sp above is the
+            same as the one added here, but this seems superfluous.  */
+         cache->copied_regs_mask |= 0x40;
+         offset += 4;
+
+         insn = sparc_fetch_instruction (pc + offset);
+       }
+
+      /* Check for a move (or) operation that copies the return register.  */
+      if (X_OP (insn) == 2
+         && X_OP3 (insn) == 0x2
+         && !X_I (insn)
+         && X_RS1 (insn) == SPARC_G0_REGNUM
+         && X_RS2 (insn) == SPARC_O7_REGNUM
+         && X_RD (insn) == SPARC_I7_REGNUM)
+       {
+          cache->copied_regs_mask |= 0x80;
+          offset += 4;
+       }
+
+      return pc + offset;
     }
 
   return pc;
@@ -821,21 +1054,36 @@ sparc32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
      indeed what GCC seems to be doing.  In that case GCC will
      generate debug information that points to the stack slots instead
      of the registers, so we should consider the instructions that
-     write out these incoming arguments onto the stack.  Of course we
-     only need to do this if we have a stack frame.  */
+     write out these incoming arguments onto the stack.  */
 
-  while (!cache.frameless_p)
+  while (1)
     {
       unsigned long insn = sparc_fetch_instruction (start_pc);
 
-      /* Recognize instructions that store incoming arguments in
-         %i0...%i5 into the corresponding stack slot.  */
-      if (X_OP (insn) == 3 && (X_OP3 (insn) & 0x3c) == 0x04 && X_I (insn)
-         && (X_RD (insn) >= 24 && X_RD (insn) <= 29) && X_RS1 (insn) == 30
-         && X_SIMM13 (insn) == 68 + (X_RD (insn) - 24) * 4)
+      /* Recognize instructions that store incoming arguments into the
+        corresponding stack slots.  */
+      if (X_OP (insn) == 3 && (X_OP3 (insn) & 0x3c) == 0x04
+         && X_I (insn) && X_RS1 (insn) == SPARC_FP_REGNUM)
        {
-         start_pc += 4;
-         continue;
+         int regnum = X_RD (insn);
+
+         /* Case of arguments still in %o[0..5].  */
+         if (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O5_REGNUM
+             && !(cache.copied_regs_mask & (1 << (regnum - SPARC_O0_REGNUM)))
+             && X_SIMM13 (insn) == 68 + (regnum - SPARC_O0_REGNUM) * 4)
+           {
+             start_pc += 4;
+             continue;
+           }
+
+         /* Case of arguments copied into %i[0..5].  */
+         if (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I5_REGNUM
+             && (cache.copied_regs_mask & (1 << (regnum - SPARC_I0_REGNUM)))
+             && X_SIMM13 (insn) == 68 + (regnum - SPARC_I0_REGNUM) * 4)
+           {
+             start_pc += 4;
+             continue;
+           }
        }
 
       break;
@@ -878,6 +1126,8 @@ sparc_frame_cache (struct frame_info *this_frame, void **this_cache)
        get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
     }
 
+  cache->base += cache->frame_offset;
+
   if (cache->base & 1)
     cache->base += BIAS;
 
@@ -926,7 +1176,8 @@ sparc32_frame_cache (struct frame_info *this_frame, void **this_cache)
          an "unimp" instruction.  If it is, then it is a struct-return
          function.  */
       CORE_ADDR pc;
-      int regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
+      int regnum =
+       (cache->copied_regs_mask & 0x80) ? SPARC_I7_REGNUM : SPARC_O7_REGNUM;
 
       pc = get_frame_register_unsigned (this_frame, regnum) + 8;
       if (sparc_is_unimp_insn (pc))
@@ -954,6 +1205,7 @@ static struct value *
 sparc32_frame_prev_register (struct frame_info *this_frame,
                             void **this_cache, int regnum)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct sparc_frame_cache *cache =
     sparc32_frame_cache (this_frame, this_cache);
 
@@ -967,14 +1219,15 @@ sparc32_frame_prev_register (struct frame_info *this_frame,
       if (cache->struct_return_p)
        pc += 4;
 
-      regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
+      regnum =
+       (cache->copied_regs_mask & 0x80) ? SPARC_I7_REGNUM : SPARC_O7_REGNUM;
       pc += get_frame_register_unsigned (this_frame, regnum) + 8;
       return frame_unwind_got_constant (this_frame, regnum, pc);
     }
 
   /* Handle StackGhost.  */
   {
-    ULONGEST wcookie = sparc_fetch_wcookie ();
+    ULONGEST wcookie = sparc_fetch_wcookie (gdbarch);
 
     if (wcookie != 0 && !cache->frameless_p && regnum == SPARC_I7_REGNUM)
       {
@@ -987,20 +1240,20 @@ sparc32_frame_prev_register (struct frame_info *this_frame,
       }
   }
 
-  /* The previous frame's `local' and `in' registers have been saved
+  /* The previous frame's `local' and `in' registers may have been saved
      in the register save area.  */
-  if (!cache->frameless_p
-      && regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
+  if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM
+      && (cache->saved_regs_mask & (1 << (regnum - SPARC_L0_REGNUM))))
     {
       CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 4;
 
       return frame_unwind_got_memory (this_frame, regnum, addr);
     }
 
-  /* The previous frame's `out' registers are accessible as the
-     current frame's `in' registers.  */
-  if (!cache->frameless_p
-      && regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+  /* The previous frame's `out' registers may be accessible as the current
+     frame's `in' registers.  */
+  if (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM
+      && (cache->copied_regs_mask & (1 << (regnum - SPARC_O0_REGNUM))))
     regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
 
   return frame_unwind_got_register (this_frame, regnum, regnum);
@@ -1009,6 +1262,7 @@ sparc32_frame_prev_register (struct frame_info *this_frame,
 static const struct frame_unwind sparc32_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   sparc32_frame_this_id,
   sparc32_frame_prev_register,
   NULL,
@@ -1053,17 +1307,29 @@ sparc32_extract_return_value (struct type *type, struct regcache *regcache,
                              gdb_byte *valbuf)
 {
   int len = TYPE_LENGTH (type);
-  gdb_byte buf[8];
+  gdb_byte buf[32];
 
   gdb_assert (!sparc_structure_or_union_p (type));
   gdb_assert (!(sparc_floating_p (type) && len == 16));
 
-  if (sparc_floating_p (type))
+  if (sparc_floating_p (type) || sparc_complex_floating_p (type))
     {
       /* Floating return values.  */
       regcache_cooked_read (regcache, SPARC_F0_REGNUM, buf);
       if (len > 4)
        regcache_cooked_read (regcache, SPARC_F1_REGNUM, buf + 4);
+      if (len > 8)
+       {
+         regcache_cooked_read (regcache, SPARC_F2_REGNUM, buf + 8);
+         regcache_cooked_read (regcache, SPARC_F3_REGNUM, buf + 12);
+       }
+      if (len > 16)
+       {
+         regcache_cooked_read (regcache, SPARC_F4_REGNUM, buf + 16);
+         regcache_cooked_read (regcache, SPARC_F5_REGNUM, buf + 20);
+         regcache_cooked_read (regcache, SPARC_F6_REGNUM, buf + 24);
+         regcache_cooked_read (regcache, SPARC_F7_REGNUM, buf + 28);
+       }
       memcpy (valbuf, buf, len);
     }
   else
@@ -1099,14 +1365,27 @@ sparc32_store_return_value (struct type *type, struct regcache *regcache,
 
   gdb_assert (!sparc_structure_or_union_p (type));
   gdb_assert (!(sparc_floating_p (type) && len == 16));
+  gdb_assert (len <= 8);
 
-  if (sparc_floating_p (type))
+  if (sparc_floating_p (type) || sparc_complex_floating_p (type))
     {
       /* Floating return values.  */
       memcpy (buf, valbuf, len);
       regcache_cooked_write (regcache, SPARC_F0_REGNUM, buf);
       if (len > 4)
        regcache_cooked_write (regcache, SPARC_F1_REGNUM, buf + 4);
+      if (len > 8)
+       {
+         regcache_cooked_write (regcache, SPARC_F2_REGNUM, buf + 8);
+         regcache_cooked_write (regcache, SPARC_F3_REGNUM, buf + 12);
+       }
+      if (len > 16)
+       {
+         regcache_cooked_write (regcache, SPARC_F4_REGNUM, buf + 16);
+         regcache_cooked_write (regcache, SPARC_F5_REGNUM, buf + 20);
+         regcache_cooked_write (regcache, SPARC_F6_REGNUM, buf + 24);
+         regcache_cooked_write (regcache, SPARC_F7_REGNUM, buf + 28);
+       }
     }
   else
     {
@@ -1129,10 +1408,12 @@ sparc32_store_return_value (struct type *type, struct regcache *regcache,
 }
 
 static enum return_value_convention
-sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
                      struct type *type, struct regcache *regcache,
                      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
   /* The psABI says that "...every stack frame reserves the word at
      %fp+64.  If a function returns a structure, union, or
      quad-precision value, this word should hold the address of the
@@ -1143,15 +1424,21 @@ sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type,
   if (sparc_structure_or_union_p (type)
       || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
     {
+      ULONGEST sp;
+      CORE_ADDR addr;
+
       if (readbuf)
        {
-         ULONGEST sp;
-         CORE_ADDR addr;
-
          regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
-         addr = read_memory_unsigned_integer (sp + 64, 4);
+         addr = read_memory_unsigned_integer (sp + 64, 4, byte_order);
          read_memory (addr, readbuf, TYPE_LENGTH (type));
        }
+      if (writebuf)
+       {
+         regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+         addr = read_memory_unsigned_integer (sp + 64, 4, byte_order);
+         write_memory (addr, writebuf, TYPE_LENGTH (type));
+       }
 
       return RETURN_VALUE_ABI_PRESERVES_ADDRESS;
     }
@@ -1168,7 +1455,8 @@ static int
 sparc32_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
 {
   return (sparc_structure_or_union_p (type)
-         || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16));
+         || (sparc_floating_p (type) && TYPE_LENGTH (type) == 16)
+         || sparc_complex_floating_p (type));
 }
 
 static int
@@ -1224,14 +1512,24 @@ sparc_analyze_control_transfer (struct frame_info *frame,
 {
   unsigned long insn = sparc_fetch_instruction (pc);
   int conditional_p = X_COND (insn) & 0x7;
-  int branch_p = 0;
+  int branch_p = 0, fused_p = 0;
   long offset = 0;                     /* Must be signed for sign-extend.  */
 
-  if (X_OP (insn) == 0 && X_OP2 (insn) == 3 && (insn & 0x1000000) == 0)
+  if (X_OP (insn) == 0 && X_OP2 (insn) == 3)
     {
-      /* Branch on Integer Register with Prediction (BPr).  */
-      branch_p = 1;
-      conditional_p = 1;
+      if ((insn & 0x10000000) == 0)
+       {
+         /* Branch on Integer Register with Prediction (BPr).  */
+         branch_p = 1;
+         conditional_p = 1;
+       }
+      else
+       {
+         /* Compare and Branch  */
+         branch_p = 1;
+         fused_p = 1;
+         offset = 4 * X_DISP10 (insn);
+       }
     }
   else if (X_OP (insn) == 0 && X_OP2 (insn) == 6)
     {
@@ -1268,7 +1566,16 @@ sparc_analyze_control_transfer (struct frame_info *frame,
 
   if (branch_p)
     {
-      if (conditional_p)
+      if (fused_p)
+       {
+         /* Fused compare-and-branch instructions are non-delayed,
+            and do not have an annuling capability.  So we need to
+            always set a breakpoint on both the NPC and the branch
+            target address.  */
+         gdb_assert (offset != 0);
+         return pc + offset;
+       }
+      else if (conditional_p)
        {
          /* For conditional branches, return nPC + 4 iff the annul
             bit is 1.  */
@@ -1285,7 +1592,6 @@ sparc_analyze_control_transfer (struct frame_info *frame,
          if (X_A (insn))
            *npc = 0;
 
-         gdb_assert (offset != 0);
          return pc + offset;
        }
     }
@@ -1304,6 +1610,7 @@ sparc_software_single_step (struct frame_info *frame)
 {
   struct gdbarch *arch = get_frame_arch (frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
+  struct address_space *aspace = get_frame_address_space (frame);
   CORE_ADDR npc, nnpc;
 
   CORE_ADDR pc, orig_npc;
@@ -1314,10 +1621,10 @@ sparc_software_single_step (struct frame_info *frame)
   /* Analyze the instruction at PC.  */
   nnpc = sparc_analyze_control_transfer (frame, pc, &npc);
   if (npc != 0)
-    insert_single_step_breakpoint (npc);
+    insert_single_step_breakpoint (arch, aspace, npc);
 
   if (nnpc != 0)
-    insert_single_step_breakpoint (nnpc);
+    insert_single_step_breakpoint (arch, aspace, nnpc);
 
   /* Assert that we have set at least one breakpoint, and that
      they're not set at the same spot - unless we're going
@@ -1338,22 +1645,18 @@ sparc_write_pc (struct regcache *regcache, CORE_ADDR pc)
 }
 \f
 
-/* Return the appropriate register set for the core section identified
-   by SECT_NAME and SECT_SIZE.  */
+/* Iterate over core file register note sections.  */
 
-static const struct regset *
-sparc_regset_from_core_section (struct gdbarch *gdbarch,
-                               const char *sect_name, size_t sect_size)
+static void
+sparc_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                   iterate_over_regset_sections_cb *cb,
+                                   void *cb_data,
+                                   const struct regcache *regcache)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (strcmp (sect_name, ".reg") == 0 && sect_size >= tdep->sizeof_gregset)
-    return tdep->gregset;
-
-  if (strcmp (sect_name, ".reg2") == 0 && sect_size >= tdep->sizeof_fpregset)
-    return tdep->fpregset;
-
-  return NULL;
+  cb (".reg", tdep->sizeof_gregset, tdep->gregset, NULL, cb_data);
+  cb (".reg2", tdep->sizeof_fpregset, tdep->fpregset, NULL, cb_data);
 }
 \f
 
@@ -1369,16 +1672,11 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     return arches->gdbarch;
 
   /* Allocate space for the new architecture.  */
-  tdep = XMALLOC (struct gdbarch_tdep);
+  tdep = XCNEW (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
 
   tdep->pc_regnum = SPARC32_PC_REGNUM;
   tdep->npc_regnum = SPARC32_NPC_REGNUM;
-  tdep->gregset = NULL;
-  tdep->sizeof_gregset = 0;
-  tdep->fpregset = NULL;
-  tdep->sizeof_fpregset = 0;
-  tdep->plt_entry_size = 0;
   tdep->step_trap = sparc_step_trap;
 
   set_gdbarch_long_double_bit (gdbarch, 128);
@@ -1397,6 +1695,7 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_fp0_regnum (gdbarch, SPARC_F0_REGNUM); /* %f0 */
 
   /* Call dummy code.  */
+  set_gdbarch_frame_align (gdbarch, sparc32_frame_align);
   set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
   set_gdbarch_push_dummy_code (gdbarch, sparc32_push_dummy_code);
   set_gdbarch_push_dummy_call (gdbarch, sparc32_push_dummy_call);
@@ -1437,8 +1736,10 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   /* If we have register sets, enable the generic core file support.  */
   if (tdep->gregset)
-    set_gdbarch_regset_from_core_section (gdbarch,
-                                         sparc_regset_from_core_section);
+    set_gdbarch_iterate_over_regset_sections
+      (gdbarch, sparc_iterate_over_regset_sections);
+
+  register_sparc_ravenscar_ops (gdbarch);
 
   return gdbarch;
 }
@@ -1448,6 +1749,8 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 void
 sparc_supply_rwindow (struct regcache *regcache, CORE_ADDR sp, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int offset = 0;
   gdb_byte buf[8];
   int i;
@@ -1466,10 +1769,12 @@ sparc_supply_rwindow (struct regcache *regcache, CORE_ADDR sp, int regnum)
              /* Handle StackGhost.  */
              if (i == SPARC_I7_REGNUM)
                {
-                 ULONGEST wcookie = sparc_fetch_wcookie ();
-                 ULONGEST i7 = extract_unsigned_integer (buf + offset, 8);
+                 ULONGEST wcookie = sparc_fetch_wcookie (gdbarch);
+                 ULONGEST i7;
 
-                 store_unsigned_integer (buf + offset, 8, i7 ^ wcookie);
+                 i7 = extract_unsigned_integer (buf + offset, 8, byte_order);
+                 store_unsigned_integer (buf + offset, 8, byte_order,
+                                         i7 ^ wcookie);
                }
 
              regcache_raw_supply (regcache, i, buf);
@@ -1500,10 +1805,12 @@ sparc_supply_rwindow (struct regcache *regcache, CORE_ADDR sp, int regnum)
              /* Handle StackGhost.  */
              if (i == SPARC_I7_REGNUM)
                {
-                 ULONGEST wcookie = sparc_fetch_wcookie ();
-                 ULONGEST i7 = extract_unsigned_integer (buf + offset, 4);
+                 ULONGEST wcookie = sparc_fetch_wcookie (gdbarch);
+                 ULONGEST i7;
 
-                 store_unsigned_integer (buf + offset, 4, i7 ^ wcookie);
+                 i7 = extract_unsigned_integer (buf + offset, 4, byte_order);
+                 store_unsigned_integer (buf + offset, 4, byte_order,
+                                         i7 ^ wcookie);
                }
 
              regcache_raw_supply (regcache, i, buf);
@@ -1516,6 +1823,8 @@ void
 sparc_collect_rwindow (const struct regcache *regcache,
                       CORE_ADDR sp, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int offset = 0;
   gdb_byte buf[8];
   int i;
@@ -1534,10 +1843,11 @@ sparc_collect_rwindow (const struct regcache *regcache,
              /* Handle StackGhost.  */
              if (i == SPARC_I7_REGNUM)
                {
-                 ULONGEST wcookie = sparc_fetch_wcookie ();
-                 ULONGEST i7 = extract_unsigned_integer (buf + offset, 8);
+                 ULONGEST wcookie = sparc_fetch_wcookie (gdbarch);
+                 ULONGEST i7;
 
-                 store_unsigned_integer (buf, 8, i7 ^ wcookie);
+                 i7 = extract_unsigned_integer (buf + offset, 8, byte_order);
+                 store_unsigned_integer (buf, 8, byte_order, i7 ^ wcookie);
                }
 
              target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8);
@@ -1563,10 +1873,12 @@ sparc_collect_rwindow (const struct regcache *regcache,
              /* Handle StackGhost.  */
              if (i == SPARC_I7_REGNUM)
                {
-                 ULONGEST wcookie = sparc_fetch_wcookie ();
-                 ULONGEST i7 = extract_unsigned_integer (buf + offset, 4);
+                 ULONGEST wcookie = sparc_fetch_wcookie (gdbarch);
+                 ULONGEST i7;
 
-                 store_unsigned_integer (buf + offset, 4, i7 ^ wcookie);
+                 i7 = extract_unsigned_integer (buf + offset, 4, byte_order);
+                 store_unsigned_integer (buf + offset, 4, byte_order,
+                                         i7 ^ wcookie);
                }
 
              target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 4),
@@ -1579,35 +1891,36 @@ sparc_collect_rwindow (const struct regcache *regcache,
 /* Helper functions for dealing with register sets.  */
 
 void
-sparc32_supply_gregset (const struct sparc_gregset *gregset,
+sparc32_supply_gregset (const struct sparc_gregmap *gregmap,
                        struct regcache *regcache,
                        int regnum, const void *gregs)
 {
   const gdb_byte *regs = gregs;
+  gdb_byte zero[4] = { 0 };
   int i;
 
   if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
     regcache_raw_supply (regcache, SPARC32_PSR_REGNUM,
-                        regs + gregset->r_psr_offset);
+                        regs + gregmap->r_psr_offset);
 
   if (regnum == SPARC32_PC_REGNUM || regnum == -1)
     regcache_raw_supply (regcache, SPARC32_PC_REGNUM,
-                        regs + gregset->r_pc_offset);
+                        regs + gregmap->r_pc_offset);
 
   if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
     regcache_raw_supply (regcache, SPARC32_NPC_REGNUM,
-                        regs + gregset->r_npc_offset);
+                        regs + gregmap->r_npc_offset);
 
   if (regnum == SPARC32_Y_REGNUM || regnum == -1)
     regcache_raw_supply (regcache, SPARC32_Y_REGNUM,
-                        regs + gregset->r_y_offset);
+                        regs + gregmap->r_y_offset);
 
   if (regnum == SPARC_G0_REGNUM || regnum == -1)
-    regcache_raw_supply (regcache, SPARC_G0_REGNUM, NULL);
+    regcache_raw_supply (regcache, SPARC_G0_REGNUM, &zero);
 
   if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
     {
-      int offset = gregset->r_g1_offset;
+      int offset = gregmap->r_g1_offset;
 
       for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
        {
@@ -1621,7 +1934,7 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset,
     {
       /* Not all of the register set variants include Locals and
          Inputs.  For those that don't, we read them off the stack.  */
-      if (gregset->r_l0_offset == -1)
+      if (gregmap->r_l0_offset == -1)
        {
          ULONGEST sp;
 
@@ -1630,7 +1943,7 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset,
        }
       else
        {
-         int offset = gregset->r_l0_offset;
+         int offset = gregmap->r_l0_offset;
 
          for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
            {
@@ -1643,7 +1956,7 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset,
 }
 
 void
-sparc32_collect_gregset (const struct sparc_gregset *gregset,
+sparc32_collect_gregset (const struct sparc_gregmap *gregmap,
                         const struct regcache *regcache,
                         int regnum, void *gregs)
 {
@@ -1652,23 +1965,23 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset,
 
   if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
     regcache_raw_collect (regcache, SPARC32_PSR_REGNUM,
-                         regs + gregset->r_psr_offset);
+                         regs + gregmap->r_psr_offset);
 
   if (regnum == SPARC32_PC_REGNUM || regnum == -1)
     regcache_raw_collect (regcache, SPARC32_PC_REGNUM,
-                         regs + gregset->r_pc_offset);
+                         regs + gregmap->r_pc_offset);
 
   if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
     regcache_raw_collect (regcache, SPARC32_NPC_REGNUM,
-                         regs + gregset->r_npc_offset);
+                         regs + gregmap->r_npc_offset);
 
   if (regnum == SPARC32_Y_REGNUM || regnum == -1)
     regcache_raw_collect (regcache, SPARC32_Y_REGNUM,
-                         regs + gregset->r_y_offset);
+                         regs + gregmap->r_y_offset);
 
   if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
     {
-      int offset = gregset->r_g1_offset;
+      int offset = gregmap->r_g1_offset;
 
       /* %g0 is always zero.  */
       for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
@@ -1683,9 +1996,9 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset,
     {
       /* Not all of the register set variants include Locals and
          Inputs.  For those that don't, we read them off the stack.  */
-      if (gregset->r_l0_offset != -1)
+      if (gregmap->r_l0_offset != -1)
        {
-         int offset = gregset->r_l0_offset;
+         int offset = gregmap->r_l0_offset;
 
          for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
            {
@@ -1698,7 +2011,8 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset,
 }
 
 void
-sparc32_supply_fpregset (struct regcache *regcache,
+sparc32_supply_fpregset (const struct sparc_fpregmap *fpregmap,
+                        struct regcache *regcache,
                         int regnum, const void *fpregs)
 {
   const gdb_byte *regs = fpregs;
@@ -1707,15 +2021,18 @@ sparc32_supply_fpregset (struct regcache *regcache,
   for (i = 0; i < 32; i++)
     {
       if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
-       regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+       regcache_raw_supply (regcache, SPARC_F0_REGNUM + i,
+                            regs + fpregmap->r_f0_offset + (i * 4));
     }
 
   if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
-    regcache_raw_supply (regcache, SPARC32_FSR_REGNUM, regs + (32 * 4) + 4);
+    regcache_raw_supply (regcache, SPARC32_FSR_REGNUM,
+                        regs + fpregmap->r_fsr_offset);
 }
 
 void
-sparc32_collect_fpregset (const struct regcache *regcache,
+sparc32_collect_fpregset (const struct sparc_fpregmap *fpregmap,
+                         const struct regcache *regcache,
                          int regnum, void *fpregs)
 {
   gdb_byte *regs = fpregs;
@@ -1724,18 +2041,20 @@ sparc32_collect_fpregset (const struct regcache *regcache,
   for (i = 0; i < 32; i++)
     {
       if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
-       regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+       regcache_raw_collect (regcache, SPARC_F0_REGNUM + i,
+                             regs + fpregmap->r_f0_offset + (i * 4));
     }
 
   if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
-    regcache_raw_collect (regcache, SPARC32_FSR_REGNUM, regs + (32 * 4) + 4);
+    regcache_raw_collect (regcache, SPARC32_FSR_REGNUM,
+                         regs + fpregmap->r_fsr_offset);
 }
 \f
 
 /* SunOS 4.  */
 
 /* From <machine/reg.h>.  */
-const struct sparc_gregset sparc32_sunos4_gregset =
+const struct sparc_gregmap sparc32_sunos4_gregmap =
 {
   0 * 4,                       /* %psr */
   1 * 4,                       /* %pc */
@@ -1746,6 +2065,18 @@ const struct sparc_gregset sparc32_sunos4_gregset =
   4 * 4,                       /* %g1 */
   -1                           /* %l0 */
 };
+
+const struct sparc_fpregmap sparc32_sunos4_fpregmap =
+{
+  0 * 4,                       /* %f0 */
+  33 * 4,                      /* %fsr */
+};
+
+const struct sparc_fpregmap sparc32_bsd_fpregmap =
+{
+  0 * 4,                       /* %f0 */
+  32 * 4,                      /* %fsr */
+};
 \f
 
 /* Provide a prototype to silence -Wmissing-prototypes.  */