Add support for single register window model on SPARC
authorJoel Brobecker <brobecker@gnat.com>
Mon, 27 Jun 2011 16:36:00 +0000 (16:36 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Mon, 27 Jun 2011 16:36:00 +0000 (16:36 +0000)
        2011-06-27  Eric Botcazou  <ebotcazou@adacore.com>
        * sparc-tdep.h (struct sparc_frame_cache): Add frame_offset,
        saved_regs_mask and copied_regs_mask fields.
        (sparc_record_save_insn): New prototype.
        * sparc-tdep.c (sparc_alloc_frame_cache): Initialize the new fields.
        (sparc_record_save_insn): New function.
        (sparc_analyze_prologue): Add head comment.  Recognize store insns
        of call-saved registers.  Use OFFSET consistently.  Recognize flat
        frames and cache their settings.
        (sparc32_skip_prologue): Handle flat frames.
        (sparc_frame_cache): Add frame_offset to the base address.
        (sparc32_frame_cache): Adjust to new frame description.
        (sparc32_frame_prev_register): Likewise.
        * sparc64-tdep.c (sparc64_frame_prev_register): Likewise.
        * sparc-sol2-tdep.c (sparc32_sol2_sigtramp_frame_cache): Likewise.
        * sparc64-sol2-tdep.c (sparc64_sol2_sigtramp_frame_cache): Likewise.
        * sparcnbsd-tdep.c (sparc32nbsd_sigcontext_frame_cache): Force the
        frame by calling sparc_record_save_insn.
        * sparc64nbsd-tdep.c (sparc64nbsd_sigcontext_frame_cache): Likewise.
        * sparcobsd-tdep.c (sparc32obsd_sigtramp_frame_cache): Likewise.
        * sparc64obsd-tdep.c (sparc64obsd_frame_cache): Likewise.

gdb/ChangeLog
gdb/sparc-sol2-tdep.c
gdb/sparc-tdep.c
gdb/sparc-tdep.h
gdb/sparc64-sol2-tdep.c
gdb/sparc64-tdep.c
gdb/sparc64nbsd-tdep.c
gdb/sparc64obsd-tdep.c
gdb/sparcnbsd-tdep.c
gdb/sparcobsd-tdep.c

index cd62b1c941c4c32496ef459c449256391b3b0038..b7c5e20cdaf9455f0f9f7f69880b93ba82de4602 100644 (file)
@@ -1,3 +1,26 @@
+2011-06-27  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * sparc-tdep.h (struct sparc_frame_cache): Add frame_offset,
+       saved_regs_mask and copied_regs_mask fields.
+       (sparc_record_save_insn): New prototype.
+       * sparc-tdep.c (sparc_alloc_frame_cache): Initialize the new fields.
+       (sparc_record_save_insn): New function.
+       (sparc_analyze_prologue): Add head comment.  Recognize store insns
+       of call-saved registers.  Use OFFSET consistently.  Recognize flat
+       frames and cache their settings.
+       (sparc32_skip_prologue): Handle flat frames.
+       (sparc_frame_cache): Add frame_offset to the base address.
+       (sparc32_frame_cache): Adjust to new frame description.
+       (sparc32_frame_prev_register): Likewise.
+       * sparc64-tdep.c (sparc64_frame_prev_register): Likewise.
+       * sparc-sol2-tdep.c (sparc32_sol2_sigtramp_frame_cache): Likewise.
+       * sparc64-sol2-tdep.c (sparc64_sol2_sigtramp_frame_cache): Likewise.
+       * sparcnbsd-tdep.c (sparc32nbsd_sigcontext_frame_cache): Force the
+       frame by calling sparc_record_save_insn.
+       * sparc64nbsd-tdep.c (sparc64nbsd_sigcontext_frame_cache): Likewise.
+       * sparcobsd-tdep.c (sparc32obsd_sigtramp_frame_cache): Likewise.
+       * sparc64obsd-tdep.c (sparc64obsd_frame_cache): Likewise.
+
 2011-06-27  Tristan Gingold  <gingold@adacore.com>
 
        * dwarf2read.c (struct dwarf2_section_info): Replace was_mmapped
index a49eb7f36b1ec1a40e0d677acb3f36cb36acd592..bff15de07e4741a891f8e0fe30a0bd245fc5f766 100644 (file)
@@ -93,7 +93,8 @@ sparc32_sol2_sigtramp_frame_cache (struct frame_info *this_frame,
   /* The third argument is a pointer to an instance of `ucontext_t',
      which has a member `uc_mcontext' that contains the saved
      registers.  */
-  regnum = (cache->frameless_p ? SPARC_O2_REGNUM : SPARC_I2_REGNUM);
+  regnum =
+    (cache->copied_regs_mask & 0x04) ? SPARC_I2_REGNUM : SPARC_O2_REGNUM;
   mcontext_addr = get_frame_register_unsigned (this_frame, regnum) + 40;
 
   cache->saved_regs[SPARC32_PSR_REGNUM].addr = mcontext_addr + 0 * 4;
index 42c13ac5a2e2f61cb41da6da16199980036802f0..faa7b3a4adc6a9848e2d9b2b3431be725f326e1d 100644 (file)
@@ -592,7 +592,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;
@@ -784,6 +786,31 @@ sparc_skip_stack_check (const CORE_ADDR 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)
@@ -813,13 +840,40 @@ sparc_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
 
   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.  */
@@ -828,14 +882,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;
@@ -878,21 +980,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;
@@ -935,6 +1052,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;
 
@@ -983,7 +1102,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))
@@ -1025,7 +1145,8 @@ 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);
     }
