* tm-sparc.c (EXTRA_FRAME_INFO): New field sp_offset.
authorJim Kingdon <jkingdon@engr.sgi.com>
Sun, 18 Dec 1994 06:59:12 +0000 (06:59 +0000)
committerJim Kingdon <jkingdon@engr.sgi.com>
Sun, 18 Dec 1994 06:59:12 +0000 (06:59 +0000)
* sparc-tdep.c (sparc_init_extra_frame_info): Set it.
(examine_prologue, sparc_init_extra_frame_info): Use ->frame plus
->sp_offset to compute the address something is saved at, not
->bottom.

* sparc-tdep.c (get_saved_register): New function.
* tm-sparc.h: Define GET_SAVED_REGISTER; don't define
FRAME_FIND_SAVED_REGS, HAVE_REGISTER_WINDOWS or REGISTER_IN_WINDOW_P.
* stack.c (frame_info): Add comment about what to do if
FRAME_FIND_SAVED_REGS is not defined.

* sparc-tdep.c (sparc_init_extra_frame_info): Set ->frame field
here.  Get it right for flat frames.
* sparc-tdep.c (sparc_frame_chain): Instead of returning
meaningful value for ->frame field, just return dummy value.
This change is needed because the old code didn't deal with mixed
flat and non-flat frames.

* sparc-tdep.c (sparc_pop_frame): Write SP_REGNUM from
frame->frame, don't go through saved regs for this.

* sparc-tdep.c: Move guts of skip_prologue to new function
examine_prologue.  Check for flat prologue and set is_flat.
Provide the caller with the information about what is saved where
if desired.
(skip_prologue, sparc_frame_find_saved_regs): Call examine_prologue.

* sparc-tdep.c: Replace union sparc_insn_layout and anonymous
union in isannulled, which won't work on a little-endian host,
with X_* macros.

* sparc-tdep.c (sparc_frame_saved_pc): If addr == 0, the saved PC
is still in %o7.

* config/sparc/tm-sparc.h: Define INIT_FRAME_PC and
INIT_FRAME_PC_FIRST.
* blockframe.c (get_prev_frame_info): Modify comments regarding
INIT_FRAME_PC_FIRST and the sparc.

* sparc-tdep.c (single_step): Use 4 not sizeof (long) for size of
instruction.

gdb/ChangeLog
gdb/config/sparc/tm-sparc.h
gdb/sparc-tdep.c

index 0fc5280..84e2e9b 100644 (file)
@@ -1,10 +1,55 @@
+Sat Dec 17 13:23:21 1994  Jim Kingdon  (kingdon@lioth.cygnus.com)
+
+       * tm-sparc.c (EXTRA_FRAME_INFO): New field sp_offset.
+       * sparc-tdep.c (sparc_init_extra_frame_info): Set it.
+       (examine_prologue, sparc_init_extra_frame_info): Use ->frame plus
+       ->sp_offset to compute the address something is saved at, not
+       ->bottom.
+
+       * sparc-tdep.c (get_saved_register): New function.
+       * tm-sparc.h: Define GET_SAVED_REGISTER; don't define
+       FRAME_FIND_SAVED_REGS, HAVE_REGISTER_WINDOWS or REGISTER_IN_WINDOW_P.
+       * stack.c (frame_info): Add comment about what to do if
+       FRAME_FIND_SAVED_REGS is not defined.
+
+       * sparc-tdep.c (sparc_init_extra_frame_info): Set ->frame field
+       here.  Get it right for flat frames.
+       * sparc-tdep.c (sparc_frame_chain): Instead of returning
+       meaningful value for ->frame field, just return dummy value.
+       This change is needed because the old code didn't deal with mixed
+       flat and non-flat frames.
+
+       * sparc-tdep.c (sparc_pop_frame): Write SP_REGNUM from
+       frame->frame, don't go through saved regs for this.
+
+       * sparc-tdep.c: Move guts of skip_prologue to new function
+       examine_prologue.  Check for flat prologue and set is_flat.
+       Provide the caller with the information about what is saved where
+       if desired.
+       (skip_prologue, sparc_frame_find_saved_regs): Call examine_prologue.
+
+       * sparc-tdep.c: Replace union sparc_insn_layout and anonymous
+       union in isannulled, which won't work on a little-endian host,
+       with X_* macros.
+
+       * sparc-tdep.c (sparc_frame_saved_pc): If addr == 0, the saved PC
+       is still in %o7.
+
+       * config/sparc/tm-sparc.h: Define INIT_FRAME_PC and
+       INIT_FRAME_PC_FIRST.
+       * blockframe.c (get_prev_frame_info): Modify comments regarding
+       INIT_FRAME_PC_FIRST and the sparc.
+
+       * sparc-tdep.c (single_step): Use 4 not sizeof (long) for size of
+       instruction. 
+
 Sat Dec 17 02:33:37 1994  Peter Schauer  (pes@regent.e-technik.tu-muenchen.de)
 
        * c-typeprint.c (c_type_print_base):  Use `show' of -1 to print
        the return type of methods to avoid infinite loops with anonymous
        types.
        * valops.c (search_struct_field):  Handle anonymous unions.
-  
+
        * sparc-tdep.c (sunos4_skip_trampoline_code):  New function
        to correctly handle steps into -g compiled PIC objects in the
        main executable.
index 36fb4e6..de0956e 100644 (file)
@@ -187,11 +187,12 @@ extern CORE_ADDR sparc_pc_adjust PARAMS ((CORE_ADDR));
    register state, the array `registers'.  On the sparc, `registers'
    contains the ins and locals, even though they are saved on the
    stack rather than with the other registers, and this causes hair
