* sparc-tdep.c (sparc_target_architecture_hook): New function to
authorMark Alexander <marka@cygnus>
Tue, 2 Jun 1998 09:19:54 +0000 (09:19 +0000)
committerMark Alexander <marka@cygnus>
Tue, 2 Jun 1998 09:19:54 +0000 (09:19 +0000)
set endianness based on machine type.
(_initialize_sparc_tdep): Initialize target_architecture_hook.
(sparc_print_register_hook): Print PSR and FPSR in fancy format
on 32-bit machines.
* config/sparc/tm-sparc.h (PRINT_REGISTER_HOOK): Redefine to
call sparc_print_register_hook instead of using inline code.
* config/sparc/tm-sp64.h (PRINT_REGISTER_HOOK): Remove.

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

index a5c88af57395727d21f0af83512aaf8089459e28..f7732d463d8831e5a2198e668fff320d99bace75 100644 (file)
@@ -1,3 +1,14 @@
+Tue Jun  2 02:01:56 1998  Mark Alexander  <marka@cygnus.com>
+
+       * sparc-tdep.c (sparc_target_architecture_hook): New function to
+       set endianness based on machine type.
+       (_initialize_sparc_tdep): Initialize target_architecture_hook.
+       (sparc_print_register_hook): Print PSR and FPSR in fancy format
+       on 32-bit machines.
+       * config/sparc/tm-sparc.h (PRINT_REGISTER_HOOK): Redefine to
+       call sparc_print_register_hook instead of using inline code.
+       * config/sparc/tm-sp64.h (PRINT_REGISTER_HOOK): Remove.
+
 Thu May 28 17:19:14 1998  Keith Seitz  <keiths@cygnus.com>
 
        * main.c (main): Check for NULL from getenv on CYGWIN32.
index 7f48bdc15edc4434edc7fbe81b474eea0f3241f7..4665bcc715ec63466a877e2a22fef168100a17e7 100644 (file)
@@ -335,14 +335,6 @@ struct value;
 #undef  FRAME_SPECIFICATION_DYADIC
 #define FRAME_SPECIFICATION_DYADIC
 
-/* To print every pair of float registers as a double, we use this hook.
-   We also print the condition code registers in a readable format
-   (FIXME: can expand this to all control regs).  */
-
-#undef         PRINT_REGISTER_HOOK
-#define        PRINT_REGISTER_HOOK(regno)      \
-  sparc_print_register_hook (regno)
-
 /* Offsets into jmp_buf.
    FIXME: This was borrowed from the v8 stuff and will probably have to change
    for v9.  */
index aaadc6b8f116c9c46e9534512b8d5c0cc555396e..ff5c6774a0a97e1aa766653fb12dbf508324ca30 100644 (file)
@@ -542,19 +542,15 @@ void sparc_fix_call_dummy PARAMS ((char *dummy, CORE_ADDR pc, CORE_ADDR fun,
 #define SETUP_ARBITRARY_FRAME(argc, argv) setup_arbitrary_frame (argc, argv)
 extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *));
 
-/* To print every pair of float registers as a double, we use this hook.  */
+/* To print every pair of float registers as a double, we use this hook.
+   We also print the condition code registers in a readable format
+   (FIXME: can expand this to all control regs).  */
 
+#undef         PRINT_REGISTER_HOOK
 #define        PRINT_REGISTER_HOOK(regno)      \
