* emultempl/mmixelf.em: Remove incorrect '#line' directive.
[deliverable/binutils-gdb.git] / gdb / spu-tdep.c
index 389c28337e4bcc7380ef71d08c25f0996c514a66..5f584ea482ca656cb38bca2e0fa3406b5d48d20d 100644 (file)
@@ -1,5 +1,5 @@
 /* SPU target-dependent code for GDB, the GNU debugger.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
 
    Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
    Based on a port by Sid Manning <sid@us.ibm.com>.
@@ -478,11 +478,17 @@ spu_analyze_prologue (CORE_ADDR start_pc, CORE_ADDR end_pc,
       else if (is_ri16 (insn, op_il, &rt, &immed))
        {
          reg_immed[rt] = immed;
+
+         if (rt == SPU_RAW_SP_REGNUM && !found_sp)
+           found_sp = 1;
        }
 
       else if (is_ri18 (insn, op_ila, &rt, &immed))
        {
          reg_immed[rt] = immed & 0x3ffff;
+
+         if (rt == SPU_RAW_SP_REGNUM && !found_sp)
+           found_sp = 1;
        }
 
       /* STQD is used to save registers to the stack.  */
@@ -553,6 +559,101 @@ spu_virtual_frame_pointer (CORE_ADDR pc, int *reg, LONGEST *offset)
     }
 }
 
+/* Return true if we are in the function's epilogue, i.e. after the
+   instruction that destroyed the function's stack frame.
+
+   1) scan forward from the point of execution:
+       a) If you find an instruction that modifies the stack pointer
+          or transfers control (except a return), execution is not in
+          an epilogue, return.
+       b) Stop scanning if you find a return instruction or reach the
+          end of the function or reach the hard limit for the size of
+          an epilogue.
+   2) scan backward from the point of execution:
+        a) If you find an instruction that modifies the stack pointer,
+            execution *is* in an epilogue, return.
+        b) Stop scanning if you reach an instruction that transfers
+           control or the beginning of the function or reach the hard
+           limit for the size of an epilogue.  */
+
+static int
+spu_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end;
+  bfd_byte buf[4];
+  unsigned int insn;
+  int rt, ra, rb, rc, immed;
+
+  /* Find the search limits based on function boundaries and hard limit.
+     We assume the epilogue can be up to 64 instructions long.  */
+
+  const int spu_max_epilogue_size = 64 * 4;
+
+  if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
+    return 0;
+
+  if (pc - func_start < spu_max_epilogue_size)
+    epilogue_start = func_start;
+  else
+    epilogue_start = pc - spu_max_epilogue_size;
+
+  if (func_end - pc < spu_max_epilogue_size)
+    epilogue_end = func_end;
+  else
+    epilogue_end = pc + spu_max_epilogue_size;
+
+  /* Scan forward until next 'bi $0'.  */
+
+  for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += 4)
+    {
+      if (target_read_memory (scan_pc, buf, 4))
+       return 0;
+      insn = extract_unsigned_integer (buf, 4);
+
+      if (is_branch (insn, &immed, &ra))
+       {
+         if (immed == 0 && ra == SPU_LR_REGNUM)
+           break;
+
+         return 0;
+       }
+
+      if (is_ri10 (insn, op_ai, &rt, &ra, &immed)
+         || is_rr (insn, op_a, &rt, &ra, &rb)
+         || is_ri10 (insn, op_lqd, &rt, &ra, &immed))
+       {
+         if (rt == SPU_RAW_SP_REGNUM)
+           return 0;
+       }
+    }
+
+  if (scan_pc >= epilogue_end)
+    return 0;
+
+  /* Scan backward until adjustment to stack pointer (R1).  */
+
+  for (scan_pc = pc - 4; scan_pc >= epilogue_start; scan_pc -= 4)
+    {
+      if (target_read_memory (scan_pc, buf, 4))
+       return 0;
+      insn = extract_unsigned_integer (buf, 4);
+
+      if (is_branch (insn, &immed, &ra))
+       return 0;
+
+      if (is_ri10 (insn, op_ai, &rt, &ra, &immed)
+         || is_rr (insn, op_a, &rt, &ra, &rb)
+         || is_ri10 (insn, op_lqd, &rt, &ra, &immed))
+       {
+         if (rt == SPU_RAW_SP_REGNUM)
+           return 1;
+       }
+    }
+
+  return 0;
+}
+
+
 /* Normal stack frames.  */
 
 struct spu_unwind_cache