-   and confusion in places like pop_frame.  It probably would be
+   and confusion in places like pop_frame.  It might be
    better to remove the ins and locals from `registers', make sure
    that get_saved_register can get them from the stack (even in the
    innermost frame), and make this the way to access them.  For the
-   frame pointer we would do that via TARGET_READ_FP.  */
+   frame pointer we would do that via TARGET_READ_FP.  On the other hand,
+   that is likely to be confusing or worse for flat frames.  */
 
 #define REGISTER_BYTES (32*4+32*4+8*4)
 
@@ -200,18 +201,11 @@ extern CORE_ADDR sparc_pc_adjust PARAMS ((CORE_ADDR));
 /* ?? */
 #define REGISTER_BYTE(N)  ((N)*4)
 
-/* The SPARC processor has register windows.  */
+/* We need to override GET_SAVED_REGISTER so that we can deal with the way
+   outs change into ins in different frames.  HAVE_REGISTER_WINDOWS can't
+   deal with this case and also handle flat frames at the same time.  */
 
-#define HAVE_REGISTER_WINDOWS
-
-/* Is this register part of the register window system?  A yes answer
-   implies that 1) The name of this register will not be the same in
-   other frames, and 2) This register is automatically "saved" (out
-   registers shifting into ins counts) upon subroutine calls and thus
-   there is no need to search more than one stack frame for it. */
-
-#define REGISTER_IN_WINDOW_P(regnum)   \
-  ((regnum) >= 8 && (regnum) < 32)
+#define GET_SAVED_REGISTER 1
 
 /* Number of bytes of storage in the actual machine representation
    for register N.  */
@@ -342,8 +336,12 @@ sparc_extract_struct_value_address PARAMS ((char [REGISTER_BYTES]));
 #define EXTRA_FRAME_INFO  \
   CORE_ADDR bottom;  \
   int flat;  \
+  /* Following fields only relevant for flat frames.  */ \
   CORE_ADDR pc_addr;  \
   CORE_ADDR fp_addr;  \
+  /* Add this to ->frame to get the value of the stack pointer at the */ \
+  /* time of the register saves.  */ \
+  int sp_offset;
 
 #define INIT_EXTRA_FRAME_INFO(fromleaf, fci) \
   sparc_init_extra_frame_info (fromleaf, fci)
@@ -356,8 +354,19 @@ extern void sparc_init_extra_frame_info ();
                        (fi)->pc_addr, (fi)->fp_addr); \
   }
 
+#ifdef __STDC__
+struct frame_info;
+#endif
+
 #define FRAME_CHAIN(thisframe) (sparc_frame_chain (thisframe))
-extern CORE_ADDR sparc_frame_chain ();
+extern CORE_ADDR sparc_frame_chain PARAMS ((struct frame_info *));
+
+/* INIT_EXTRA_FRAME_INFO needs the PC to detect flat frames.  */
+
+#define        INIT_FRAME_PC(fromleaf, prev) /* nothing */
+#define INIT_FRAME_PC_FIRST(fromleaf, prev) \
+  (prev)->pc = ((fromleaf) ? SAVED_PC_AFTER_CALL ((prev)->next) : \
+             (prev)->next ? FRAME_SAVED_PC ((prev)->next) : read_pc ());
 
 /* Define other aspects of the stack frame.  */
 
@@ -397,19 +406,6 @@ extern CORE_ADDR sparc_frame_saved_pc ();
 /* Return number of bytes at start of arglist that are not really args.  */
 
 #define FRAME_ARGS_SKIP 68
-
-/* Put here the code to store, into a struct frame_saved_regs,
-   the addresses of the saved registers of frame described by FRAME_INFO.
-   The actual code is in sparc-tdep.c so we can debug it sanely.  */
-
-#define FRAME_FIND_SAVED_REGS(fi, frame_saved_regs)                \
-       sparc_frame_find_saved_regs ((fi), &(frame_saved_regs))
-#ifdef __STDC__
-struct frame_info;
-struct frame_saved_regs;
-#endif
-extern void sparc_frame_find_saved_regs PARAMS ((struct frame_info *,
-                                                struct frame_saved_regs *));
 \f
 /* Things needed for making the inferior call functions.  */
 /*
index 22a0bd2..8801136 100644 (file)
@@ -31,30 +31,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "gdbcore.h"
 
-/* Definition of SPARC instruction layouts.  */
-
-union sparc_insn_layout
-{
-  unsigned long int code;
-  struct
-    {
-      unsigned int op:2;
-      unsigned int rd:5;
-      unsigned int op2:3;
-      unsigned int imm22:22;
-    } sethi;
-  struct
-    {
-      unsigned int op:2;
-      unsigned int rd:5;
-      unsigned int op3:6;
-      unsigned int rs1:5;
-      unsigned int i:1;
-      unsigned int simm13:13;
-    } add;
-  int i;
-};
-
 /* From infrun.c */
 extern int stop_after_trap;
 
@@ -66,6 +42,21 @@ extern int stop_after_trap;
 
 int deferred_stores = 0;       /* Cumulates stores we want to do eventually. */
 
+/* Macros to extract fields from sparc instructions.  */
+#define X_OP(i) (((i) >> 30) & 0x3)
+#define X_RD(i) (((i) >> 25) & 0x1f)
+#define X_A(i) (((i) >> 29) & 1)
+#define X_COND(i) (((i) >> 25) & 0xf)
+#define X_OP2(i) (((i) >> 22) & 0x7)
+#define X_IMM22(i) ((i) & 0x3fffff)
+#define X_OP3(i) (((i) >> 19) & 0x3f)
+#define X_RS1(i) (((i) >> 14) & 0x1f)
+#define X_I(i) (((i) >> 13) & 1)
+#define X_IMM13(i) ((i) & 0x1fff)
+/* Sign extension macros.  */
+#define X_SIMM13(i) ((X_IMM13 (i) ^ 0x1000) - 0x1000)
+#define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
+
 typedef enum
 {
   Error, not_branch, bicc, bicca, ba, baa, ticc, ta
@@ -114,7 +105,7 @@ single_step (ignore)
       /* printf_unfiltered ("set break at %x\n",next_pc); */
 
       pc = read_register (PC_REGNUM);
-      pc_instruction = read_memory_integer (pc, sizeof(pc_instruction));
+      pc_instruction = read_memory_integer (pc, 4);
       br = isannulled (pc_instruction, pc, &target);
       brknpc4 = brktrg = 0;
 
@@ -166,69 +157,91 @@ sparc_init_extra_frame_info (fromleaf, fi)
 {
   char *name;
   CORE_ADDR addr;
-  union sparc_insn_layout x;
+  int insn;
 
   fi->bottom =
     (fi->next ?
      (fi->frame == fi->next->frame ? fi->next->bottom : fi->next->frame) :
      read_register (SP_REGNUM));
 
+  /* If fi->next is NULL, then we already set ->frame by passing read_fp()
+     to create_new_frame.  */
+  if (fi->next)
+    {
+      char buf[MAX_REGISTER_RAW_SIZE];
+      int err;
+
+      /* Compute ->frame as if not flat.  If it is flat, we'll change
+        it later.  */
+      /* FIXME: If error reading memory, should just stop backtracing, rather
+        than error().  */
+      get_saved_register (buf, 0, 0, fi, FP_REGNUM, 0);
+      fi->frame = extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
+    }
+
   /* Decide whether this is a function with a ``flat register window''
      frame.  For such functions, the frame pointer is actually in %i7.  */
   fi->flat = 0;
   if (find_pc_partial_function (fi->pc, &name, &addr, NULL))
     {
       /* See if the function starts with an add (which will be of a
-        negative number if a flat frame) to the sp.  */
-      x.i = read_memory_integer (addr, 4);
-      if (x.add.op == 2 && x.add.rd == 14 && x.add.op3 == 0)
+        negative number if a flat frame) to the sp.  FIXME: Does not
+        handle large frames which will need more than one instruction
+        to adjust the sp.  */
+      insn = read_memory_integer (addr, 4);
+      if (X_OP (insn) == 2 && X_RD (insn) == 14 && X_OP3 (insn) == 0
+         && X_I (insn) && X_SIMM13 (insn) < 0)
        {
+         int offset = X_SIMM13 (insn);
+
          /* Then look for a save of %i7 into the frame.  */
-         x.i = read_memory_integer (addr + 4, 4);
-         if (x.add.op == 3
-             && x.add.rd == 31
-             && x.add.op3 == 4
-             && x.add.rs1 == 14)
+         insn = read_memory_integer (addr + 4, 4);
+         if (X_OP (insn) == 3
+             && X_RD (insn) == 31
+             && X_OP3 (insn) == 4
+             && X_RS1 (insn) == 14)
            {
+             char buf[MAX_REGISTER_RAW_SIZE];
+
              /* We definitely have a flat frame now.  */
              fi->flat = 1;
+
+             fi->sp_offset = offset;
+
              /* Overwrite the frame's address with the value in %i7.  */
-             fi->frame = 
-               (fi->next ?
-                (fi->frame == fi->next->frame ? fi->bottom : fi->frame) :
-                read_register (I7_REGNUM));
+             get_saved_register (buf, 0, 0, fi, I7_REGNUM, 0);
+             fi->frame = extract_address (buf, REGISTER_RAW_SIZE (I7_REGNUM));
+
              /* Record where the fp got saved.  */
-             fi->fp_addr = fi->bottom + x.add.simm13;
+             fi->fp_addr = fi->frame + fi->sp_offset + X_SIMM13 (insn);
+
              /* Also try to collect where the pc got saved to.  */
              fi->pc_addr = 0;
-             x.i = read_memory_integer (addr + 12, 4);
-             if (x.add.op == 3
-                 && x.add.rd == 15
-                 && x.add.op3 == 4
-                 && x.add.rs1 == 14)
-               fi->pc_addr = fi->bottom + x.add.simm13;
+             insn = read_memory_integer (addr + 12, 4);
+             if (X_OP (insn) == 3
+                 && X_RD (insn) == 15
+                 && X_OP3 (insn) == 4
+                 && X_RS1 (insn) == 14)
+               fi->pc_addr = fi->frame + fi->sp_offset + X_SIMM13 (insn);
            }
        }
     }
+  if (fi->next && fi->frame == 0)
+    {
+      /* Kludge to cause init_prev_frame_info to destroy the new frame.  */
+      fi->frame = fi->next->frame;
+      fi->pc = fi->next->pc;
+    }
 }
 
 CORE_ADDR
 sparc_frame_chain (frame)
      struct frame_info *frame;
 {
-  char buf[MAX_REGISTER_RAW_SIZE];
-  int err;
-  CORE_ADDR addr;
-
-  if (frame->flat)
-    addr = frame->fp_addr;
-  else
-    addr = frame->frame + FRAME_SAVED_I0 +
-      REGISTER_RAW_SIZE (FP_REGNUM) * (FP_REGNUM - I0_REGNUM);
-  err = target_read_memory (addr, buf, REGISTER_RAW_SIZE (FP_REGNUM));
-  if (err)
-    return 0;
-  return extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
+  /* Value that will cause FRAME_CHAIN_VALID to not worry about the chain
+     value.  If it realy is zero, we detect it later in
+     sparc_init_prev_frame.  */
+  return (CORE_ADDR)1;
 }
 
 CORE_ADDR
@@ -285,6 +298,12 @@ sparc_frame_saved_pc (frame)
   else
     addr = frame->bottom + FRAME_SAVED_I0 +
       REGISTER_RAW_SIZE (I7_REGNUM) * (I7_REGNUM - I0_REGNUM);
+
+  if (addr == 0)
+    /* A flat frame leaf function might not save the PC anywhere,
+       just leave it in %o7.  */
+    return PC_ADJUST (read_register (O7_REGNUM));
+
   read_memory (addr, buf, REGISTER_RAW_SIZE (I7_REGNUM));
   return PC_ADJUST (extract_address (buf, REGISTER_RAW_SIZE (I7_REGNUM)));
 }
@@ -326,24 +345,29 @@ setup_arbitrary_frame (argc, argv)
    This routine should be more specific in its actions; making sure
    that it uses the same register in the initial prologue section.  */
 
-CORE_ADDR 
-skip_prologue (start_pc, frameless_p)
+static CORE_ADDR examine_prologue PARAMS ((CORE_ADDR, int, struct frame_info *,
+                                          struct frame_saved_regs *));
+
+static CORE_ADDR 
+examine_prologue (start_pc, frameless_p, fi, saved_regs)
      CORE_ADDR start_pc;
      int frameless_p;
+     struct frame_info *fi;
+     struct frame_saved_regs *saved_regs;
 {
-  union sparc_insn_layout x;
+  int insn;
   int dest = -1;
   CORE_ADDR pc = start_pc;
   int is_flat = 0;
 
-  x.i = read_memory_integer (pc, 4);
+  insn = read_memory_integer (pc, 4);
 
   /* Recognize the `sethi' insn and record its destination.  */
