import gdb-1999-06-14 snapshot
[deliverable/binutils-gdb.git] / gdb / sparc-tdep.c
index 25d92cf5d4d1c58d79388beb3b27c8046bf963e3..7a1abf84282c15c2983fdf917755aad8c2ce4cfe 100644 (file)
@@ -66,6 +66,13 @@ extern int stop_after_trap;
 int deferred_stores = 0;       /* Cumulates stores we want to do eventually. */
 
 
+/* Some machines, such as Fujitsu SPARClite 86x, have a bi-endian mode
+   where instructions are big-endian and data are little-endian.
+   This flag is set when we detect that the target is of this type. */
+
+int bi_endian = 0;
+
+
 /* Fetch a single instruction.  Even on bi-endian machines
    such as sparc86x, instructions are always big-endian.  */
 
@@ -130,13 +137,6 @@ static int brknpc4, brktrg;
 typedef char binsn_quantum[BREAKPOINT_MAX];
 static binsn_quantum break_mem[3];
 
-/* Non-zero if we just simulated a single-step ptrace call.  This is
-   needed because we cannot remove the breakpoints in the inferior
-   process until after the `wait' in `wait_for_inferior'.  Used for
-   sun4. */
-
-int one_stepped;
-
 static branch_type isbranch PARAMS ((long, CORE_ADDR, CORE_ADDR *));
 
 /* single_step() is called just before we want to resume the inferior,
@@ -148,14 +148,15 @@ static branch_type isbranch PARAMS ((long, CORE_ADDR, CORE_ADDR *));
    set up a simulated single-step, we undo our damage.  */
 
 void
-single_step (ignore)
+sparc_software_single_step (ignore, insert_breakpoints_p)
      enum target_signal ignore; /* pid, but we don't need it */
+     int insert_breakpoints_p;
 {
   branch_type br;
   CORE_ADDR pc;
   long pc_instruction;
 
-  if (!one_stepped)
+  if (insert_breakpoints_p)
     {
       /* Always set breakpoint for NPC.  */
       next_pc = read_register (NPC_REGNUM);
@@ -191,10 +192,6 @@ single_step (ignore)
          target_insert_breakpoint (target, break_mem[2]);
        }
 #endif
-
-      /* We are ready to let it go */
-      one_stepped = 1;
-      return;
     }
   else
     {
@@ -206,8 +203,6 @@ single_step (ignore)
 
       if (brktrg)
        target_remove_breakpoint (target, break_mem[2]);
-
-      one_stepped = 0;
     }
 }
 \f
@@ -223,7 +218,7 @@ sparc_init_extra_frame_info (fromleaf, fi)
      struct frame_info *fi;
 {
   char *name;
-  CORE_ADDR addr;
+  CORE_ADDR prologue_start, prologue_end;
   int insn;
 
   fi->bottom =
@@ -265,20 +260,21 @@ sparc_init_extra_frame_info (fromleaf, fi)
   /* 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))
+  fi->in_prologue = 0;
+  if (find_pc_partial_function (fi->pc, &name, &prologue_start, &prologue_end))
     {
       /* See if the function starts with an add (which will be of a
         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 = fetch_instruction (addr);
+      insn = fetch_instruction (prologue_start, 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.  */
-         insn = fetch_instruction (addr + 4);
+         insn = fetch_instruction (prologue_start + 4);
          if (X_OP (insn) == 3
              && X_RD (insn) == 31
              && X_OP3 (insn) == 4
@@ -303,7 +299,7 @@ sparc_init_extra_frame_info (fromleaf, fi)
 
              /* Also try to collect where the pc got saved to.  */
              fi->pc_addr = 0;
-             insn = fetch_instruction (addr + 12);
+             insn = fetch_instruction (prologue_start + 12);
              if (X_OP (insn) == 3
                  && X_RD (insn) == 15
                  && X_OP3 (insn) == 4
@@ -311,6 +307,35 @@ sparc_init_extra_frame_info (fromleaf, fi)
                fi->pc_addr = fi->frame + fi->sp_offset + X_SIMM13 (insn);
            }
        }
+       else
+         {
+           /* Check if the PC is in the function prologue before a SAVE
+              instruction has been executed yet.  If so, set the frame
+              to the current value of the stack pointer and set
+              the in_prologue flag.  */
+           CORE_ADDR addr;
+           struct symtab_and_line sal;
+
+           sal = find_pc_line (prologue_start, 0);
+           if (sal.line == 0)                  /* no line info, use PC */
+             prologue_end = fi->pc;
+           else if (sal.end < prologue_end)
+             prologue_end = sal.end;
+           if (fi->pc < prologue_end)
+             {
+               for (addr = prologue_start; addr < fi->pc; addr += 4)
+                 {
+                   insn = read_memory_integer (addr, 4);
+                   if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3c)
+                     break;                    /* SAVE seen, stop searching */
+                 }
+               if (addr >= fi->pc)
+                 {
+                   fi->in_prologue = 1;
+                   fi->frame = read_register (SP_REGNUM);
+                 }
+             }
+         }
     }
   if (fi->next && fi->frame == 0)
     {
@@ -334,15 +359,8 @@ CORE_ADDR
 sparc_extract_struct_value_address (regbuf)
      char regbuf[REGISTER_BYTES];
 {
-#ifdef GDB_TARGET_IS_SPARC64
   return extract_address (regbuf + REGISTER_BYTE (O0_REGNUM),
                          REGISTER_RAW_SIZE (O0_REGNUM));
-#else
-  CORE_ADDR sp = extract_address (&regbuf [REGISTER_BYTE (SP_REGNUM)],
-                                 REGISTER_RAW_SIZE (SP_REGNUM));
-  return read_memory_integer (sp + (16 * SPARC_INTREG_SIZE), 
-                             TARGET_PTR_BIT / TARGET_CHAR_BIT);
-#endif
 }
 
 /* Find the pc saved in frame FRAME.  */
@@ -386,10 +404,11 @@ sparc_frame_saved_pc (frame)
                          scbuf, sizeof (scbuf));
       return extract_address (scbuf, sizeof (scbuf));
     }
