3 This code was written as part of the CMU Common Lisp project at
4 Carnegie Mellon University, and has been placed in the public domain.
15 #include "internals.h"
20 #include "interrupt.h"
22 #include "breakpoint.h"
24 extern char call_into_lisp_LRA[], call_into_lisp_end[];
26 #define BREAKPOINT_INST 0
31 if (mmap((os_vm_address_t) call_into_lisp_LRA_page, OS_VM_DEFAULT_PAGESIZE,
32 OS_VM_PROT_ALL, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0)
33 == (os_vm_address_t) - 1)
35 memcpy(call_into_lisp_LRA_page, call_into_lisp_LRA, OS_VM_DEFAULT_PAGESIZE);
36 os_flush_icache((os_vm_address_t) call_into_lisp_LRA_page,
37 OS_VM_DEFAULT_PAGESIZE);
42 arch_get_bad_addr(int sig, int code, struct sigcontext * scp)
46 if ((scp->sc_pc & 3) != 0)
49 if ((scp->sc_pc < READ_ONLY_SPACE_START ||
50 scp->sc_pc >= READ_ONLY_SPACE_START + READ_ONLY_SPACE_SIZE) &&
51 ((lispobj *) scp->sc_pc < current_dynamic_space ||
52 (lispobj *) scp->sc_pc >= current_dynamic_space + dynamic_space_size))
55 badinst = *(unsigned int *) scp->sc_pc;
57 if (((badinst >> 27) != 0x16) /* STL or STQ */
58 &&((badinst >> 27) != 0x13)) /* STS or STT */
59 return NULL; /* Otherwise forget about address */
61 return (os_vm_address_t) (scp->sc_regs[(badinst >> 16) & 0x1f] +
66 arch_skip_instruction(scp)
67 struct sigcontext *scp;
73 arch_internal_error_arguments(struct sigcontext *scp)
75 return (unsigned char *) (scp->sc_pc + 4);
79 arch_pseudo_atomic_atomic(struct sigcontext *scp)
81 return (scp->sc_regs[reg_ALLOC] & 1);
85 arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
88 scp->sc_regs[reg_ALLOC] |= (1 << 63);
90 scp->sc_regs[reg_ALLOC] |= 2;
95 arch_install_breakpoint(void *pc)
97 unsigned int *ptr = (unsigned int *) pc;
98 unsigned long result = (unsigned long) *ptr;
100 *ptr = BREAKPOINT_INST;
102 os_flush_icache((os_vm_address_t) ptr, sizeof(unsigned long));
108 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
110 unsigned int *ptr = (unsigned int) pc;
113 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
116 static unsigned int *skipped_break_addr, displaced_after_inst, after_breakpoint;
118 static sigset_t orig_sigmask;
121 emulate_branch(struct sigcontext *scp, unsigned long orig_inst)
123 int op = orig_inst >> 26;
124 int reg_a = (orig_inst >> 21) & 0x1f;
125 int reg_b = (orig_inst >> 16) & 0x1f;
126 int fn = orig_inst & 0xffff;
129 (orig_inst & (1 << 20)) ? orig_inst | (-1 << 21) : orig_inst & 0x1fffff;
130 int next_pc = scp->sc_pc;
134 case 0x1a: /* jmp, jsr, jsr_coroutine, ret */
135 scp->sc_regs[reg_a] = scp->sc_pc;
136 scp->sc_pc = scp->sc_regs[reg_b] & ~3;
139 scp->sc_regs[reg_a] = scp->sc_pc;
142 case 0x31: /* fbeq */
143 if (scp->sc_fpregs[reg_a] == 0)
146 case 0x32: /* fblt */
147 if (scp->sc_fpregs[reg_a] < 0)
150 case 0x33: /* fble */
151 if (scp->sc_fpregs[reg_a] <= 0)
155 scp->sc_regs[reg_a] = scp->sc_pc;
158 case 0x35: /* fbne */
159 if (scp->sc_regs[reg_a] != 0)
162 case 0x36: /* fbge */
163 if (scp->sc_fpregs[reg_a] >= 0)
166 case 0x37: /* fbgt */
167 if (scp->sc_fpregs[reg_a] > 0)
170 case 0x38: /* blbc */
171 if ((scp->sc_regs[reg_a] & 1) == 0)
175 if (scp->sc_regs[reg_a] == 0)
179 if (scp->sc_regs[reg_a] < 0)
183 if (scp->sc_regs[reg_a] <= 0)
186 case 0x3c: /* blbs */
187 if ((scp->sc_regs[reg_a] & 1) != 0)
191 if (scp->sc_regs[reg_a] != 0)
195 if (scp->sc_regs[reg_a] >= 0)
199 if (scp->sc_regs[reg_a] > 0)
209 arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
211 unsigned int *pc = scp->sc_pc;
212 unsigned int *next_pc;
213 unsigned int next_inst;
214 int op = orig_inst >> 26;;
216 #if !defined(__linux__) || (defined(__linux__) && (__GNU_LIBRARY__ < 6))
217 orig_sigmask = context->uc_sigmask;
218 FILLBLOCKSET(&context->uc_sigmask);
224 orig_sigmask.__val[0] = scp->uc_sigmask;
225 temp.__val[0] = scp->uc_sigmask;
228 scp->uc_sigmask = temp.__val[0];
232 /* Figure out where the displaced inst is going */
233 if (op == 0x1a || op & 0xf == 0x30) /* branch...ugh */
234 next_pc = (unsigned int *) emulate_branch(scp, orig_inst);
238 /* Put the original instruction back. */
240 os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
242 skipped_break_addr = pc;
244 /* set the after breakpoint */
245 displaced_after_inst = *next_pc;
246 *next_pc = BREAKPOINT_INST;
247 after_breakpoint = 1;
248 os_flush_icache((os_vm_address_t) next_pc, sizeof(unsigned long));
253 #define AfterBreakpoint 100
256 sigtrap_handler(int signal, int code, struct sigcontext *scp)
258 /* Don't disallow recursive breakpoint traps. Otherwise, we can't */
259 /* use debugger breakpoints anywhere in here. */
260 sigsetmask(scp->sc_mask);
262 if (*(unsigned int *) (scp->sc_pc - 4) == BREAKPOINT_INST) {
263 if (after_breakpoint)
264 code = AfterBreakpoint;
266 code = trap_Breakpoint;
268 code = *(u32 *) scp->sc_pc;
271 case trap_PendingInterrupt:
272 arch_skip_instruction(scp);
273 interrupt_handle_pending(scp);
277 fake_foreign_function_call(scp);
278 lose("%%primitive halt called; the party is over.\n");
282 interrupt_internal_error(signal, code, scp, code == trap_Cerror);
285 case trap_Breakpoint:
287 handle_breakpoint(signal, code, scp);
290 case trap_FunctionEndBreakpoint:
292 scp->sc_pc = (int) handle_function_end_breakpoint(signal, code, scp);
295 case AfterBreakpoint:
297 *skipped_break_addr = BREAKPOINT_INST;
298 os_flush_icache((os_vm_address_t) skipped_break_addr,
300 sizeof(unsigned long));
301 skipped_break_addr = NULL;
302 *(unsigned int *) scp->sc_pc = displaced_after_inst;
303 os_flush_icache((os_vm_address_t) scp->sc_pc, sizeof(unsigned long));
305 #if !defined(__linux__) || (defined(__linux__) && (__GNU_LIBRARY__ < 6))
306 scp->sc_mask = orig_sigmask;
308 scp->sc_mask = orig_sigmask.__val[0];
310 after_breakpoint = NULL;
314 interrupt_handle_now(signal, code, scp);
320 sigfpe_handler(int signal, int code, struct sigcontext *scp)
325 arch_install_interrupt_handlers(void)
327 interrupt_install_low_level_handler(SIGILL, sigtrap_handler);
328 interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
329 interrupt_install_low_level_handler(SIGFPE, sigfpe_handler);
332 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
335 funcall0(lispobj function)
337 lispobj *args = current_control_stack_pointer;
339 return call_into_lisp(function, args, 0);
343 funcall1(lispobj function, lispobj arg0)
345 lispobj *args = current_control_stack_pointer;
347 current_control_stack_pointer += 1;
350 return call_into_lisp(function, args, 1);
354 funcall2(lispobj function, lispobj arg0, lispobj arg1)
356 lispobj *args = current_control_stack_pointer;
358 current_control_stack_pointer += 2;
362 return call_into_lisp(function, args, 2);
366 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
368 lispobj *args = current_control_stack_pointer;
370 current_control_stack_pointer += 3;
375 return call_into_lisp(function, args, 3);
379 /* This is apparently called by emulate_branch, but isn't defined. So */
380 /* just do nothing and hope it works... */