@@ -581,7 +682,7 @@ spu_frame_unwind_cache (struct frame_info *next_frame,
   info->local_base = 0;
 
   /* Find the start of the current function, and analyze its prologue.  */
-  info->func = frame_func_unwind (next_frame);
+  info->func = frame_func_unwind (next_frame, NORMAL_FRAME);
   if (info->func == 0)
     {
       /* Fall back to using the current PC as frame ID.  */
@@ -720,7 +821,9 @@ static const struct frame_base spu_frame_base = {
 static CORE_ADDR
 spu_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  return frame_unwind_register_unsigned (next_frame, SPU_PC_REGNUM);
+  CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, SPU_PC_REGNUM);
+  /* Mask off interrupt enable bit.  */
+  return pc & -4;
 }
 
 static CORE_ADDR
@@ -729,9 +832,31 @@ spu_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
   return frame_unwind_register_unsigned (next_frame, SPU_SP_REGNUM);
 }
 
+static CORE_ADDR
+spu_read_pc (ptid_t ptid)
+{
+  CORE_ADDR pc = read_register_pid (SPU_PC_REGNUM, ptid);
+  /* Mask off interrupt enable bit.  */
+  return pc & -4;
+}
+
+static void
+spu_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+  /* Keep interrupt enabled state unchanged.  */
+  CORE_ADDR old_pc = read_register_pid (SPU_PC_REGNUM, ptid);
+  write_register_pid (SPU_PC_REGNUM, (pc & -4) | (old_pc & 3), ptid);
+}
+
 
 /* Function calling convention.  */
 
+static CORE_ADDR
+spu_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  return sp & ~15;
+}
+
 static int
 spu_scalar_value_p (struct type *type)
 {
@@ -964,7 +1089,8 @@ spu_software_single_step (enum target_signal signal, int insert_breakpoints_p)
       gdb_byte buf[4];
 
       regcache_cooked_read (current_regcache, SPU_PC_REGNUM, buf);
-      pc = extract_unsigned_integer (buf, 4);
+      /* Mask off interrupt enable bit.  */
+      pc = extract_unsigned_integer (buf, 4) & -4;
 
       if (target_read_memory (pc, buf, 4))
        return;
@@ -974,9 +1100,9 @@ spu_software_single_step (enum target_signal signal, int insert_breakpoints_p)
          instruction is a PPE-assisted call, in which case it is at PC + 8.
          Wrap around LS limit to be on the safe side.  */
       if ((insn & 0xffffff00) == 0x00002100)
-       next_pc = (pc + 8) & (SPU_LS_SIZE - 1) & -4;
+       next_pc = (pc + 8) & (SPU_LS_SIZE - 1);
       else
-       next_pc = (pc + 4) & (SPU_LS_SIZE - 1) & -4;
+       next_pc = (pc + 4) & (SPU_LS_SIZE - 1);
 
       insert_single_step_breakpoint (next_pc);
 
@@ -989,10 +1115,10 @@ spu_software_single_step (enum target_signal signal, int insert_breakpoints_p)
          else if (reg != -1)
            {
              regcache_cooked_read_part (current_regcache, reg, 0, 4, buf);
-             target += extract_unsigned_integer (buf, 4);
+             target += extract_unsigned_integer (buf, 4) & -4;
            }
 
-         target = target & (SPU_LS_SIZE - 1) & -4;
+         target = target & (SPU_LS_SIZE - 1);
          if (target != next_pc)
            insert_single_step_breakpoint (target);
        }
@@ -1029,6 +1155,8 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_num_pseudo_regs (gdbarch, SPU_NUM_PSEUDO_REGS);
   set_gdbarch_sp_regnum (gdbarch, SPU_SP_REGNUM);
   set_gdbarch_pc_regnum (gdbarch, SPU_PC_REGNUM);
+  set_gdbarch_read_pc (gdbarch, spu_read_pc);
+  set_gdbarch_write_pc (gdbarch, spu_write_pc);
   set_gdbarch_register_name (gdbarch, spu_register_name);
   set_gdbarch_register_type (gdbarch, spu_register_type);
   set_gdbarch_pseudo_register_read (gdbarch, spu_pseudo_register_read);
@@ -1047,11 +1175,13 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_float_bit (gdbarch, 32);
   set_gdbarch_double_bit (gdbarch, 64);
   set_gdbarch_long_double_bit (gdbarch, 64);
-  set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
-  set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
-  set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
 
   /* Inferior function calls.  */
+  set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+  set_gdbarch_frame_align (gdbarch, spu_frame_align);
   set_gdbarch_push_dummy_call (gdbarch, spu_push_dummy_call);
   set_gdbarch_unwind_dummy_id (gdbarch, spu_unwind_dummy_id);
   set_gdbarch_return_value (gdbarch, spu_return_value);
@@ -1065,6 +1195,7 @@ spu_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_virtual_frame_pointer (gdbarch, spu_virtual_frame_pointer);
   set_gdbarch_frame_args_skip (gdbarch, 0);
   set_gdbarch_skip_prologue (gdbarch, spu_skip_prologue);
+  set_gdbarch_in_function_epilogue_p (gdbarch, spu_in_function_epilogue_p);
 
   /* Breakpoints.  */
   set_gdbarch_decr_pc_after_break (gdbarch, 4);
This page took 0.026197 seconds and 4 git commands to generate.