-  if (((regno) >= FP0_REGNUM)          \
-   && ((regno) <  FP0_REGNUM + 32)     \
-   && (0 == ((regno) & 1))) {          \
-    char doublereg[8];         /* two float regs */    \
-    if (!read_relative_register_raw_bytes ((regno)  , doublereg  )     \
-     && !read_relative_register_raw_bytes ((regno)+1, doublereg+4)) {  \
-      printf("\t");                    \
-      print_floating (doublereg, builtin_type_double, stdout); \
-    }                                  \
-  }
+  sparc_print_register_hook (regno)
+extern void sparc_print_register_hook PARAMS ((int regno));
+
 
 /* Optimization for storing registers to the inferior.  The hook
    DO_DEFERRED_STORES
index 2b970a6f8930bba999e824488a1ecf961ec4296d..25d92cf5d4d1c58d79388beb3b27c8046bf963e3 100644 (file)
@@ -35,6 +35,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "gdbcore.h"
 
+#if defined(TARGET_SPARCLET) || defined(TARGET_SPARCLITE)
+#define SPARC_HAS_FPU 0
+#else
+#define SPARC_HAS_FPU 1
+#endif
+
 #ifdef GDB_TARGET_IS_SPARC64
 #define FP_REGISTER_BYTES (64 * 4)
 #else
@@ -59,6 +65,29 @@ extern int stop_after_trap;
 
 int deferred_stores = 0;       /* Cumulates stores we want to do eventually. */
 
+
+/* Fetch a single instruction.  Even on bi-endian machines
+   such as sparc86x, instructions are always big-endian.  */
+
+static unsigned long
+fetch_instruction (pc)
+     CORE_ADDR pc;
+{
+  unsigned long retval;
+  int i;
+  unsigned char buf[4];
+
+  read_memory (pc, buf, sizeof (buf));
+
+  /* Start at the most significant end of the integer, and work towards
+     the least significant.  */
+  retval = 0;
+  for (i = 0; i < sizeof (buf); ++i)
+    retval = (retval << 8) | buf[i];
+  return retval;
+}
+
+
 /* Branches with prediction are treated like their non-predicting cousins.  */
 /* FIXME: What about floating point branches?  */
 
@@ -136,7 +165,7 @@ single_step (ignore)
       /* printf_unfiltered ("set break at %x\n",next_pc); */
 
       pc = read_register (PC_REGNUM);
-      pc_instruction = read_memory_integer (pc, 4);
+      pc_instruction = fetch_instruction (pc);
       br = isbranch (pc_instruction, pc, &target);
       brknpc4 = brktrg = 0;
 
@@ -200,7 +229,7 @@ sparc_init_extra_frame_info (fromleaf, fi)
   fi->bottom =
     (fi->next ?
      (fi->frame == fi->next->frame ? fi->next->bottom : fi->next->frame) :
-     read_register (SP_REGNUM));
+     read_sp ());
 
   /* If fi->next is NULL, then we already set ->frame by passing read_fp()
      to create_new_frame.  */
@@ -222,8 +251,14 @@ sparc_init_extra_frame_info (fromleaf, fi)
        }
       else
        {
+         /* Should we adjust for stack bias here? */
          get_saved_register (buf, 0, 0, fi, FP_REGNUM, 0);
          fi->frame = extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
+#ifdef GDB_TARGET_IS_SPARC64
+         if (fi->frame & 1)
+           fi->frame += 2047;
+#endif
+         
        }
     }
 
@@ -236,14 +271,14 @@ sparc_init_extra_frame_info (fromleaf, fi)
         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);
+      insn = fetch_instruction (addr);
       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.  */
