* gdbarch.sh (push_dummy_code): Add REGCACHE argument.
[deliverable/binutils-gdb.git] / gdb / sparc-tdep.c
index e3b1ccfd43725a8e21a160847af2f9041ea28433..59d6f9f29a27a9b07e6dd8357f4834007b9806ca 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for SPARC.
 
-   Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -65,7 +65,7 @@ struct regset;
 
 /* The SPARC Floating-Point Quad-Precision format is similar to
    big-endian IA-64 Quad-recision format.  */
-#define floatformat_sparc_quad floatformat_ia64_quad_big
+#define floatformats_sparc_quad floatformats_ia64_quad
 
 /* The stack pointer is offset from the stack frame by a BIAS of 2047
    (0x7ff) for 64-bit code.  BIAS is likely to be defined on SPARC
@@ -82,6 +82,7 @@ struct regset;
 #define X_IMM22(i) ((i) & 0x3fffff)
 #define X_OP3(i) (((i) >> 19) & 0x3f)
 #define X_RS1(i) (((i) >> 14) & 0x1f)
+#define X_RS2(i) ((i) & 0x1f)
 #define X_I(i) (((i) >> 13) & 1)
 /* Sign extension macros.  */
 #define X_DISP22(i) ((X_IMM22 (i) ^ 0x200000) - 0x200000)
@@ -99,7 +100,7 @@ sparc_fetch_instruction (CORE_ADDR pc)
   int i;
 
   /* If we can't read the instruction at PC, return zero.  */
-  if (target_read_memory (pc, buf, sizeof (buf)))
+  if (read_memory_nobpt (pc, buf, sizeof (buf)))
     return 0;
 
   insn = 0;
@@ -158,7 +159,7 @@ sparc_fetch_wcookie (void)
   gdb_byte buf[8];
   int len;
 
-  len = target_read_partial (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
+  len = target_read (ops, TARGET_OBJECT_WCOOKIE, NULL, buf, 0, 8);
   if (len == -1)
     return 0;
 
@@ -169,18 +170,6 @@ sparc_fetch_wcookie (void)
 }
 \f
 
-/* Return the contents if register REGNUM as an address.  */
-
-CORE_ADDR
-sparc_address_from_register (int regnum)
-{
-  ULONGEST addr;
-
-  regcache_cooked_read_unsigned (current_regcache, regnum, &addr);
-  return addr;
-}
-\f
-
 /* The functions on this page are intended to be used to classify
    function arguments.  */
 
@@ -294,6 +283,48 @@ sparc32_register_name (int regnum)
 
   return NULL;
 }
+\f
+
+/* Type for %psr.  */
+struct type *sparc_psr_type;
+
+/* Type for %fsr.  */
+struct type *sparc_fsr_type;
+
+/* Construct types for ISA-specific registers.  */
+
+static void
+sparc_init_types (void)
+{
+  struct type *type;
+
+  type = init_flags_type ("builtin_type_sparc_psr", 4);
+  append_flags_type_flag (type, 5, "ET");
+  append_flags_type_flag (type, 6, "PS");
+  append_flags_type_flag (type, 7, "S");
+  append_flags_type_flag (type, 12, "EF");
+  append_flags_type_flag (type, 13, "EC");
+  sparc_psr_type = type;
+
+  type = init_flags_type ("builtin_type_sparc_fsr", 4);
+  append_flags_type_flag (type, 0, "NXA");
+  append_flags_type_flag (type, 1, "DZA");
+  append_flags_type_flag (type, 2, "UFA");
+  append_flags_type_flag (type, 3, "OFA");
+  append_flags_type_flag (type, 4, "NVA");
+  append_flags_type_flag (type, 5, "NXC");
+  append_flags_type_flag (type, 6, "DZC");
+  append_flags_type_flag (type, 7, "UFC");
+  append_flags_type_flag (type, 8, "OFC");
+  append_flags_type_flag (type, 9, "NVC");
+  append_flags_type_flag (type, 22, "NS");
+  append_flags_type_flag (type, 23, "NXM");
+  append_flags_type_flag (type, 24, "DZM");
+  append_flags_type_flag (type, 25, "UFM");
+  append_flags_type_flag (type, 26, "OFM");
+  append_flags_type_flag (type, 27, "NVM");
+  sparc_fsr_type = type;
+}
 
 /* Return the GDB type object for the "standard" data type of data in
    register REGNUM. */
