X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fsparc-arch.c;h=a365bb0d512cf5028d809260c148e704bba05aef;hb=b43b6e70ce48d959d77f7f56be9d11aa101fdd7d;hp=850acfd020347b0542afc94860ff334e3244872c;hpb=79cc569a97e444389350ea3f5b1017374fe16bec;p=sbcl.git diff --git a/src/runtime/sparc-arch.c b/src/runtime/sparc-arch.c index 850acfd..a365bb0 100644 --- a/src/runtime/sparc-arch.c +++ b/src/runtime/sparc-arch.c @@ -35,11 +35,11 @@ void arch_init(void) 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. */ @@ -105,30 +105,52 @@ void arch_set_pseudo_atomic_interrupted(os_context_t *context) *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); */ @@ -136,11 +158,11 @@ void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst) /* 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)); } @@ -227,10 +249,11 @@ static void sigill_handler(int signal, siginfo_t *siginfo, void *void_context) 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: @@ -248,7 +271,7 @@ static void sigill_handler(int signal, siginfo_t *siginfo, void *void_context) 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); } @@ -263,7 +286,7 @@ static void sigill_handler(int signal, siginfo_t *siginfo, void *void_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); @@ -271,7 +294,7 @@ static void sigemt_handler(int signal, siginfo_t *siginfo, void *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); @@ -296,6 +319,8 @@ static void sigemt_handler(int signal, siginfo_t *siginfo, void *void_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);