-  if (x.sethi.op == 0 && x.sethi.op2 == 4)
+  if (X_OP (insn) == 0 && X_OP2 (insn) == 4)
     {
-      dest = x.sethi.rd;
+      dest = X_RD (insn);
       pc += 4;
-      x.i = read_memory_integer (pc, 4);
+      insn = read_memory_integer (pc, 4);
     }
 
   /* Recognize an add immediate value to register to either %g1 or
@@ -352,63 +376,99 @@ skip_prologue (start_pc, frameless_p)
      It doesn't check that rs1 == rd because in theory "sub %g0, 5, %g1"
      followed by "save %sp, %g1, %sp" is a valid prologue (Not that
      I imagine any compiler really does that, however).  */
-  if (x.add.op == 2 && x.add.i && (x.add.rd == 1 || x.add.rd == dest))
+  if (X_OP (insn) == 2
+      && X_I (insn)
+      && (X_RD (insn) == 1 || X_RD (insn) == dest))
     {
       pc += 4;
-      x.i = read_memory_integer (pc, 4);
+      insn = read_memory_integer (pc, 4);
     }
 
-  /* This recognizes any SAVE insn.  But why do the XOR and then
-     the compare?  That's identical to comparing against 60 (as long
-     as there isn't any sign extension).  */
-  if (x.add.op == 2 && (x.add.op3 ^ 32) == 28)
+  /* Recognize any SAVE insn.  */
+  if (X_OP (insn) == 2 && X_OP3 (insn) == 60)
     {
       pc += 4;
       if (frameless_p)                 /* If the save is all we care about, */
        return pc;                      /* return before doing more work */
-      x.i = read_memory_integer (pc, 4);
+      insn = read_memory_integer (pc, 4);
     }
