/* 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>.
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. */
}
}
+/* 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
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. */
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
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)
{
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;
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);
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);
}
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);
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);
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);