@@ -1045,20 +1166,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);
index 0eb7afaeeb0b9450a9b511fe0616ff694f1b8e05..d4e8b067c61c5b0754e5fd93e6eae4e433fe3985 100644 (file)
@@ -146,6 +146,15 @@ struct sparc_frame_cache
   /* Do we have a frame?  */
   int frameless_p;
 
+  /* The offset from the base register to the CFA.  */
+  int frame_offset;
+
+  /* Mask of `local' and `in' registers saved in the register save area.  */
+  unsigned short int saved_regs_mask;
+
+  /* Mask of `out' registers copied or renamed to their `in' sibling.  */
+  unsigned char copied_regs_mask;
+
   /* Do we have a Structure, Union or Quad-Precision return value?  */
   int struct_return_p;
 
@@ -159,6 +168,10 @@ extern unsigned long sparc_fetch_instruction (CORE_ADDR pc);
 /* Fetch StackGhost Per-Process XOR cookie.  */
 extern ULONGEST sparc_fetch_wcookie (struct gdbarch *gdbarch);
 
+/* Record the effect of a SAVE instruction on CACHE.  */
+extern void sparc_record_save_insn (struct sparc_frame_cache *cache);
+
+/* Do a full analysis of the prologue at PC and update CACHE accordingly.  */
 extern CORE_ADDR sparc_analyze_prologue (struct gdbarch *gdbarch,
                                         CORE_ADDR pc, CORE_ADDR current_pc,
                                         struct sparc_frame_cache *cache);
index d11619d8691dd9906fecc9f8a56c686cfd70eb65..6e108d15a72ac348d96bc989cd26a321a88b1e2d 100644 (file)
@@ -67,7 +67,8 @@ sparc64_sol2_sigtramp_frame_cache (struct frame_info *this_frame,
   /* The third argument is a pointer to an instance of `ucontext_t',
      which has a member `uc_mcontext' that contains the saved
      registers.  */
-  regnum = (cache->frameless_p ? SPARC_O2_REGNUM : SPARC_I2_REGNUM);
+  regnum =
+    (cache->copied_regs_mask & 0x04) ? SPARC_I2_REGNUM : SPARC_O2_REGNUM;
   mcontext_addr = get_frame_register_unsigned (this_frame, regnum) + 64;
 
   cache->saved_regs[SPARC64_CCR_REGNUM].addr = mcontext_addr + 0 * 8;
index 6efa2202a50fd836c50149d0bdf90a29f2be8432..0430ecf22acc8299ee7eacc28630dc87ddbf6054 100644 (file)
@@ -520,7 +520,8 @@ sparc64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
     {
       CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
 
-      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);
     }
@@ -540,20 +541,20 @@ sparc64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
       }
   }
 
-  /* 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) * 8;
 
       return frame_unwind_got_memory (this_frame, regnum, addr);
     }
 
-  /* The previous frame's `out' registers are accessable 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);
index 5d6c27c17f4c7036ad42b2699642ce62e0309589..94e0f3e83c2b1860fa77d0838e610d81cbbe9dc2 100644 (file)
@@ -173,7 +173,7 @@ sparc64nbsd_sigcontext_frame_cache (struct frame_info *this_frame,
 
       /* Since we couldn't find the frame's function, the cache was
          initialized under the assumption that we're frameless.  */
-      cache->frameless_p = 0;
+      sparc_record_save_insn (cache);
       addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
       if (addr & 1)
        addr += BIAS;
index adc16a18a45be881c93850bcaf729170131245d6..c7746dcfba6cef699a0fa624b31da67a1dccc43c 100644 (file)
@@ -142,7 +142,7 @@ sparc64obsd_frame_cache (struct frame_info *this_frame, void **this_cache)
 
       /* Since we couldn't find the frame's function, the cache was
          initialized under the assumption that we're frameless.  */
-      cache->frameless_p = 0;
+      sparc_record_save_insn (cache);
       addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
       if (addr & 1)
        addr += BIAS;
index 8bbaa4bc9da4ab11f0bb1ddcf827951d362f0b40..594dd03015bab3d3c62fac9a9a63b64156774486 100644 (file)
@@ -202,7 +202,7 @@ sparc32nbsd_sigcontext_frame_cache (struct frame_info *this_frame,
 
       /* Since we couldn't find the frame's function, the cache was
          initialized under the assumption that we're frameless.  */
-      cache->frameless_p = 0;
+      sparc_record_save_insn (cache);
       addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
       cache->base = addr;
     }
index b9e954001a4012614e925b4ee55aefbe374b31da..52f9d70c54107d988475d8fe47cf358d6e1fc553 100644 (file)
@@ -91,7 +91,7 @@ sparc32obsd_sigtramp_frame_cache (struct frame_info *this_frame,
 
       /* Since we couldn't find the frame's function, the cache was
          initialized under the assumption that we're frameless.  */
-      cache->frameless_p = 0;
+      sparc_record_save_insn (cache);
       addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
       cache->base = addr;
     }