-  else if (frame->next != NULL
-          && (frame->next->signal_handler_caller
-              || frame_in_dummy (frame->next))
-          && frameless_look_for_prologue (frame))
+  else if (frame->in_prologue ||
+          (frame->next != NULL
+           && (frame->next->signal_handler_caller
+               || frame_in_dummy (frame->next))
+           && frameless_look_for_prologue (frame)))
     {
       /* A frameless function interrupted by a signal did not save
         the PC, it is still in %o7.  */
@@ -566,7 +585,7 @@ examine_prologue (start_pc, frameless_p, fi, saved_regs)
 }
 
 CORE_ADDR 
-skip_prologue (start_pc, frameless_p)
+sparc_skip_prologue (start_pc, frameless_p)
      CORE_ADDR start_pc;
      int frameless_p;
 {
@@ -654,7 +673,7 @@ isbranch (instruction, addr, target)
    The argument RAW_BUFFER must point to aligned memory.  */
 
 void
-get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
+sparc_get_saved_register (raw_buffer, optimized, addrp, frame, regnum, lval)
      char *raw_buffer;
      int *optimized;
      CORE_ADDR *addrp;
@@ -1776,7 +1795,9 @@ sparc_extract_return_value (type, regbuf, valbuf)
   else
     memcpy (valbuf,
            &regbuf [O0_REGNUM * regsize +
-                    (typelen >= regsize ? 0 : regsize - typelen)],
+                    (typelen >= regsize
+                     || TARGET_BYTE_ORDER == LITTLE_ENDIAN ? 0
+                        : regsize - typelen)],
            typelen);
 }
 
@@ -1816,7 +1837,7 @@ sparc_store_return_value (type, valbuf)
 }
 
 
-/* Insert the function address into a call dummy instsruction sequence
+/* Insert the function address into a call dummy instruction sequence
    stored at DUMMY.
 
    For structs and unions, if the function was compiled with Sun cc,
@@ -1861,6 +1882,21 @@ sparc_fix_call_dummy (dummy, pc, fun, value_type, using_gcc)
        store_unsigned_integer (dummy + (i * 4), 4, 0x01000000);
     }
 #endif
+
+  /* If this is a bi-endian target, GDB has written the call dummy
+     in little-endian order.  We must byte-swap it back to big-endian. */
+  if (bi_endian)
+    {
+      for (i = 0; i < CALL_DUMMY_LENGTH; i += 4)
+       {
+         char tmp = dummy [i];
+         dummy [i] = dummy [i+3];
+         dummy [i+3] = tmp;
+         tmp = dummy [i+1];
+         dummy [i+1] = dummy [i+2];
+         dummy [i+2] = tmp;
+       }
+    }
 }
 
 
@@ -1873,7 +1909,19 @@ sparc_target_architecture_hook (ap)
   int i, j;
 
   if (ap->mach == bfd_mach_sparc_sparclite_le)
-    target_byte_order = LITTLE_ENDIAN;
+    {
+      if (TARGET_BYTE_ORDER_SELECTABLE_P)
+       {
+         target_byte_order = LITTLE_ENDIAN;
+         bi_endian = 1;
+       }
+      else
+       {
+         warning ("This GDB does not support little endian sparclite.");
+       }
+    }
+  else
+    bi_endian = 0;
   return 1;
 }
 
This page took 0.026924 seconds and 4 git commands to generate.