-         insn = read_memory_integer (addr + 4, 4);
+         insn = fetch_instruction (addr + 4);
          if (X_OP (insn) == 3
              && X_RD (insn) == 31
              && X_OP3 (insn) == 4
@@ -259,13 +294,16 @@ sparc_init_extra_frame_info (fromleaf, fi)
              /* Overwrite the frame's address with the value in %i7.  */
              get_saved_register (buf, 0, 0, fi, I7_REGNUM, 0);
              fi->frame = extract_address (buf, REGISTER_RAW_SIZE (I7_REGNUM));
-
+#ifdef GDB_TARGET_IS_SPARC64
+             if (fi->frame & 1)
+               fi->frame += 2047;
+#endif
              /* Record where the fp got saved.  */
              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;
-             insn = read_memory_integer (addr + 12, 4);
+             insn = fetch_instruction (addr + 12);
              if (X_OP (insn) == 3
                  && X_RD (insn) == 15
                  && X_OP3 (insn) == 4
@@ -426,14 +464,14 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
   CORE_ADDR pc = start_pc;
   int is_flat = 0;
 
-  insn = read_memory_integer (pc, 4);
+  insn = fetch_instruction (pc);
 
   /* Recognize the `sethi' insn and record its destination.  */
   if (X_OP (insn) == 0 && X_OP2 (insn) == 4)
     {
       dest = X_RD (insn);
       pc += 4;
-      insn = read_memory_integer (pc, 4);
+      insn = fetch_instruction (pc);
     }
 
   /* Recognize an add immediate value to register to either %g1 or
@@ -447,7 +485,7 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
       && (X_RD (insn) == 1 || X_RD (insn) == dest))
     {
       pc += 4;
-      insn = read_memory_integer (pc, 4);
+      insn = fetch_instruction (pc);
     }
 
   /* Recognize any SAVE insn.  */
@@ -456,7 +494,7 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
       pc += 4;
       if (frameless_p)                 /* If the save is all we care about, */
        return pc;                      /* return before doing more work */
-      insn = read_memory_integer (pc, 4);
+      insn = fetch_instruction (pc);
     }
   /* Recognize add to %sp.  */
   else if (X_OP (insn) == 2 && X_RD (insn) == 14 && X_OP3 (insn) == 0)
@@ -465,7 +503,7 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
       if (frameless_p)                 /* If the add is all we care about, */
        return pc;                      /* return before doing more work */
       is_flat = 1;
-      insn = read_memory_integer (pc, 4);
+      insn = fetch_instruction (pc);
       /* Recognize store of frame pointer (i7).  */
       if (X_OP (insn) == 3
          && X_RD (insn) == 31
@@ -473,7 +511,7 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
          && X_RS1 (insn) == 14)
        {
          pc += 4;
-         insn = read_memory_integer (pc, 4);
+         insn = fetch_instruction (pc);
 
          /* Recognize sub %sp, <anything>, %i7.  */
          if (X_OP (insn) ==  2
@@ -482,7 +520,7 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
              && X_RD (insn) == 31)
            {
              pc += 4;
-             insn = read_memory_integer (pc, 4);
+             insn = fetch_instruction (pc);
            }
          else
            return pc;
@@ -521,7 +559,7 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
       else
        break;
       pc += 4;
-      insn = read_memory_integer (pc, 4);
+      insn = fetch_instruction (pc);
     }
 
   return pc;
@@ -670,7 +708,7 @@ get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
   while (frame1 != NULL)
     {
       if (frame1->pc >= (frame1->bottom ? frame1->bottom :
-                        read_register (SP_REGNUM))
+                        read_sp ())
          && frame1->pc <= FRAME_FP (frame1))
        {
          /* Dummy frame.  All but the window regs are in there somewhere.
@@ -792,7 +830,7 @@ get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
 /* See tm-sparc.h for how this is calculated.  */
 #ifdef FP0_REGNUM
 #define DUMMY_STACK_REG_BUF_SIZE \
-(((8+8+8) * SPARC_INTREG_SIZE) + (32 * REGISTER_RAW_SIZE (FP0_REGNUM)))
+(((8+8+8) * SPARC_INTREG_SIZE) + FP_REGISTER_BYTES)
 #else
 #define DUMMY_STACK_REG_BUF_SIZE \
 (((8+8+8) * SPARC_INTREG_SIZE) )
@@ -805,9 +843,14 @@ sparc_push_dummy_frame ()
   CORE_ADDR sp, old_sp;
   char register_temp[DUMMY_STACK_SIZE];
 
-  old_sp = sp = read_register (SP_REGNUM);
+  old_sp = sp = read_sp ();
 
 #ifdef GDB_TARGET_IS_SPARC64
+  /* PC, NPC, CCR, FSR, FPRS, Y, ASI */
+  read_register_bytes (REGISTER_BYTE (PC_REGNUM), &register_temp[0],
+                      REGISTER_RAW_SIZE (PC_REGNUM) * 7);
+  read_register_bytes (REGISTER_BYTE (PSTATE_REGNUM), &register_temp[8],
+                      REGISTER_RAW_SIZE (PSTATE_REGNUM));
   /* FIXME: not sure what needs to be saved here.  */
 #else
   /* Y, PS, WIM, TBR, PC, NPC, FPS, CPS regs */
@@ -831,15 +874,37 @@ sparc_push_dummy_frame ()
 
   sp -= DUMMY_STACK_SIZE;
 
-  write_register (SP_REGNUM, sp);
+  write_sp (sp);
 
   write_memory (sp + DUMMY_REG_SAVE_OFFSET, &register_temp[0],
                DUMMY_STACK_REG_BUF_SIZE);
 
-  write_register (FP_REGNUM, old_sp);
+  if (strcmp (target_shortname, "sim") != 0)
+    {
+      write_fp (old_sp);
 
-  /* Set return address register for the call dummy to the current PC.  */
-  write_register (I7_REGNUM, read_pc() - 8);
+      /* Set return address register for the call dummy to the current PC.  */
+      write_register (I7_REGNUM, read_pc() - 8);
+    }
+  else
+    {
+      /* The call dummy will write this value to FP before executing
+         the 'save'.  This ensures that register window flushes work
+        correctly in the simulator.  */
+      write_register (G0_REGNUM+1, read_register (FP_REGNUM));
+    
+      /* The call dummy will write this value to FP after executing
+         the 'save'. */
+      write_register (G0_REGNUM+2, old_sp);
+    
+      /* The call dummy will write this value to the return address (%i7) after
+        executing the 'save'. */
+      write_register (G0_REGNUM+3, read_pc() - 8);
+    
+      /* Set the FP that the call dummy will be using after the 'save'.
+        This makes backtraces from an inferior function call work properly.  */
+      write_register (FP_REGNUM, old_sp);
+    }
 }
 
 /* sparc_frame_find_saved_regs ().  This function is here only because
@@ -873,7 +938,7 @@ sparc_push_dummy_frame ()
    is a return address minus 8.)  sparc_pop_frame knows how to
    deal with that.  Other routines might or might not.
 
-   See tm-sparc.h (PUSH_FRAME and friends) for CRITICAL information
+   See tm-sparc.h (PUSH_DUMMY_FRAME and friends) for CRITICAL information
    about how this works.  */
 
 static void sparc_frame_find_saved_regs PARAMS ((struct frame_info *,
@@ -893,7 +958,7 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr)
   memset (saved_regs_addr, 0, sizeof (*saved_regs_addr));
 
   if (fi->pc >= (fi->bottom ? fi->bottom :
-                  read_register (SP_REGNUM))
+                  read_sp ())
       && fi->pc <= FRAME_FP(fi))
     {
       /* Dummy frame.  All but the window regs are in there somewhere. */
@@ -913,16 +978,27 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr)
 #ifdef GDB_TARGET_IS_SPARC64
       for (regnum = FP0_REGNUM + 32; regnum < FP_MAX_REGNUM; regnum++)
        saved_regs_addr->regs[regnum] =
-         frame_addr + 32 * 4 + (regnum - FP0_REGNUM - 32) * 8
+         frame_addr + 32 * 4 + (regnum - FP0_REGNUM - 32) * 4
            - DUMMY_STACK_REG_BUF_SIZE + 24 * SPARC_INTREG_SIZE;
 #endif
 #endif /* FP0_REGNUM */
+#ifdef GDB_TARGET_IS_SPARC64
+      for (regnum = PC_REGNUM; regnum < PC_REGNUM + 7; regnum++)
+       {
+         saved_regs_addr->regs[regnum] =
+           frame_addr + (regnum - PC_REGNUM) * SPARC_INTREG_SIZE 
+             - DUMMY_STACK_REG_BUF_SIZE;
+       }
+      saved_regs_addr->regs[PSTATE_REGNUM] = 
+       frame_addr + 8 * SPARC_INTREG_SIZE - DUMMY_STACK_REG_BUF_SIZE;
+#else
       for (regnum = Y_REGNUM; regnum < NUM_REGS; regnum++)
        saved_regs_addr->regs[regnum] =
          frame_addr + (regnum - Y_REGNUM) * SPARC_INTREG_SIZE 
            - DUMMY_STACK_REG_BUF_SIZE;
+#endif
       frame_addr = fi->bottom ?
-       fi->bottom : read_register (SP_REGNUM);
+       fi->bottom : read_sp ();
     }
   else if (fi->flat)
     {
@@ -938,7 +1014,7 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr)
     {
       /* Normal frame.  Just Local and In registers */
       frame_addr = fi->bottom ?
-       fi->bottom : read_register (SP_REGNUM);
+       fi->bottom : read_sp ();
       for (regnum = L0_REGNUM; regnum < L0_REGNUM+8; regnum++)
        saved_regs_addr->regs[regnum] =
          (frame_addr + (regnum - L0_REGNUM) * SPARC_INTREG_SIZE
@@ -960,7 +1036,7 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr)
          CORE_ADDR next_next_frame_addr =
            (fi->next->bottom ?
             fi->next->bottom :
-            read_register (SP_REGNUM));
+            read_sp ());
          for (regnum = O0_REGNUM; regnum < O0_REGNUM+8; regnum++)
            saved_regs_addr->regs[regnum] =
              (next_next_frame_addr
@@ -969,6 +1045,7 @@ sparc_frame_find_saved_regs (fi, saved_regs_addr)
        }
     }
   /* Otherwise, whatever we would get from ptrace(GETREGS) is accurate */
