os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
{
- unsigned long badinst;
- unsigned long *pc;
+ unsigned int badinst;
+ unsigned int *pc;
int rs1;
- pc = (unsigned long *)(*os_context_pc_addr(context));
+ pc = (unsigned int *)(*os_context_pc_addr(context));
/* On the sparc, we have to decode the instruction. */
if ((pc < READ_ONLY_SPACE_START ||
pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) &&
(pc < current_dynamic_space ||
- pc >= current_dynamic_space + DYNAMIC_SPACE_SIZE)) {
+ pc >= current_dynamic_space + dynamic_space_size)) {
return NULL;
}
*os_context_register_addr(context,reg_ALLOC) |= 1;
}
-unsigned long arch_install_breakpoint(void *pc)
+void arch_clear_pseudo_atomic_interrupted(os_context_t *context)
{
- unsigned long *ptr = (unsigned long *)pc;
- unsigned long result = *ptr;
+ *os_context_register_addr(context,reg_ALLOC) &= ~1;
+}
+
+unsigned int arch_install_breakpoint(void *pc)
+{
+ unsigned int *ptr = (unsigned int *)pc;
+ unsigned int result = *ptr;
*ptr = trap_Breakpoint;
- os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+ os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
return result;
}
-void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
+void arch_remove_breakpoint(void *pc, unsigned int orig_inst)
{
- *(unsigned long *)pc = orig_inst;
- os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+ *(unsigned int *)pc = orig_inst;
+ os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
}
-static unsigned long *skipped_break_addr, displaced_after_inst;
+/*
+ * Perform the instruction that we overwrote with a breakpoint. As we
+ * don't have a single-step facility, this means we have to:
+ * - put the instruction back
+ * - put a second breakpoint at the following instruction,
+ * set after_breakpoint and continue execution.
+ *
+ * When the second breakpoint is hit (very shortly thereafter, we hope)
+ * sigtrap_handler gets called again, but follows the AfterBreakpoint
+ * arm, which
+ * - puts a bpt back in the first breakpoint place (running across a
+ * breakpoint shouldn't cause it to be uninstalled)
+ * - replaces the second bpt with the instruction it was meant to be
+ * - carries on
+ *
+ * Clear?
+ */
+static unsigned int *skipped_break_addr, displaced_after_inst;
static sigset_t orig_sigmask;
void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
{
- unsigned long *pc = (unsigned long *)(*os_context_pc_addr(context));
- unsigned long *npc = (unsigned long *)(*os_context_npc_addr(context));
+ unsigned int *pc = (unsigned int *)(*os_context_pc_addr(context));
+ unsigned int *npc = (unsigned int *)(*os_context_npc_addr(context));
/* orig_sigmask = context->sigmask;
sigemptyset(&context->sigmask); */
/* FILLBLOCKSET(&context->uc_sigmask);*/
*pc = orig_inst;
- os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+ os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
skipped_break_addr = pc;
displaced_after_inst = *npc;
*npc = trap_AfterBreakpoint;
- os_flush_icache((os_vm_address_t) npc, sizeof(unsigned long));
+ os_flush_icache((os_vm_address_t) npc, sizeof(unsigned int));
}
case trap_AfterBreakpoint:
*skipped_break_addr = trap_Breakpoint;
+ os_flush_icache(skipped_break_addr, sizeof(unsigned int));
skipped_break_addr = NULL;
*(unsigned long *) os_context_pc_addr(context) = displaced_after_inst;
/* context->sigmask = orig_sigmask; */
- os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned long));
+ os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned int));
break;
default:
to fixup up alloc-tn to remove the interrupted flag,
skip over the trap instruction, and then handle the
pending interrupt(s). */
- *os_context_register_addr(context, reg_ALLOC) &= ~7;
+ arch_clear_pseudo_atomic_interrupted(context);
arch_skip_instruction(context);
interrupt_handle_pending(context);
}
static void sigemt_handler(int signal, siginfo_t *siginfo, void *void_context)
{
- unsigned long badinst;
+ unsigned int badinst;
boolean subtract, immed;
int rd, rs1, op1, rs2, op2, result;
os_context_t *context = arch_os_get_context(&void_context);
os_restore_fp_control(context);
#endif
- badinst = *(unsigned long *)os_context_pc_addr(context);
+ badinst = *(unsigned int *)os_context_pc_addr(context);
if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
/* It wasn't a tagged add. Pass the signal into lisp. */
interrupt_handle_now(signal, siginfo, context);
result = op1 - op2;
else
result = op1 + op2;
+ /* KLUDGE: this & ~7 is a little bit magical but basically
+ clears pseudo_atomic bits if any */
*os_context_register_addr(context, reg_ALLOC) = result & ~7;
arch_skip_instruction(context);
interrupt_handle_pending(context);