-  else if (x.add.op == 2 && x.add.rd == 14 && x.add.op3 == 0)
+  /* Recognize add to %sp.  */
+  else if (X_OP (insn) == 2 && X_RD (insn) == 14 && X_OP3 (insn) == 0)
     {
       pc += 4;
       if (frameless_p)                 /* If the add is all we care about, */
        return pc;                      /* return before doing more work */
-      /* FIXME test that the following instructions are the right ones
-         for a flat frame */
-      x.i = read_memory_integer (pc, 4);
-      pc += 4;
-      x.i = read_memory_integer (pc, 4);
-      pc += 4;
-      x.i = read_memory_integer (pc, 4);
+      is_flat = 1;
+      insn = read_memory_integer (pc, 4);
+      /* Recognize store of frame pointer (i7).  */
+      if (X_OP (insn) == 3
+         && X_RD (insn) == 31
+         && X_OP3 (insn) == 4
+         && X_RS1 (insn) == 14)
+       {
+         pc += 4;
+         insn = read_memory_integer (pc, 4);
+
+         /* Recognize sub %sp, <anything>, %i7.  */
+         if (X_OP (insn) ==  2
+             && X_OP3 (insn) == 4
+             && X_RS1 (insn) == 14
+             && X_RD (insn) == 31)
+           {
+             pc += 4;
+             insn = read_memory_integer (pc, 4);
+           }
+         else
+           return pc;
+       }
+      else
+       return pc;
     }
   else
     /* Without a save or add instruction, it's not a prologue.  */
     return start_pc;
 
