ALPHA: Migrate from 'regset_from_core_section' to 'iterate_over_regset_sections'
[deliverable/binutils-gdb.git] / gdb / sparc-tdep.c
index 2b38521a85f6600fde32afc6127d534bb6ba144a..bcd4f6e7464d8e2cb4cfe53ab23e786a7939aed4 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for SPARC.
 
-   Copyright (C) 2003-2013 Free Software Foundation, Inc.
+   Copyright (C) 2003-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -35,9 +35,6 @@
 #include "target.h"
 #include "value.h"
 
-#include "gdb_assert.h"
-#include "gdb_string.h"
-
 #include "sparc-tdep.h"
 #include "sparc-ravenscar-thread.h"
 
@@ -88,6 +85,9 @@ struct regset;
 #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.  */
@@ -121,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
@@ -421,6 +452,29 @@ 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)
@@ -855,7 +909,7 @@ 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);
@@ -1538,7 +1592,6 @@ sparc_analyze_control_transfer (struct frame_info *frame,
          if (X_A (insn))
            *npc = 0;
 
-         gdb_assert (offset != 0);
          return pc + offset;
        }
     }
@@ -1623,7 +1676,7 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     return arches->gdbarch;
 
   /* Allocate space for the new architecture.  */
-  tdep = XZALLOC (struct gdbarch_tdep);
+  tdep = XCNEW (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
 
   tdep->pc_regnum = SPARC32_PC_REGNUM;
@@ -1842,7 +1895,7 @@ 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)
 {
@@ -1852,26 +1905,26 @@ sparc32_supply_gregset (const struct sparc_gregset *gregset,
 
   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, &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++)
        {
@@ -1885,7 +1938,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;
 
@@ -1894,7 +1947,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++)
            {
@@ -1907,7 +1960,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)
 {
@@ -1916,23 +1969,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++)
@@ -1947,9 +2000,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++)
            {
@@ -1962,7 +2015,7 @@ sparc32_collect_gregset (const struct sparc_gregset *gregset,
 }
 
 void
-sparc32_supply_fpregset (const struct sparc_fpregset *fpregset,
+sparc32_supply_fpregset (const struct sparc_fpregmap *fpregmap,
                         struct regcache *regcache,
                         int regnum, const void *fpregs)
 {
@@ -1973,16 +2026,16 @@ sparc32_supply_fpregset (const struct sparc_fpregset *fpregset,
     {
       if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
        regcache_raw_supply (regcache, SPARC_F0_REGNUM + i,
-                            regs + fpregset->r_f0_offset + (i * 4));
+                            regs + fpregmap->r_f0_offset + (i * 4));
     }
 
   if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
     regcache_raw_supply (regcache, SPARC32_FSR_REGNUM,
-                        regs + fpregset->r_fsr_offset);
+                        regs + fpregmap->r_fsr_offset);
 }
 
 void
-sparc32_collect_fpregset (const struct sparc_fpregset *fpregset,
+sparc32_collect_fpregset (const struct sparc_fpregmap *fpregmap,
                          const struct regcache *regcache,
                          int regnum, void *fpregs)
 {
@@ -1993,19 +2046,19 @@ sparc32_collect_fpregset (const struct sparc_fpregset *fpregset,
     {
       if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
        regcache_raw_collect (regcache, SPARC_F0_REGNUM + i,
-                             regs + fpregset->r_f0_offset + (i * 4));
+                             regs + fpregmap->r_f0_offset + (i * 4));
     }
 
   if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
     regcache_raw_collect (regcache, SPARC32_FSR_REGNUM,
-                         regs + fpregset->r_fsr_offset);
+                         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 */
@@ -2017,13 +2070,13 @@ const struct sparc_gregset sparc32_sunos4_gregset =
   -1                           /* %l0 */
 };
 
-const struct sparc_fpregset sparc32_sunos4_fpregset =
+const struct sparc_fpregmap sparc32_sunos4_fpregmap =
 {
   0 * 4,                       /* %f0 */
   33 * 4,                      /* %fsr */
 };
 
-const struct sparc_fpregset sparc32_bsd_fpregset =
+const struct sparc_fpregmap sparc32_bsd_fpregmap =
 {
   0 * 4,                       /* %f0 */
   32 * 4,                      /* %fsr */
This page took 0.029335 seconds and 4 git commands to generate.