@@ -313,6 +344,12 @@ sparc32_register_type (struct gdbarch *gdbarch, int regnum)
   if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
     return builtin_type_void_func_ptr;
 
+  if (regnum == SPARC32_PSR_REGNUM)
+    return sparc_psr_type;
+
+  if (regnum == SPARC32_FSR_REGNUM)
+    return sparc_fsr_type;
+
   return builtin_type_int32;
 }
 
@@ -346,7 +383,8 @@ sparc32_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
                         CORE_ADDR funcaddr, int using_gcc,
                         struct value **args, int nargs,
                         struct type *value_type,
-                        CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
+                        CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+                        struct regcache *regcache)
 {
   *bp_addr = sp - 4;
   *real_pc = funcaddr;
@@ -523,6 +561,156 @@ sparc_alloc_frame_cache (void)
   return cache;
 }
 
+/* GCC generates several well-known sequences of instructions at the begining
+   of each function prologue when compiling with -fstack-check.  If one of
+   such sequences starts at START_PC, then return the address of the
+   instruction immediately past this sequence.  Otherwise, return START_PC.  */
+   
+static CORE_ADDR
+sparc_skip_stack_check (const CORE_ADDR start_pc)
+{
+  CORE_ADDR pc = start_pc;
+  unsigned long insn;
+  int offset_stack_checking_sequence = 0;
+
+  /* With GCC, all stack checking sequences begin with the same two
+     instructions.  */
+
+  /* sethi <some immediate>,%g1 */
+  insn = sparc_fetch_instruction (pc);
+  pc = pc + 4;
+  if (!(X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 1))
+    return start_pc;
+
+  /* sub %sp, %g1, %g1 */
+  insn = sparc_fetch_instruction (pc);
+  pc = pc + 4;
+  if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+        && X_RD (insn) == 1 && X_RS1 (insn) == 14 && X_RS2 (insn) == 1))
+    return start_pc;
+
+  insn = sparc_fetch_instruction (pc);
+  pc = pc + 4;
+
+  /* First possible sequence:
+         [first two instructions above]
+         clr [%g1 - some immediate]  */
+
+  /* clr [%g1 - some immediate]  */
+  if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+      && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+    {
+      /* Valid stack-check sequence, return the new PC.  */
+      return pc;
+    }
+
+  /* Second possible sequence: A small number of probes.
+         [first two instructions above]
+         clr [%g1]
+         add   %g1, -<some immediate>, %g1
+         clr [%g1]
+         [repeat the two instructions above any (small) number of times]
+         clr [%g1 - some immediate]  */
+
+  /* clr [%g1] */
+  else if (X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+      && X_RS1 (insn) == 1 && X_RD (insn) == 0)
+    {
+      while (1)
+        {
+          /* add %g1, -<some immediate>, %g1 */
+          insn = sparc_fetch_instruction (pc);
+          pc = pc + 4;
+          if (!(X_OP (insn) == 2  && X_OP3(insn) == 0 && X_I(insn)
+                && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+            break;
+
+          /* clr [%g1] */
+          insn = sparc_fetch_instruction (pc);
+          pc = pc + 4;
+          if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+                && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+            return start_pc;
+        }
+
+      /* clr [%g1 - some immediate] */
+      if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+            && X_RS1 (insn) == 1 && X_RD (insn) == 0))
+        return start_pc;
+
+      /* We found a valid stack-check sequence, return the new PC.  */
+      return pc;
+    }
+  
+  /* Third sequence: A probing loop.
+         [first two instructions above]
+         sethi  <some immediate>, %g4
+         sub  %g1, %g4, %g4
+         cmp  %g1, %g4
+         be  <disp>
+         add  %g1, -<some immediate>, %g1
+         ba  <disp>
+         clr  [%g1]
+         clr [%g4 - some immediate]  */
+
+  /* sethi  <some immediate>, %g4 */
+  else if (X_OP (insn) == 0 && X_OP2 (insn) == 0x4 && X_RD (insn) == 4)
+    {
+      /* sub  %g1, %g4, %g4 */
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+      if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x4 && !X_I(insn)
+            && X_RD (insn) == 4 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+        return start_pc;
+
+      /* cmp  %g1, %g4 */
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+      if (!(X_OP (insn) == 2 && X_OP3 (insn) == 0x14 && !X_I(insn)
+            && X_RD (insn) == 0 && X_RS1 (insn) == 1 && X_RS2 (insn) == 4))
+        return start_pc;
+
+      /* be  <disp> */
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+      if (!(X_OP (insn) == 0 && X_COND (insn) == 0x1))
+        return start_pc;
+
+      /* add  %g1, -<some immediate>, %g1 */
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+      if (!(X_OP (insn) == 2  && X_OP3(insn) == 0 && X_I(insn)
+            && X_RS1 (insn) == 1 && X_RD (insn) == 1))
+        return start_pc;
+
+      /* ba  <disp> */
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+      if (!(X_OP (insn) == 0 && X_COND (insn) == 0x8))
+        return start_pc;
+
+      /* clr  [%g1] */
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+      if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && !X_I(insn)
+            && X_RD (insn) == 0 && X_RS1 (insn) == 1))
+        return start_pc;
+
+      /* clr [%g4 - some immediate]  */
+      insn = sparc_fetch_instruction (pc);
+      pc = pc + 4;
+      if (!(X_OP (insn) == 3 && X_OP3(insn) == 0x4 && X_I(insn)
+            && X_RS1 (insn) == 4 && X_RD (insn) == 0))
+        return start_pc;
+
+      /* We found a valid stack-check sequence, return the new PC.  */
+      return pc;
+    }
+
+  /* No stack check code in our prologue, return the start_pc.  */
+  return start_pc;
+}
+
 CORE_ADDR
 sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
                        struct sparc_frame_cache *cache)