-  /* Now we need to recognize stores into the frame from the input
-     registers.  This recognizes all non alternate stores of input
-     register, into a location offset from the frame pointer.  */
-  while ((x.add.op == 3
-         && (x.add.op3 & 0x3c) == 4 /* Store, non-alternate.  */
-         && (x.add.rd & 0x18) == 0x18 /* Input register.  */
-         && x.add.i            /* Immediate mode.  */
-         && x.add.rs1 == 30    /* Off of frame pointer.  */
-         /* Into reserved stack space.  */
-         && x.add.simm13 >= 0x44
-         && x.add.simm13 < 0x5b)
-        || (is_flat
-            && x.add.op == 3
-            && x.add.op3 == 4
-            && x.add.rs1 == 14
-            ))
+  while (1)
     {
+      /* Recognize stores into the frame from the input registers.
+        This recognizes all non alternate stores of input register,
+        into a location offset from the frame pointer.  */
+      if ((X_OP (insn) == 3
+          && (X_OP3 (insn) & 0x3c) == 4 /* Store, non-alternate.  */
+          && (X_RD (insn) & 0x18) == 0x18 /* Input register.  */
+          && X_I (insn)                /* Immediate mode.  */
+          && X_RS1 (insn) == 30        /* Off of frame pointer.  */
+          /* Into reserved stack space.  */
+          && X_SIMM13 (insn) >= 0x44
+          && X_SIMM13 (insn) < 0x5b))
+       ;
+      else if (is_flat
+              && X_OP (insn) == 3
+              && X_OP3 (insn) == 4
+              && X_RS1 (insn) == 14
+              )
+       {
+         if (saved_regs && X_I (insn))
+           saved_regs->regs[X_RD (insn)] =
+             fi->frame + fi->sp_offset + X_SIMM13 (insn);
+       }
+      else
+       break;
       pc += 4;
-      x.i = read_memory_integer (pc, 4);
+      insn = read_memory_integer (pc, 4);
     }
 
   return pc;
 }
 
