Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / breakpoint.c
1 /*
2
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.
5
6 */
7
8 #include <stdio.h>
9 #include <signal.h>
10
11 #include "lisp.h"
12 #include "os.h"
13 #include "internals.h"
14 #include "interrupt.h"
15 #include "arch.h"
16 #include "lispregs.h"
17 #include "globals.h"
18 #include "alloc.h"
19 #include "breakpoint.h"
20 #if defined GENCGC
21 #include "gencgc.h"
22 #endif
23
24 /*
25  * See MAKE-BOGUS-LRA in code/debug-int.lisp for these values.
26  *
27  * Ideally, internals.h should have the correct values.  We leave
28  * these defaults here for now.
29  */
30 #ifndef REAL_LRA_SLOT
31 #define REAL_LRA_SLOT 0
32 #endif
33
34 #ifndef KNOWN_RETURN_P_SLOT
35 #ifndef i386
36 #define KNOWN_RETURN_P_SLOT 1
37 #else
38 #define KNOWN_RETURN_P_SLOT 2
39 #endif
40 #endif
41
42 #ifndef BOGUS_LRA_CONSTANTS
43 #ifndef i386
44 #define BOGUS_LRA_CONSTANTS 2
45 #else
46 #define BOGUS_LRA_CONSTANTS 3
47 #endif
48 #endif
49
50
51 static void *
52 compute_pc(lispobj code_obj, int pc_offset)
53 {
54     struct code *code;
55
56     code = (struct code *) PTR(code_obj);
57     return (void *) ((char *) code + HeaderValue(code->header) * sizeof(lispobj)
58                      + pc_offset);
59 }
60
61 unsigned long
62 breakpoint_install(lispobj code_obj, int pc_offset)
63 {
64     return arch_install_breakpoint(compute_pc(code_obj, pc_offset));
65 }
66
67 void
68 breakpoint_remove(lispobj code_obj, int pc_offset, unsigned long orig_inst)
69 {
70     arch_remove_breakpoint(compute_pc(code_obj, pc_offset), orig_inst);
71 }
72
73 void
74 breakpoint_do_displaced_inst(os_context_t * scp, unsigned long orig_inst)
75 {
76 #if !defined(hpux) && !defined(irix) && !defined(i386)
77     undo_fake_foreign_function_call(scp);
78 #endif
79     arch_do_displaced_inst(scp, orig_inst);
80 }
81
82 #if !defined(i386)
83 static lispobj
84 find_code(os_context_t * scp)
85 {
86 #ifdef reg_CODE
87     lispobj code = SC_REG(scp, reg_CODE), header;
88
89     if (LowtagOf(code) != type_OtherPointer)
90         return NIL;
91
92     header = *(lispobj *) (code - type_OtherPointer);
93
94     if (TypeOf(header) == type_CodeHeader)
95         return code;
96     else
97         return code - HeaderValue(header) * sizeof(lispobj);
98 #else
99     return NIL;
100 #endif
101 }
102 #endif
103
104 #if defined(i386)
105 static lispobj
106 find_code(os_context_t * scp)
107 {
108     lispobj *codeptr = component_ptr_from_pc((lispobj *) SC_PC(scp));
109
110     if (codeptr == NULL)
111         return NIL;
112     else
113         return (lispobj) codeptr | type_OtherPointer;
114 }
115 #endif
116
117 #if (defined(DARWIN) && defined(__ppc__)) || (defined(sparc))
118 /*
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.
124  *
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
128  * code.)
129  *
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.
133  */
134 static int
135 compute_offset(os_context_t * scp, lispobj code, boolean function_end)
136 {
137     if (code == NIL)
138         return 0;
139     if (function_end) {
140         /*
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.)
144          *
145          * Then make the offset negative so the caller knows
146          * that the offset is not from the code object.
147          */
148         extern char function_end_breakpoint_trap;
149         extern char function_end_breakpoint_guts;
150         int offset;
151             
152         offset =
153             &function_end_breakpoint_trap -
154             &function_end_breakpoint_guts;
155 #if 0
156         fprintf(stderr, "compute_offset\n");
157         fprintf(stderr, " function end offset  = %d\n", offset);
158 #endif
159         return make_fixnum(-offset);
160     } else {
161         unsigned long code_start;
162         struct code *codeptr = (struct code *) PTR(code);
163         unsigned long pc = SC_PC(scp);
164
165         code_start = (unsigned long) codeptr
166             + HeaderValue(codeptr->header) * sizeof(lispobj);
167 #if 0
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);
172 #endif
173         if (pc < code_start) {
174             return 0;
175         } else {
176             int offset = pc - code_start;
177
178 #if 0
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);
182 #endif
183             if (offset >= codeptr->code_size) {
184                 return 0;
185             } else {
186                 return make_fixnum(offset);
187             }
188         }
189     }
190 }
191 #else
192 static int
193 compute_offset(os_context_t * scp, lispobj code, boolean function_end)
194 {
195     if (code == NIL)
196         return 0;
197     else {
198         unsigned long code_start;
199         struct code *codeptr = (struct code *) PTR(code);
200
201 #ifdef parisc
202         unsigned long pc = SC_PC(scp) & ~3;
203 #else
204         unsigned long pc = SC_PC(scp);
205 #endif
206
207         code_start = (unsigned long) codeptr
208             + HeaderValue(codeptr->header) * sizeof(lispobj);
209         if (pc < code_start)
210             return 0;
211         else {
212             int offset = pc - code_start;
213
214             if (offset >= codeptr->code_size) {
215                 return 0;
216             } else {
217                 return make_fixnum(offset);
218             }
219         }
220     }
221 }
222 #endif
223
224 #ifndef i386
225 void
226 handle_breakpoint(int signal, int subcode, os_context_t * scp)
227 {
228     lispobj code;
229
230     fake_foreign_function_call(scp);
231
232     code = find_code(scp);
233
234 #if 0
235     fprintf(stderr, "handle_breakpoint\n");
236     fprintf(stderr, " offset = %d\n", compute_offset(scp, code, 0));
237 #endif    
238     funcall3(SymbolFunction(HANDLE_BREAKPOINT),
239              compute_offset(scp, code, 0), code, alloc_sap(scp));
240
241     undo_fake_foreign_function_call(scp);
242 }
243 #else
244 void
245 handle_breakpoint(int signal, int subcode, os_context_t * scp)
246 {
247     lispobj code, scp_sap = alloc_sap(scp);
248
249     fake_foreign_function_call(scp);
250
251     code = find_code(scp);
252
253     /*
254      * Don't disallow recursive breakpoint traps.  Otherwise, we can't
255      * use debugger breakpoints anywhere in here.
256      */
257
258     sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
259     funcall3(SymbolFunction(HANDLE_BREAKPOINT),
260              compute_offset(scp, code, 0), code, scp_sap);
261
262     undo_fake_foreign_function_call(scp);
263 }
264 #endif
265
266 #ifndef i386
267 void *
268 handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
269 {
270     lispobj code, lra;
271     struct code *codeptr;
272     int offset;
273     int known_return_p;
274     
275     fake_foreign_function_call(scp);
276
277     code = find_code(scp);
278     codeptr = (struct code *) PTR(code);
279     offset = compute_offset(scp, code, 1);
280 #if 0
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));
285     fflush(stdout);
286 #endif
287
288     if (offset < 0) {
289         /*
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
294          * thing.
295          */
296         unsigned int pc;
297
298         pc = SC_PC(scp);
299
300         offset = -offset;
301         /*
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
306          * debug-int.lisp
307          */
308         code = pc - fixnum_value(offset);
309         code -= sizeof(struct code) + BOGUS_LRA_CONSTANTS * sizeof(lispobj);
310
311         code += type_OtherPointer;
312         codeptr = (struct code *) PTR(code);
313 #if 0
314         printf("  pc   = 0x%08x\n", pc);
315         printf("  code    = 0x%08x\n", code);
316         printf("  codeptr = %p\n", codeptr);
317         fflush(stdout);
318 #endif
319     }
320
321     lra = codeptr->constants[REAL_LRA_SLOT];
322
323     known_return_p = codeptr->constants[KNOWN_RETURN_P_SLOT] != NIL;
324     
325     {
326         lispobj *args = current_control_stack_pointer;
327
328         /*
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.
334          */
335         current_control_stack_pointer += 1;
336         args[0] = lra;
337
338         funcall3(SymbolFunction(HANDLE_BREAKPOINT), offset, code, alloc_sap(scp));
339
340         /*
341          * Breakpoint handling done.  Get the (possibly changed) LRA
342          * value off the stack so we know where to return to.
343          */
344         lra = args[0];
345         current_control_stack_pointer -= 1;
346
347 #ifdef reg_CODE 
348         /*
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.
352          */
353         if (!known_return_p) {
354             SC_REG(scp, reg_CODE) = lra;
355         }
356 #endif
357     }
358
359     undo_fake_foreign_function_call(scp);
360     return (void *) (lra - type_OtherPointer + sizeof(lispobj));
361 }
362 #else
363 void *
364 handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
365 {
366     lispobj code, scp_sap = alloc_sap(scp);
367     struct code *codeptr;
368
369     fake_foreign_function_call(scp);
370
371     code = find_code(scp);
372     codeptr = (struct code *) PTR(code);
373
374     /*
375      * Don't disallow recursive breakpoint traps.  Otherwise, we can't
376      * use debugger breakpoints anywhere in here.
377      */
378
379     sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
380     funcall3(SymbolFunction(HANDLE_BREAKPOINT),
381              compute_offset(scp, code, 1), code, scp_sap);
382
383     undo_fake_foreign_function_call(scp);
384
385     return compute_pc(codeptr->constants[REAL_LRA_SLOT],
386                       fixnum_value(codeptr->constants[REAL_LRA_SLOT + 1]));
387 }
388 #endif