+  /* FIXME -- should this adjust for the sparc64 offset? */
   saved_regs_addr->regs[SP_REGNUM] = FRAME_FP (fi);
 }
 
@@ -1046,7 +1123,7 @@ sparc_pop_frame ()
                        read_memory_integer (fsr.regs[O0_REGNUM + 7],
                                             SPARC_INTREG_SIZE));
 
-      write_register (SP_REGNUM, frame->frame);
+      write_sp (frame->frame);
     }
   else if (fsr.regs[I0_REGNUM])
     {
@@ -1062,6 +1139,10 @@ sparc_pop_frame ()
         locals from the registers array, so we need to muck with the
         registers array.  */
       sp = fsr.regs[SP_REGNUM];
+#ifdef GDB_TARGET_IS_SPARC64
+      if (sp & 1)
+       sp += 2047;
+#endif
       read_memory (sp, reg_temp, SPARC_INTREG_SIZE * 16);
 
       /* Restore the out registers.
@@ -1392,7 +1473,6 @@ sunpro_static_transform_name (name)
 }
 #endif /* STATIC_TRANSFORM_NAME */
 \f
-#ifdef GDB_TARGET_IS_SPARC64
 
 /* Utilities for printing registers.
    Page numbers refer to the SPARC Architecture Manual.  */
@@ -1503,6 +1583,7 @@ sparc_print_register_hook (regno)
   /* pages 40 - 60 */
   switch (regno)
     {
+#ifdef GDB_TARGET_IS_SPARC64
     case CCR_REGNUM :
       printf_unfiltered("\t");
       dump_ccreg ("xcc", val >> 4);
@@ -1576,12 +1657,32 @@ sparc_print_register_hook (regno)
     case OTHERWIN_REGNUM :
       printf ("\t%d", BITS (0, 31));
       break;
+#else
+    case PS_REGNUM:
+      printf ("\ticc:%c%c%c%c, pil:%d, s:%d, ps:%d, et:%d, cwp:%d",
+             BITS (23, 1) ? 'N' : '-', BITS (22, 1) ? 'Z' : '-',
+             BITS (21, 1) ? 'V' : '-', BITS (20, 1) ? 'C' : '-',
+             BITS (8, 15), BITS (7, 1), BITS (6, 1), BITS (5, 1),
+             BITS (0, 31));
+      break;
+    case FPS_REGNUM:
+      {
+       static char *fcc[4] = { "=", "<", ">", "?" };
+       static char *rd[4] = { "N", "0", "+", "-" };
+       /* Long, yes, but I'd rather leave it as is and use a wide screen.  */
+       printf ("\trd:%s, tem:%d, ns:%d, ver:%d, ftt:%d, qne:%d, "
+               "fcc:%s, aexc:%d, cexc:%d",
+               rd[BITS (30, 3)], BITS (23, 31), BITS (22, 1), BITS (17, 7),
+               BITS (14, 7), BITS (13, 1), fcc[BITS (10, 3)], BITS (5, 31),
+               BITS (0, 31));
+       break;
+      }
+
+#endif /* GDB_TARGET_IS_SPARC64 */
     }
 
 #undef BITS
 }