+CORE_ADDR 
+skip_prologue (start_pc, frameless_p)
+     CORE_ADDR start_pc;
+     int frameless_p;
+{
+  return examine_prologue (start_pc, frameless_p, NULL, NULL);
+}
+
 /* Check instruction at ADDR to see if it is an annulled branch.
    All other instructions will go to NPC or will trap.
    Set *TARGET if we find a candidate branch; set to zero if not. */
@@ -420,37 +480,187 @@ isannulled (instruction, addr, target)
 {
   branch_type val = not_branch;
   long int offset;             /* Must be signed for sign-extend.  */
-  union
-    {
-      unsigned long int code;
-      struct
-       {
-         unsigned int op:2;
-         unsigned int a:1;
-         unsigned int cond:4;
-         unsigned int op2:3;
-         unsigned int disp22:22;
-       } b;
-    } insn;
 
   *target = 0;
-  insn.code = instruction;
 
-  if (insn.b.op == 0
-      && (insn.b.op2 == 2 || insn.b.op2 == 6 || insn.b.op2 == 7))
+  if (X_OP (instruction) == 0
+      && (X_OP2 (instruction) == 2
+         || X_OP2 (instruction) == 6
+         || X_OP2 (instruction) == 7))
     {
-      if (insn.b.cond == 8)
-       val = insn.b.a ? baa : ba;
+      if (X_COND (instruction) == 8)
+       val = X_A (instruction) ? baa : ba;
       else
-       val = insn.b.a ? bicca : bicc;
-      offset = 4 * ((int) (insn.b.disp22 << 10) >> 10);
+       val = X_A (instruction) ? bicca : bicc;
+      offset = 4 * X_DISP22 (instruction);
       *target = addr + offset;
     }
 
   return val;
 }
