/[cmucl]/src/lisp/breakpoint.c
ViewVC logotype

Contents of /src/lisp/breakpoint.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.21 - (show annotations)
Thu Sep 4 22:31:47 2008 UTC (5 years, 7 months ago) by rtoy
Branch: MAIN
Changes since 1.20: +90 -1 lines
File MIME type: text/plain
A fix for the error that causes di::handle-breakpoint to complain
about an unknown breakpoint at offset 0 when handling a function-end
breakpoint.

See the comment for compute_offset for an explanation.

Note that this seems to fix that issue, but there is still the issue
where a segfault will happen during tracing.  It seems to happen if a
GC occurs after the function end breakpoint has happened
(compute_offset has already been called before GC happens), and trace
has printed out the return value.  Then a segfault happens.

Due to some issues, this fix only works when compiled with gcc.
Compiling with Sun c produces some segfaults somewhere such that we
can't build cmucl at all.  The bizarre part is that compute_offset is
never called during a build because there are no breakpoints enabled
during a normal build.
1 /*
2
3 $Header: /tiger/var/lib/cvsroots/cmucl/src/lisp/breakpoint.c,v 1.21 2008/09/04 22:31:47 rtoy Exp $
4
5 This code was written as part of the CMU Common Lisp project at
6 Carnegie Mellon University, and has been placed in the public domain.
7
8 */
9
10 #include <stdio.h>
11 #include <signal.h>
12
13 #include "lisp.h"
14 #include "os.h"
15 #include "internals.h"
16 #include "interrupt.h"
17 #include "arch.h"
18 #include "lispregs.h"
19 #include "globals.h"
20 #include "alloc.h"
21 #include "breakpoint.h"
22 #if defined GENCGC
23 #include "gencgc.h"
24 #endif
25
26 /*
27 * See MAKE-BOGUS-LRA in code/debug-int.lisp for these values. (We
28 * really should generate these from the Lisp code.)
29 */
30 #define REAL_LRA_SLOT 0
31 #ifndef i386
32 #define KNOWN_RETURN_P_SLOT 1
33 #define BOGUS_LRA_CONSTANTS 2
34 #else
35 #define KNOWN_RETURN_P_SLOT 2
36 #define BOGUS_LRA_CONSTANTS 3
37 #endif
38
39 static void *
40 compute_pc(lispobj code_obj, int pc_offset)
41 {
42 struct code *code;
43
44 code = (struct code *) PTR(code_obj);
45 return (void *) ((char *) code + HeaderValue(code->header) * sizeof(lispobj)
46 + pc_offset);
47 }
48
49 unsigned long
50 breakpoint_install(lispobj code_obj, int pc_offset)
51 {
52 return arch_install_breakpoint(compute_pc(code_obj, pc_offset));
53 }
54
55 void
56 breakpoint_remove(lispobj code_obj, int pc_offset, unsigned long orig_inst)
57 {
58 arch_remove_breakpoint(compute_pc(code_obj, pc_offset), orig_inst);
59 }
60
61 void
62 breakpoint_do_displaced_inst(os_context_t * scp, unsigned long orig_inst)
63 {
64 #if !defined(hpux) && !defined(irix) && !defined(i386)
65 undo_fake_foreign_function_call(scp);
66 #endif
67 arch_do_displaced_inst(scp, orig_inst);
68 }
69
70 #if !defined(i386)
71 static lispobj
72 find_code(os_context_t * scp)
73 {
74 #ifdef reg_CODE
75 lispobj code = SC_REG(scp, reg_CODE), header;
76
77 if (LowtagOf(code) != type_OtherPointer)
78 return NIL;
79
80 header = *(lispobj *) (code - type_OtherPointer);
81
82 if (TypeOf(header) == type_CodeHeader)
83 return code;
84 else
85 return code - HeaderValue(header) * sizeof(lispobj);
86 #else
87 return NIL;
88 #endif
89 }
90 #endif
91
92 #if defined(i386)
93 static lispobj
94 find_code(os_context_t * scp)
95 {
96 lispobj *codeptr = component_ptr_from_pc((lispobj *) SC_PC(scp));
97
98 if (codeptr == NULL)
99 return NIL;
100 else
101 return (lispobj) codeptr | type_OtherPointer;
102 }
103 #endif
104
105 #if defined(sparc) && defined(__GNUC__)
106 /*
107 * For some unknown reason, if you compile this code with Sun C, CMUCL
108 * is unable to build itself anymore. This is bizarre because this
109 * code is not called during a build since there are no breakpoints
110 * during a build.
111 *
112 * Hence, until this is figured out, we can't use this code with Sun
113 * C. This also means we some known issues with tracing will manifest
114 * itself.
115 *
116 * During a function-end-breakpoint, the pc is sometimes less than the
117 * code address, which bypasses the function end stuff. Then the
118 * offset is zero for a function-end-breakpoint, and we can't find the
119 * breakpoint data, causing an error during tracing. But we know this
120 * is a function-end breakpoint, because function_end is set to true.
121 *
122 * (This condition of pc < code address seems to occur only if a GC
123 * happens during tracing. I guess the function-end code object
124 * sometimes gets moved to a lower address than the corresponding
125 * code.)
126 *
127 * Hence this replacement looks at the function end flag first
128 * to see if it is a function-end breakpoint and does the function-end
129 * stuff anyway. If not, we do the normal stuff.
130 */
131 static int
132 compute_offset(os_context_t * scp, lispobj code, boolean function_end)
133 {
134 if (code == NIL)
135 return 0;
136 if (function_end) {
137 /*
138 * We're in a function end breakpoint. Compute the
139 * offset from the (known) breakpoint location and the
140 * beginning of the breakpoint guts. (See *-assem.S.)
141 *
142 * Then make the offset negative so the caller knows
143 * that the offset is not from the code object.
144 */
145 extern char function_end_breakpoint_trap;
146 extern char function_end_breakpoint_guts;
147 int offset;
148
149 offset =
150 &function_end_breakpoint_trap -
151 &function_end_breakpoint_guts;
152 #if 0
153 fprintf(stderr, "compute_offset\n");
154 fprintf(stderr, " function end offset = %d\n", offset);
155 #endif
156 return make_fixnum(-offset);
157 } else {
158 unsigned long code_start;
159 struct code *codeptr = (struct code *) PTR(code);
160 unsigned long pc = SC_PC(scp);
161
162 code_start = (unsigned long) codeptr
163 + HeaderValue(codeptr->header) * sizeof(lispobj);
164 #if 0
165 fprintf(stderr, "compute_offset\n");
166 fprintf(stderr, " pc = %d\n", pc);
167 fprintf(stderr, " code_start = %d\n", code_start);
168 fprintf(stderr, " function_end = %d\n", function_end);
169 #endif
170 if (pc < code_start) {
171 return 0;
172 } else {
173 int offset = pc - code_start;
174
175 #if 0
176 fprintf(stderr, " offset = %d\n", offset);
177 fprintf(stderr, " codeptr->code_size = %d\n", codeptr->code_size);
178 fprintf(stderr, " function_end = %d\n", function_end);
179 #endif
180 if (offset >= codeptr->code_size) {
181 return 0;
182 } else {
183 return make_fixnum(offset);
184 }
185 }
186 }
187 }
188 #else
189 static int
190 compute_offset(os_context_t * scp, lispobj code, boolean function_end)
191 {
192 if (code == NIL)
193 return 0;
194 else {
195 unsigned long code_start;
196 struct code *codeptr = (struct code *) PTR(code);
197
198 #ifdef parisc
199 unsigned long pc = SC_PC(scp) & ~3;
200 #else
201 unsigned long pc = SC_PC(scp);
202 #endif
203
204 code_start = (unsigned long) codeptr
205 + HeaderValue(codeptr->header) * sizeof(lispobj);
206 if (pc < code_start)
207 return 0;
208 else {
209 int offset = pc - code_start;
210
211 if (offset >= codeptr->code_size) {
212 if (function_end) {
213 #if defined(sparc) || (defined(DARWIN) && defined(__ppc__))
214 /*
215 * We're in a function end breakpoint. Compute the
216 * offset from the (known) breakpoint location and the
217 * beginning of the breakpoint guts. (See *-assem.S.)
218 *
219 * Then make the offset negative so the caller knows
220 * that the offset is not from the code object.
221 */
222 extern char function_end_breakpoint_trap;
223 extern char function_end_breakpoint_guts;
224
225 offset =
226 &function_end_breakpoint_trap -
227 &function_end_breakpoint_guts;
228 return make_fixnum(-offset);
229 #else
230 return 0;
231 #endif
232 } else {
233 return 0;
234 }
235 } else {
236 return make_fixnum(offset);
237 }
238 }
239 }
240 }
241 #endif
242
243 #ifndef i386
244 void
245 handle_breakpoint(int signal, int subcode, os_context_t * scp)
246 {
247 lispobj code;
248
249 fake_foreign_function_call(scp);
250
251 code = find_code(scp);
252
253 #if 0
254 fprintf(stderr, "handle_breakpoint\n");
255 fprintf(stderr, " offset = %d\n", compute_offset(scp, code, 0));
256 #endif
257 funcall3(SymbolFunction(HANDLE_BREAKPOINT),
258 compute_offset(scp, code, 0), code, alloc_sap(scp));
259
260 undo_fake_foreign_function_call(scp);
261 }
262 #else
263 void
264 handle_breakpoint(int signal, int subcode, os_context_t * scp)
265 {
266 lispobj code, scp_sap = alloc_sap(scp);
267
268 fake_foreign_function_call(scp);
269
270 code = find_code(scp);
271
272 /*
273 * Don't disallow recursive breakpoint traps. Otherwise, we can't
274 * use debugger breakpoints anywhere in here.
275 */
276
277 sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
278 funcall3(SymbolFunction(HANDLE_BREAKPOINT),
279 compute_offset(scp, code, 0), code, scp_sap);
280
281 undo_fake_foreign_function_call(scp);
282 }
283 #endif
284
285 #ifndef i386
286 void *
287 handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
288 {
289 lispobj code, lra;
290 struct code *codeptr;
291 int offset;
292
293 fake_foreign_function_call(scp);
294
295 code = find_code(scp);
296 codeptr = (struct code *) PTR(code);
297 offset = compute_offset(scp, code, 1);
298 #if 0
299 printf("handle_function_end:\n");
300 printf(" code = 0x%08x\n", code);
301 printf(" codeptr = %p\n", codeptr);
302 printf(" offset = %d\n", fixnum_value(offset));
303 fflush(stdout);
304 #endif
305
306 if (offset < 0) {
307 /*
308 * We were in the function end breakpoint. Which means we are
309 * in a bogus LRA, so compute where the code-component of this
310 * bogus lra object starts. Adjust code, and codeptr
311 * appropriately so the breakpoint handler can do the right
312 * thing.
313 */
314 unsigned int pc;
315
316 pc = SC_PC(scp);
317
318 offset = -offset;
319 /*
320 * Some magic here. pc points to the trap instruction. The
321 * offset gives us where the function_end_breakpoint_guts
322 * begins. But we need to back up some more to get to the
323 * code-component object. The magic 2 below is
324 */
325 code = pc - fixnum_value(offset);
326 code -= sizeof(struct code) + BOGUS_LRA_CONSTANTS * sizeof(lispobj);
327
328 code += type_OtherPointer;
329 codeptr = (struct code *) PTR(code);
330 #if 0
331 printf(" pc = 0x%08x\n", pc);
332 printf(" code = 0x%08x\n", code);
333 printf(" codeptr = %p\n", codeptr);
334 fflush(stdout);
335 #endif
336 }
337
338 funcall3(SymbolFunction(HANDLE_BREAKPOINT), offset, code, alloc_sap(scp));
339
340 /*
341 * Breakpoint handling done, so get the real LRA where we're
342 * supposed to return to so we can return there.
343 */
344 lra = codeptr->constants[REAL_LRA_SLOT];
345 #ifdef reg_CODE
346 /*
347 * With the known-return convention, we definitely do NOT want to
348 * mangle the CODE register because it isn't pointing to the bogus
349 * LRA but to the actual routine.
350 */
351 if (codeptr->constants[KNOWN_RETURN_P_SLOT] == NIL)
352 SC_REG(scp, reg_CODE) = lra;
353 #endif
354 undo_fake_foreign_function_call(scp);
355 return (void *) (lra - type_OtherPointer + sizeof(lispobj));
356 }
357 #else
358 void *
359 handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
360 {
361 lispobj code, scp_sap = alloc_sap(scp);
362 struct code *codeptr;
363
364 fake_foreign_function_call(scp);
365
366 code = find_code(scp);
367 codeptr = (struct code *) PTR(code);
368
369 /*
370 * Don't disallow recursive breakpoint traps. Otherwise, we can't
371 * use debugger breakpoints anywhere in here.
372 */
373
374 sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
375 funcall3(SymbolFunction(HANDLE_BREAKPOINT),
376 compute_offset(scp, code, 1), code, scp_sap);
377
378 undo_fake_foreign_function_call(scp);
379
380 return compute_pc(codeptr->constants[REAL_LRA_SLOT],
381 fixnum_value(codeptr->constants[REAL_LRA_SLOT + 1]));
382 }
383 #endif

  ViewVC Help
Powered by ViewVC 1.1.5