-
-#endif
 \f
 int
 gdb_print_insn_sparc (memaddr, info)
@@ -1655,10 +1756,317 @@ sparc_push_arguments (nargs, args, sp, struct_return, struct_addr)
 
   return sp;
 }
+
+
+/* Extract from an array REGBUF containing the (raw) register state
+   a function return value of type TYPE, and copy that, in virtual format,
+   into VALBUF.  */
+
+void
+sparc_extract_return_value (type, regbuf, valbuf)
+     struct type *type;
+     char *regbuf;
+     char *valbuf;
+{
+  int typelen = TYPE_LENGTH (type);
+  int regsize = REGISTER_RAW_SIZE (O0_REGNUM);
+
+  if (TYPE_CODE (type) == TYPE_CODE_FLT && SPARC_HAS_FPU)
+    memcpy (valbuf, &regbuf [REGISTER_BYTE (FP0_REGNUM)], typelen);
+  else
+    memcpy (valbuf,
+           &regbuf [O0_REGNUM * regsize +
+                    (typelen >= regsize ? 0 : regsize - typelen)],
+           typelen);
+}
+
+
+/* Write into appropriate registers a function return value
+   of type TYPE, given in virtual format.  On SPARCs with FPUs,
+   float values are returned in %f0 (and %f1).  In all other cases,
+   values are returned in register %o0.  */
+
+void
+sparc_store_return_value (type, valbuf)
+     struct type *type;
+     char *valbuf;
+{
+  int regno;
+  char buffer[MAX_REGISTER_RAW_SIZE];
+
+  if (TYPE_CODE (type) == TYPE_CODE_FLT && SPARC_HAS_FPU)
+    /* Floating-point values are returned in the register pair */
+    /* formed by %f0 and %f1 (doubles are, anyway).  */
+    regno = FP0_REGNUM;
+  else
+    /* Other values are returned in register %o0.  */
+    regno = O0_REGNUM;
+
+  /* Add leading zeros to the value. */
+  if (TYPE_LENGTH (type) < REGISTER_RAW_SIZE(regno))
+    {
+      bzero (buffer, REGISTER_RAW_SIZE(regno));
+      memcpy (buffer + REGISTER_RAW_SIZE(regno) - TYPE_LENGTH (type), valbuf,
+             TYPE_LENGTH (type));
+      write_register_bytes (REGISTER_BYTE (regno), buffer, 
+                           REGISTER_RAW_SIZE(regno));
+    }
+  else
+    write_register_bytes (REGISTER_BYTE (regno), valbuf, TYPE_LENGTH (type));
+}
+
+
+/* Insert the function address into a call dummy instsruction sequence
+   stored at DUMMY.
+
+   For structs and unions, if the function was compiled with Sun cc,
+   it expects 'unimp' after the call.  But gcc doesn't use that
+   (twisted) convention.  So leave a nop there for gcc (FIX_CALL_DUMMY
+   can assume it is operating on a pristine CALL_DUMMY, not one that
+   has already been customized for a different function).  */
+
+void
+sparc_fix_call_dummy (dummy, pc, fun, value_type, using_gcc)
+     char *dummy;
+     CORE_ADDR pc;
+     CORE_ADDR fun;
+     struct type *value_type;
+     int using_gcc;
+{
+  int i;
+
+  /* Store the relative adddress of the target function into the
+     'call' instruction. */
+  store_unsigned_integer (dummy + CALL_DUMMY_CALL_OFFSET, 4,
+                         (0x40000000
+                          | (((fun - (pc + CALL_DUMMY_CALL_OFFSET)) >> 2)
+                              & 0x3fffffff)));
+
+  /* Comply with strange Sun cc calling convention for struct-returning
+     functions.  */
+  if (!using_gcc
+      && (TYPE_CODE (value_type) == TYPE_CODE_STRUCT
+         || TYPE_CODE (value_type) == TYPE_CODE_UNION))
+    store_unsigned_integer (dummy + CALL_DUMMY_CALL_OFFSET + 8, 4,
+                           TYPE_LENGTH (value_type) & 0x1fff);
+
+#ifndef GDB_TARGET_IS_SPARC64
+  /* If this is not a simulator target, change the first four instructions
+     of the call dummy to NOPs.  Those instructions include a 'save'
+     instruction and are designed to work around problems with register
+     window flushing in the simulator. */
+  if (strcmp (target_shortname, "sim") != 0)
+    {
+      for (i = 0; i < 4; i++)
+       store_unsigned_integer (dummy + (i * 4), 4, 0x01000000);
+    }
+#endif
+}
+
+
+/* Set target byte order based on machine type. */
+
+static int
+sparc_target_architecture_hook (ap)
+     const bfd_arch_info_type *ap;
+{
+  int i, j;
+
+  if (ap->mach == bfd_mach_sparc_sparclite_le)
+    target_byte_order = LITTLE_ENDIAN;
+  return 1;
+}
+
 \f
 void
 _initialize_sparc_tdep ()
 {
   tm_print_insn = gdb_print_insn_sparc;
   tm_print_insn_info.mach = TM_PRINT_INSN_MACH;  /* Selects sparc/sparclite */
+  target_architecture_hook = sparc_target_architecture_hook;
+}
+
+
+#ifdef GDB_TARGET_IS_SPARC64
+
+/* Compensate for stack bias. Note that we currently don't handle mixed
+   32/64 bit code. */
+CORE_ADDR
+sparc64_read_sp ()
+{
+  CORE_ADDR sp = read_register (SP_REGNUM);
+
+  if (sp & 1)
+    sp += 2047;
+  return sp;
+}
+
+CORE_ADDR
+sparc64_read_fp ()
+{
+  CORE_ADDR fp = read_register (FP_REGNUM);
+
+  if (fp & 1)
+    fp += 2047;
+  return fp;
+}
+
+void
+sparc64_write_sp (val)
+     CORE_ADDR val;
+{
+  CORE_ADDR oldsp = read_register (SP_REGNUM);
+  if (oldsp & 1)
+    write_register (SP_REGNUM, val - 2047);
+  else
+    write_register (SP_REGNUM, val);
+}
+
+void
+sparc64_write_fp (val)
+     CORE_ADDR val;
+{
+  CORE_ADDR oldfp = read_register (FP_REGNUM);
+  if (oldfp & 1)
+    write_register (FP_REGNUM, val - 2047);
+  else
+    write_register (FP_REGNUM, val);
+}
+
+/* The SPARC 64 ABI passes floating-point arguments in FP0-31. They are
+   also copied onto the stack in the correct places. */
+
+CORE_ADDR
+sp64_push_arguments (nargs, args, sp, struct_return, struct_retaddr)
+     int nargs;
+     value_ptr *args;
+     CORE_ADDR sp;
+     unsigned char struct_return;
+     CORE_ADDR struct_retaddr;
+{
+  int x;
+  int regnum = 0;
+  CORE_ADDR tempsp;
+  
+  sp = (sp & ~(((unsigned long)TYPE_LENGTH (builtin_type_long)) - 1UL));
+
+  /* Figure out how much space we'll need. */
+  for (x = nargs - 1; x >= 0; x--)
+    {
+      int len = TYPE_LENGTH (check_typedef (VALUE_TYPE (args[x])));
+      value_ptr copyarg = args[x];
+      int copylen = len;
+
+      /* This code is, of course, no longer correct. */
+      if (copylen < TYPE_LENGTH (builtin_type_long))
+       {
+         copyarg = value_cast(builtin_type_long, copyarg);
+          copylen = TYPE_LENGTH (builtin_type_long);
+        }
+      sp -= copylen;
+    }
+
+  /* Round down. */
+  sp = sp & ~7;
+  tempsp = sp;
+
+  /* Now write the arguments onto the stack, while writing FP arguments
+     into the FP registers. */
+  for (x = 0; x < nargs; x++)
+    {
+      int len = TYPE_LENGTH (check_typedef (VALUE_TYPE (args[x])));
+      value_ptr copyarg = args[x];
+      int copylen = len;
+
+      /* This code is, of course, no longer correct. */
+      if (copylen < TYPE_LENGTH (builtin_type_long))
+       {
+         copyarg = value_cast(builtin_type_long, copyarg);
+          copylen = TYPE_LENGTH (builtin_type_long);
+        }
+      write_memory (tempsp, VALUE_CONTENTS (copyarg), copylen);
+      tempsp += copylen;
+      if (TYPE_CODE (VALUE_TYPE (args[x])) == TYPE_CODE_FLT && regnum < 32)
+       {
+         /* This gets copied into a FP register. */
+         int nextreg = regnum + 2;
+         char *data = VALUE_CONTENTS (args[x]);
+         /* Floats go into the lower half of a FP register pair; quads
+            use 2 pairs. */
+
+         if (len == 16)
+           nextreg += 2;
+         else if (len == 4)
+           regnum++;
+
+         write_register_bytes (REGISTER_BYTE (FP0_REGNUM + regnum),
+                               data,
+                               len);
+         regnum = nextreg;
+       }
+    }
+  return sp;
+}
+
+/* Values <= 32 bytes are returned in o0-o3 (floating-point values are
+   returned in f0-f3). */
+void
+sparc64_extract_return_value (type, regbuf, valbuf, bitoffset)
+     struct type *type;
+     char *regbuf;
+     char *valbuf;
+     int bitoffset;
+{
+  int typelen = TYPE_LENGTH (type);
+  int regsize = REGISTER_RAW_SIZE (O0_REGNUM);
+
+  if (TYPE_CODE (type) == TYPE_CODE_FLT && SPARC_HAS_FPU)
+    {
+      memcpy (valbuf, &regbuf [REGISTER_BYTE (FP0_REGNUM)], typelen);
+      return;
+    }
+
+  if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+      || (TYPE_LENGTH (type) > 32))
+    {
+      memcpy (valbuf,
+             &regbuf [O0_REGNUM * regsize +
+                     (typelen >= regsize ? 0 : regsize - typelen)],
+             typelen);
+      return;
+    }
+  else
+    {
+      char *o0 = &regbuf[O0_REGNUM * regsize];
+      char *f0 = &regbuf[FP0_REGNUM * regsize];
+      int x;
+
+      for (x = 0; x < TYPE_NFIELDS (type); x++)
+       {
+         struct field *f = &TYPE_FIELDS(type)[x];
+         /* FIXME: We may need to handle static fields here. */
+         int whichreg = (f->loc.bitpos + bitoffset) / 32;
+         int remainder = ((f->loc.bitpos + bitoffset) % 32) / 8;
+         int where = (f->loc.bitpos + bitoffset) / 8;
+         int size = TYPE_LENGTH (f->type);
+         int typecode = TYPE_CODE (f->type);
+
+         if (typecode == TYPE_CODE_STRUCT)
+           {
+             sparc64_extract_return_value (f->type,
+                                           regbuf,
+                                           valbuf,
+                                           bitoffset + f->loc.bitpos);
+           }
+         else if (typecode == TYPE_CODE_FLT)
+           {
+             memcpy (valbuf + where, &f0[whichreg * 4] + remainder, size);
+           }
+         else
+           {
+             memcpy (valbuf + where, &o0[whichreg * 4] + remainder, size);
+           }
+       }
+    }
 }
+#endif