+\f
+/* Find register number REGNUM relative to FRAME and put its
+   (raw) contents in *RAW_BUFFER.  Set *OPTIMIZED if the variable
+   was optimized out (and thus can't be fetched).  If the variable
+   was fetched from memory, set *ADDRP to where it was fetched from,
+   otherwise it was fetched from a register.
+
+   The argument RAW_BUFFER must point to aligned memory.  */
+
+void
+get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
+     char *raw_buffer;
+     int *optimized;
+     CORE_ADDR *addrp;
+     struct frame_info *frame;
+     int regnum;
+     enum lval_type *lval;
+{
+  struct frame_info *frame1;
+  CORE_ADDR addr;
 
-/* sparc_frame_find_saved_regs ()
+  if (optimized)
+    *optimized = 0;
+
+  addr = 0;
+  frame1 = frame->next;
+  while (frame1 != NULL)
+    {
+      if (frame1->pc >= (frame1->bottom ? frame1->bottom :
+                        read_register (SP_REGNUM))
+         && frame1->pc <= FRAME_FP (frame1))
+       {
+         /* Dummy frame.  All but the window regs are in there somewhere. */
+         if (regnum >= G1_REGNUM && regnum < G1_REGNUM + 7)
+           addr = frame1->frame + (regnum - G0_REGNUM) * 4 - 0xa0;
+         else if (regnum >= I0_REGNUM && regnum < I0_REGNUM + 8)
+           addr = frame1->frame + (regnum - I0_REGNUM) * 4 - 0xc0;
+         else if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM + 32)
+           addr = frame1->frame + (regnum - FP0_REGNUM) * 4 - 0x80;
+         else if (regnum >= Y_REGNUM && regnum < NUM_REGS)
+           addr = frame1->frame + (regnum - Y_REGNUM) * 4 - 0xe0;
+       }
+      else if (frame1->flat)
+       {
+
+         if (regnum == RP_REGNUM)
+           addr = frame1->pc_addr;
+         else if (regnum == I7_REGNUM)
+           addr = frame1->fp_addr;
+         else
+           {
+             CORE_ADDR func_start;
+             struct frame_saved_regs regs;
+             memset (&regs, 0, sizeof (regs));
+
+             find_pc_partial_function (frame1->pc, NULL, &func_start, NULL);
+             examine_prologue (func_start, 0, frame1, &regs);
+             addr = regs.regs[regnum];
+           }
+       }
+      else
+       {
+         /* Normal frame.  Local and In registers are saved on stack.  */
+         if (regnum >= I0_REGNUM && regnum < I0_REGNUM + 8)
+           addr = (frame1->prev->bottom
+                   + (regnum - I0_REGNUM) * REGISTER_RAW_SIZE (I0_REGNUM)
+                   + FRAME_SAVED_I0);
+         else if (regnum >= L0_REGNUM && regnum < L0_REGNUM + 8)
+           addr = (frame1->prev->bottom
+                   + (regnum - L0_REGNUM) * REGISTER_RAW_SIZE (L0_REGNUM)
+                   + FRAME_SAVED_L0);
+         else if (regnum >= O0_REGNUM && regnum < O0_REGNUM + 8)
+           {
+             /* Outs become ins.  */
+             get_saved_register (raw_buffer, optimized, addrp, frame1,
+                                 (regnum - O0_REGNUM + I0_REGNUM), lval);
+             return;
+           }
+       }
+      if (addr != 0)
+       break;
+      frame1 = frame1->next;
+    }
+  if (addr != 0)
+    {
+      if (lval != NULL)
+       *lval = lval_memory;
+      if (regnum == SP_REGNUM)
+       {
+         if (raw_buffer != NULL)
+           {
+             /* Put it back in target format.  */
+             store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), addr);
+           }
+         if (addrp != NULL)
+           *addrp = 0;
+         return;
+       }
+      if (raw_buffer != NULL)
+       read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+    }
+  else
+    {
+      if (lval != NULL)
+       *lval = lval_register;
+      addr = REGISTER_BYTE (regnum);
+      if (raw_buffer != NULL)
+       read_register_gen (regnum, raw_buffer);
+    }
+  if (addrp != NULL)
+    *addrp = addr;
+}
+
+/* Push an empty stack frame, and record in it the current PC, regs, etc.
+
+   We save the non-windowed registers and the ins.  The locals and outs
+   are new; they don't need to be saved. The i's and l's of
+   the last frame were already saved on the stack.  */
+
+/* Definitely see tm-sparc.h for more doc of the frame format here.  */
+
+void
+sparc_push_dummy_frame ()
+{
+  CORE_ADDR sp, old_sp;
+  char register_temp[0x140];
+
+  old_sp = sp = read_register (SP_REGNUM);
+
+  /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */
+  read_register_bytes (REGISTER_BYTE (Y_REGNUM), &register_temp[0],
+                      REGISTER_RAW_SIZE (Y_REGNUM) * 8);
+
+  read_register_bytes (REGISTER_BYTE (O0_REGNUM), &register_temp[8 * 4],
+                      REGISTER_RAW_SIZE (O0_REGNUM) * 8);
+
+  read_register_bytes (REGISTER_BYTE (G0_REGNUM), &register_temp[16 * 4],
+                      REGISTER_RAW_SIZE (G0_REGNUM) * 8);
+
+  read_register_bytes (REGISTER_BYTE (FP0_REGNUM), &register_temp[24 * 4],
+                      REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
+
+  sp -= 0x140;
+
+  write_register (SP_REGNUM, sp);
+
+  write_memory (sp + 0x60, &register_temp[0], (8 + 8 + 8 + 32) * 4);
+
+  write_register (FP_REGNUM, old_sp);
+
+  /* Set return address register for the call dummy to the current PC.  */
+  write_register (I7_REGNUM, read_pc() - 8);
+}
+
+/* sparc_frame_find_saved_regs ().  This function is here only because
+   pop_frame uses it.  Note there is an interesting corner case which
+   I think few ports of GDB get right--if you are popping a frame
+   which does not save some register that *is* saved by a more inner
+   frame (such a frame will never be a dummy frame because dummy
+   frames save all registers).  Rewriting pop_frame to use
+   get_saved_register would solve this problem and also get rid of the
+   ugly duplication between sparc_frame_find_saved_regs and
+   get_saved_register.
 
    Stores, into a struct frame_saved_regs,
    the addresses of the saved registers of frame described by FRAME_INFO.
@@ -476,7 +686,10 @@ isannulled (instruction, addr, target)
    See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information
    about how this works.  */
 
-void
+static void sparc_frame_find_saved_regs PARAMS ((struct frame_info *,
+                                                struct frame_saved_regs *));
+
+static void
 sparc_frame_find_saved_regs (fi, saved_regs_addr)
      struct frame_info *fi;
      struct frame_saved_regs *saved_regs_addr;
@@ -511,10 +724,13 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr)
     }
   else if (fi->flat)
     {
+      CORE_ADDR func_start;
+      find_pc_partial_function (fi->pc, NULL, &func_start, NULL);
+      examine_prologue (func_start, 0, fi, saved_regs_addr);
+
       /* Flat register window frame.  */
       saved_regs_addr->regs[RP_REGNUM] = fi->pc_addr;
       saved_regs_addr->regs[I7_REGNUM] = fi->fp_addr;
-      frame_addr = fi->bottom ? fi->bottom : read_register (SP_REGNUM);
     }
   else
     {
@@ -554,47 +770,6 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr)
   saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi);
 }
 