@@ -532,6 +720,8 @@ sparc_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
   int offset = 0;
   int dest = -1;
 
+  pc = sparc_skip_stack_check (pc);
+
   if (current_pc <= pc)
     return current_pc;
 
@@ -651,12 +841,9 @@ sparc_frame_cache (struct frame_info *next_frame, void **this_cache)
   cache = sparc_alloc_frame_cache ();
   *this_cache = cache;
 
-  cache->pc = frame_func_unwind (next_frame);
+  cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
   if (cache->pc != 0)
-    {
-      CORE_ADDR addr_in_block = frame_unwind_address_in_block (next_frame);
-      sparc_analyze_prologue (cache->pc, addr_in_block, cache);
-    }
+    sparc_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
 
   if (cache->frameless_p)
     {
@@ -1006,7 +1193,7 @@ sparc32_stabs_argument_has_addr (struct gdbarch *gdbarch, struct type *type)
 static int
 sparc32_dwarf2_struct_return_p (struct frame_info *next_frame)
 {
-  CORE_ADDR pc = frame_unwind_address_in_block (next_frame);
+  CORE_ADDR pc = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
   struct symbol *sym = find_pc_function (pc);
 
   if (sym)
@@ -1051,7 +1238,7 @@ sparc32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
    software single-step mechanism.  */
 
 static CORE_ADDR
-sparc_analyze_control_transfer (struct gdbarch *arch,
+sparc_analyze_control_transfer (struct frame_info *frame,
                                CORE_ADDR pc, CORE_ADDR *npc)
 {
   unsigned long insn = sparc_fetch_instruction (pc);
@@ -1093,7 +1280,7 @@ sparc_analyze_control_transfer (struct gdbarch *arch,
   else if (X_OP (insn) == 2 && X_OP3 (insn) == 0x3a)
     {
       /* Trap instruction (TRAP).  */
-      return gdbarch_tdep (arch)->step_trap (insn);
+      return gdbarch_tdep (get_frame_arch (frame))->step_trap (frame, insn);
     }
 
   /* FIXME: Handle DONE and RETRY instructions.  */
@@ -1126,46 +1313,38 @@ sparc_analyze_control_transfer (struct gdbarch *arch,
 }
 
 static CORE_ADDR
-sparc_step_trap (unsigned long insn)
+sparc_step_trap (struct frame_info *frame, unsigned long insn)
 {
   return 0;
 }
 
-void
-sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+int
+sparc_software_single_step (struct frame_info *frame)
 {
-  struct gdbarch *arch = current_gdbarch;
+  struct gdbarch *arch = get_frame_arch (frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
-  static CORE_ADDR npc, nnpc;
-  static gdb_byte npc_save[4], nnpc_save[4];
+  CORE_ADDR npc, nnpc;
 
-  if (insert_breakpoints_p)
-    {
-      CORE_ADDR pc, orig_npc;
-
-      pc = sparc_address_from_register (tdep->pc_regnum);
-      orig_npc = npc = sparc_address_from_register (tdep->npc_regnum);
-
-      /* Analyze the instruction at PC.  */
-      nnpc = sparc_analyze_control_transfer (arch, pc, &npc);
-      if (npc != 0)
-       target_insert_breakpoint (npc, npc_save);
-      if (nnpc != 0)
-       target_insert_breakpoint (nnpc, nnpc_save);
-
-      /* Assert that we have set at least one breakpoint, and that
-        they're not set at the same spot - unless we're going
-        from here straight to NULL, i.e. a call or jump to 0.  */
-      gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0);
-      gdb_assert (nnpc != npc || orig_npc == 0);
-    }
-  else
-    {
-      if (npc != 0)
-       target_remove_breakpoint (npc, npc_save);
-      if (nnpc != 0)
-       target_remove_breakpoint (nnpc, nnpc_save);
-    }
+  CORE_ADDR pc, orig_npc;
+
+  pc = get_frame_register_unsigned (frame, tdep->pc_regnum);
+  orig_npc = npc = get_frame_register_unsigned (frame, tdep->npc_regnum);
+
+  /* Analyze the instruction at PC.  */
+  nnpc = sparc_analyze_control_transfer (frame, pc, &npc);
+  if (npc != 0)
+    insert_single_step_breakpoint (npc);
+
+  if (nnpc != 0)
+    insert_single_step_breakpoint (nnpc);
+
+  /* Assert that we have set at least one breakpoint, and that
+     they're not set at the same spot - unless we're going
+     from here straight to NULL, i.e. a call or jump to 0.  */
+  gdb_assert (npc != 0 || nnpc != 0 || orig_npc == 0);
+  gdb_assert (nnpc != npc || orig_npc == 0);
+
+  return 1;
 }
 
 static void
@@ -1253,7 +1432,7 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->step_trap = sparc_step_trap;
 
   set_gdbarch_long_double_bit (gdbarch, 128);
-  set_gdbarch_long_double_format (gdbarch, &floatformat_sparc_quad);
+  set_gdbarch_long_double_format (gdbarch, floatformats_sparc_quad);
 
   set_gdbarch_num_regs (gdbarch, SPARC32_NUM_REGS);
   set_gdbarch_register_name (gdbarch, sparc32_register_name);
@@ -1296,14 +1475,14 @@ sparc32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   frame_base_set_default (gdbarch, &sparc32_frame_base);
 
-  /* Hook in ABI-specific overrides, if they have been registered.  */
-  gdbarch_init_osabi (info, gdbarch);
-
   /* Hook in the DWARF CFI frame unwinder.  */
   dwarf2_frame_set_init_reg (gdbarch, sparc32_dwarf2_frame_init_reg);
   /* FIXME: kettenis/20050423: Don't enable the unwinder until the
      StackGhost issues have been resolved.  */
 
+  /* Hook in ABI-specific overrides, if they have been registered.  */
+  gdbarch_init_osabi (info, gdbarch);
+
   frame_unwind_append_sniffer (gdbarch, sparc32_frame_sniffer);
 
   /* If we have register sets, enable the generic core file support.  */
@@ -1626,4 +1805,7 @@ void
 _initialize_sparc_tdep (void)
 {
   register_gdbarch_init (bfd_arch_sparc, sparc32_gdbarch_init);
+
+  /* Initialize the SPARC-specific register types.  */
+  sparc_init_types();
 }
This page took 0.027824 seconds and 4 git commands to generate.