*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / sparc-tdep.c
index 797e2400536fe90792e02e1650d31e9b144f55b2..0e2a496a20b52f38c91bc89e5d85aeadb7f53ece 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;
 
@@ -294,6 +295,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 +356,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;
 }
 
@@ -523,6 +572,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 +731,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 +852,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 +1204,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)
@@ -1131,36 +1329,33 @@ sparc_step_trap (unsigned long insn)
   return 0;
 }
 
-void
-sparc_software_single_step (enum target_signal sig, int insert_breakpoints_p)
+int
+sparc_software_single_step (struct regcache *regcache)
 {
   struct gdbarch *arch = current_gdbarch;
   struct gdbarch_tdep *tdep = gdbarch_tdep (arch);
   CORE_ADDR npc, nnpc;
 
-  if (insert_breakpoints_p)
-    {
-      CORE_ADDR pc, orig_npc;
+  CORE_ADDR pc, orig_npc;
 
-      pc = sparc_address_from_register (tdep->pc_regnum);
-      orig_npc = npc = sparc_address_from_register (tdep->npc_regnum);
+  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)
-       insert_single_step_breakpoint (npc);
+  /* Analyze the instruction at PC.  */
+  nnpc = sparc_analyze_control_transfer (arch, pc, &npc);
+  if (npc != 0)
+    insert_single_step_breakpoint (npc);
 
-      if (nnpc != 0)
-       insert_single_step_breakpoint (nnpc);
+  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);
-    }
-  else
-    remove_single_step_breakpoints ();
+  /* 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
@@ -1248,7 +1443,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);
@@ -1621,4 +1816,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.029072 seconds and 4 git commands to generate.