-/* Push an empty stack frame, and record in it the current PC, regs, etc.
-
-   We save the non-windowed registers and the ins.  The locals and outs
-   are new; they don't need to be saved. The i's and l's of
-   the last frame were already saved on the stack.  */
-
-/* Definitely see tm-sparc.h for more doc of the frame format here.  */
-
-void
-sparc_push_dummy_frame ()
-{
-  CORE_ADDR sp, old_sp;
-  char register_temp[0x140];
-
-  old_sp = sp = read_register (SP_REGNUM);
-
-  /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */
-  read_register_bytes (REGISTER_BYTE (Y_REGNUM), &register_temp[0],
-                      REGISTER_RAW_SIZE (Y_REGNUM) * 8);
-
-  read_register_bytes (REGISTER_BYTE (O0_REGNUM), &register_temp[8 * 4],
-                      REGISTER_RAW_SIZE (O0_REGNUM) * 8);
-
-  read_register_bytes (REGISTER_BYTE (G0_REGNUM), &register_temp[16 * 4],
-                      REGISTER_RAW_SIZE (G0_REGNUM) * 8);
-
-  read_register_bytes (REGISTER_BYTE (FP0_REGNUM), &register_temp[24 * 4],
-                      REGISTER_RAW_SIZE (FP0_REGNUM) * 32);
-
-  sp -= 0x140;
-
-  write_register (SP_REGNUM, sp);
-
-  write_memory (sp + 0x60, &register_temp[0], (8 + 8 + 8 + 32) * 4);
-
-  write_register (FP_REGNUM, old_sp);
-
-  /* Set return address register for the call dummy to the current PC.  */
-  write_register (I7_REGNUM, read_pc() - 8);
-}
-
 /* Discard from the stack the innermost frame, restoring all saved registers.
 
    Note that the values stored in fsr by get_frame_saved_regs are *in
@@ -618,7 +793,7 @@ sparc_pop_frame ()
   char raw_buffer[REGISTER_BYTES];
   int regnum;
 
-  get_frame_saved_regs (frame, &fsr);
+  sparc_frame_find_saved_regs (frame, &fsr);
   if (fsr.regs[FP0_REGNUM])
     {
       read_memory (fsr.regs[FP0_REGNUM], raw_buffer, 32 * 4);
@@ -650,9 +825,16 @@ sparc_pop_frame ()
       for (regnum = I0_REGNUM; regnum < I0_REGNUM + 8; ++regnum)
        if (fsr.regs[regnum])
          write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
-      for (regnum = O0_REGNUM; regnum < O0_REGNUM + 8; ++regnum)
+
+      /* Handle all outs except stack pointer (o0-o5; o7).  */
+      for (regnum = O0_REGNUM; regnum < O0_REGNUM + 6; ++regnum)
        if (fsr.regs[regnum])
          write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
+      if (fsr.regs[O0_REGNUM + 7])
+       write_register (O0_REGNUM + 7,
+                       read_memory_integer (fsr.regs[O0_REGNUM + 7], 4));
+
+      write_register (SP_REGNUM, frame->frame, 4);
     }
   else if (fsr.regs[I0_REGNUM])
     {
@@ -690,9 +872,21 @@ sparc_pop_frame ()
        write_register (NPC_REGNUM,
                        read_memory_integer (fsr.regs[NPC_REGNUM], 4));
     }
-  else if (frame->flat && frame->pc_addr)
+  else if (frame->flat)
     {
-      pc = PC_ADJUST ((CORE_ADDR) read_memory_integer (frame->pc_addr, 4));
+      if (frame->pc_addr)
+       pc = PC_ADJUST ((CORE_ADDR) read_memory_integer (frame->pc_addr, 4));
+      else
+       {
+         /* I think this happens only in the innermost frame, if so then
+            it is a complicated way of saying
+            "pc = read_register (O7_REGNUM);".  */
+         char buf[MAX_REGISTER_RAW_SIZE];
+         get_saved_register (buf, 0, 0, frame, O7_REGNUM, 0);
+         pc = PC_ADJUST (extract_address
+                         (buf, REGISTER_RAW_SIZE (O7_REGNUM)));
+       }
+
       write_register (PC_REGNUM,  pc);
       write_register (NPC_REGNUM, pc + 4);
     }