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.
13 #include "internals.h"
14 #include "interrupt.h"
19 #include "breakpoint.h"
25 * See MAKE-BOGUS-LRA in code/debug-int.lisp for these values.
27 * Ideally, internals.h should have the correct values. We leave
28 * these defaults here for now.
31 #define REAL_LRA_SLOT 0
34 #ifndef KNOWN_RETURN_P_SLOT
36 #define KNOWN_RETURN_P_SLOT 1
38 #define KNOWN_RETURN_P_SLOT 2
42 #ifndef BOGUS_LRA_CONSTANTS
44 #define BOGUS_LRA_CONSTANTS 2
46 #define BOGUS_LRA_CONSTANTS 3
52 compute_pc(lispobj code_obj, int pc_offset)
56 code = (struct code *) PTR(code_obj);
57 return (void *) ((char *) code + HeaderValue(code->header) * sizeof(lispobj)
62 breakpoint_install(lispobj code_obj, int pc_offset)
64 return arch_install_breakpoint(compute_pc(code_obj, pc_offset));
68 breakpoint_remove(lispobj code_obj, int pc_offset, unsigned long orig_inst)
70 arch_remove_breakpoint(compute_pc(code_obj, pc_offset), orig_inst);
74 breakpoint_do_displaced_inst(os_context_t * scp, unsigned long orig_inst)
76 #if !defined(hpux) && !defined(irix) && !defined(i386)
77 undo_fake_foreign_function_call(scp);
79 arch_do_displaced_inst(scp, orig_inst);
84 find_code(os_context_t * scp)
87 lispobj code = SC_REG(scp, reg_CODE), header;
89 if (LowtagOf(code) != type_OtherPointer)
92 header = *(lispobj *) (code - type_OtherPointer);
94 if (TypeOf(header) == type_CodeHeader)
97 return code - HeaderValue(header) * sizeof(lispobj);
106 find_code(os_context_t * scp)
108 lispobj *codeptr = component_ptr_from_pc((lispobj *) SC_PC(scp));
113 return (lispobj) codeptr | type_OtherPointer;
117 #if (defined(DARWIN) && defined(__ppc__)) || (defined(sparc))
119 * During a function-end-breakpoint, the pc is sometimes less than the
120 * code address, which bypasses the function end stuff. Then the
121 * offset is zero for a function-end-breakpoint, and we can't find the
122 * breakpoint data, causing an error during tracing. But we know this
123 * is a function-end breakpoint, because function_end is set to true.
125 * (This condition of pc < code address seems to occur only if a GC
126 * happens during tracing. I guess the function-end code object
127 * sometimes gets moved to a lower address than the corresponding
130 * Hence this replacement looks at the function end flag first
131 * to see if it is a function-end breakpoint and does the function-end
132 * stuff anyway. If not, we do the normal stuff.
135 compute_offset(os_context_t * scp, lispobj code, boolean function_end)
141 * We're in a function end breakpoint. Compute the
142 * offset from the (known) breakpoint location and the
143 * beginning of the breakpoint guts. (See *-assem.S.)
145 * Then make the offset negative so the caller knows
146 * that the offset is not from the code object.
148 extern char function_end_breakpoint_trap;
149 extern char function_end_breakpoint_guts;
153 &function_end_breakpoint_trap -
154 &function_end_breakpoint_guts;
156 fprintf(stderr, "compute_offset\n");
157 fprintf(stderr, " function end offset = %d\n", offset);
159 return make_fixnum(-offset);
161 unsigned long code_start;
162 struct code *codeptr = (struct code *) PTR(code);
163 unsigned long pc = SC_PC(scp);
165 code_start = (unsigned long) codeptr
166 + HeaderValue(codeptr->header) * sizeof(lispobj);
168 fprintf(stderr, "compute_offset\n");
169 fprintf(stderr, " pc = %d\n", pc);
170 fprintf(stderr, " code_start = %d\n", code_start);
171 fprintf(stderr, " function_end = %d\n", function_end);
173 if (pc < code_start) {
176 int offset = pc - code_start;
179 fprintf(stderr, " offset = %d\n", offset);
180 fprintf(stderr, " codeptr->code_size = %d\n", codeptr->code_size);
181 fprintf(stderr, " function_end = %d\n", function_end);
183 if (offset >= codeptr->code_size) {
186 return make_fixnum(offset);
193 compute_offset(os_context_t * scp, lispobj code, boolean function_end)
198 unsigned long code_start;
199 struct code *codeptr = (struct code *) PTR(code);
202 unsigned long pc = SC_PC(scp) & ~3;
204 unsigned long pc = SC_PC(scp);
207 code_start = (unsigned long) codeptr
208 + HeaderValue(codeptr->header) * sizeof(lispobj);
212 int offset = pc - code_start;
214 if (offset >= codeptr->code_size) {
217 return make_fixnum(offset);
226 handle_breakpoint(int signal, int subcode, os_context_t * scp)
230 fake_foreign_function_call(scp);
232 code = find_code(scp);
235 fprintf(stderr, "handle_breakpoint\n");
236 fprintf(stderr, " offset = %d\n", compute_offset(scp, code, 0));
238 funcall3(SymbolFunction(HANDLE_BREAKPOINT),
239 compute_offset(scp, code, 0), code, alloc_sap(scp));
241 undo_fake_foreign_function_call(scp);
245 handle_breakpoint(int signal, int subcode, os_context_t * scp)
247 lispobj code, scp_sap = alloc_sap(scp);
249 fake_foreign_function_call(scp);
251 code = find_code(scp);
254 * Don't disallow recursive breakpoint traps. Otherwise, we can't
255 * use debugger breakpoints anywhere in here.
258 sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
259 funcall3(SymbolFunction(HANDLE_BREAKPOINT),
260 compute_offset(scp, code, 0), code, scp_sap);
262 undo_fake_foreign_function_call(scp);
268 handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
271 struct code *codeptr;
275 fake_foreign_function_call(scp);
277 code = find_code(scp);
278 codeptr = (struct code *) PTR(code);
279 offset = compute_offset(scp, code, 1);
281 printf("handle_function_end:\n");
282 printf(" code = 0x%08x\n", code);
283 printf(" codeptr = %p\n", codeptr);
284 printf(" offset = %d\n", fixnum_value(offset));
290 * We were in the function end breakpoint. Which means we are
291 * in a bogus LRA, so compute where the code-component of this
292 * bogus lra object starts. Adjust code, and codeptr
293 * appropriately so the breakpoint handler can do the right
302 * Some magic here. pc points to the trap instruction. The
303 * offset gives us where the function_end_breakpoint_guts
304 * begins. But we need to back up some more to get to the
305 * code-component object. See MAKE-BOGUS-LRA in
308 code = pc - fixnum_value(offset);
309 code -= sizeof(struct code) + BOGUS_LRA_CONSTANTS * sizeof(lispobj);
311 code += type_OtherPointer;
312 codeptr = (struct code *) PTR(code);
314 printf(" pc = 0x%08x\n", pc);
315 printf(" code = 0x%08x\n", code);
316 printf(" codeptr = %p\n", codeptr);
321 lra = codeptr->constants[REAL_LRA_SLOT];
323 known_return_p = codeptr->constants[KNOWN_RETURN_P_SLOT] != NIL;
326 lispobj *args = current_control_stack_pointer;
329 * Because HANDLE_BREAKPOINT can GC, the LRA could move, and
330 * we need to know where it went so we can return to the
331 * correct place. We do this by saving the LRA on the Lisp
332 * stack. If GC moves the LRA, the stack entry will get
333 * updated appropriately too.
335 current_control_stack_pointer += 1;
338 funcall3(SymbolFunction(HANDLE_BREAKPOINT), offset, code, alloc_sap(scp));
341 * Breakpoint handling done. Get the (possibly changed) LRA
342 * value off the stack so we know where to return to.
345 current_control_stack_pointer -= 1;
349 * With the known-return convention, we definitely do NOT want
350 * to mangle the CODE register because it isn't pointing to
351 * the bogus LRA but to the actual routine.
353 if (!known_return_p) {
354 SC_REG(scp, reg_CODE) = lra;
359 undo_fake_foreign_function_call(scp);
360 return (void *) (lra - type_OtherPointer + sizeof(lispobj));
364 handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
366 lispobj code, scp_sap = alloc_sap(scp);
367 struct code *codeptr;
369 fake_foreign_function_call(scp);
371 code = find_code(scp);
372 codeptr = (struct code *) PTR(code);
375 * Don't disallow recursive breakpoint traps. Otherwise, we can't
376 * use debugger breakpoints anywhere in here.
379 sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
380 funcall3(SymbolFunction(HANDLE_BREAKPOINT),
381 compute_offset(scp, code, 1), code, scp_sap);
383 undo_fake_foreign_function_call(scp);
385 return compute_pc(codeptr->constants[REAL_LRA_SLOT],
386 fixnum_value(codeptr->constants[REAL_LRA_SLOT + 1]));