Newer
Older
/*
This code was written as part of the CMU Common Lisp project at
Carnegie Mellon University, and has been placed in the public domain.
*/
#include <stdio.h>
#include <signal.h>
#include "lisp.h"
#include "os.h"
#include "internals.h"
#include "arch.h"
#include "lispregs.h"
#include "globals.h"
#include "alloc.h"
#include "breakpoint.h"
* See MAKE-BOGUS-LRA in code/debug-int.lisp for these values.
*
* Ideally, internals.h should have the correct values. We leave
* these defaults here for now.
#else
#define KNOWN_RETURN_P_SLOT 2
#endif
#endif
#ifndef BOGUS_LRA_CONSTANTS
#ifndef i386
#define BOGUS_LRA_CONSTANTS 2
#else
#define BOGUS_LRA_CONSTANTS 3
#endif
static void *
compute_pc(lispobj code_obj, int pc_offset)
code = (struct code *) PTR(code_obj);
return (void *) ((char *) code + HeaderValue(code->header) * sizeof(lispobj)
+ pc_offset);
unsigned long
breakpoint_install(lispobj code_obj, int pc_offset)
{
return arch_install_breakpoint(compute_pc(code_obj, pc_offset));
}
void
breakpoint_remove(lispobj code_obj, int pc_offset, unsigned long orig_inst)
{
arch_remove_breakpoint(compute_pc(code_obj, pc_offset), orig_inst);
}
void
breakpoint_do_displaced_inst(os_context_t * scp, unsigned long orig_inst)
#if !defined(hpux) && !defined(irix) && !defined(i386)
static lispobj
find_code(os_context_t * scp)
header = *(lispobj *) (code - type_OtherPointer);
if (TypeOf(header) == type_CodeHeader)
return code;
else
return code - HeaderValue(header) * sizeof(lispobj);
static lispobj
find_code(os_context_t * scp)
lispobj *codeptr = component_ptr_from_pc((lispobj *) SC_PC(scp));
if (codeptr == NULL)
return NIL;
else
return (lispobj) codeptr | type_OtherPointer;
}
#endif
#if (defined(DARWIN) && defined(__ppc__)) || (defined(sparc))
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
* During a function-end-breakpoint, the pc is sometimes less than the
* code address, which bypasses the function end stuff. Then the
* offset is zero for a function-end-breakpoint, and we can't find the
* breakpoint data, causing an error during tracing. But we know this
* is a function-end breakpoint, because function_end is set to true.
*
* (This condition of pc < code address seems to occur only if a GC
* happens during tracing. I guess the function-end code object
* sometimes gets moved to a lower address than the corresponding
* code.)
*
* Hence this replacement looks at the function end flag first
* to see if it is a function-end breakpoint and does the function-end
* stuff anyway. If not, we do the normal stuff.
*/
static int
compute_offset(os_context_t * scp, lispobj code, boolean function_end)
{
if (code == NIL)
return 0;
if (function_end) {
/*
* We're in a function end breakpoint. Compute the
* offset from the (known) breakpoint location and the
* beginning of the breakpoint guts. (See *-assem.S.)
*
* Then make the offset negative so the caller knows
* that the offset is not from the code object.
*/
extern char function_end_breakpoint_trap;
extern char function_end_breakpoint_guts;
int offset;
offset =
&function_end_breakpoint_trap -
&function_end_breakpoint_guts;
#if 0
fprintf(stderr, "compute_offset\n");
fprintf(stderr, " function end offset = %d\n", offset);
#endif
return make_fixnum(-offset);
} else {
unsigned long code_start;
struct code *codeptr = (struct code *) PTR(code);
unsigned long pc = SC_PC(scp);
code_start = (unsigned long) codeptr
+ HeaderValue(codeptr->header) * sizeof(lispobj);
#if 0
fprintf(stderr, "compute_offset\n");
fprintf(stderr, " pc = %d\n", pc);
fprintf(stderr, " code_start = %d\n", code_start);
fprintf(stderr, " function_end = %d\n", function_end);
#endif
if (pc < code_start) {
return 0;
} else {
int offset = pc - code_start;
#if 0
fprintf(stderr, " offset = %d\n", offset);
fprintf(stderr, " codeptr->code_size = %d\n", codeptr->code_size);
fprintf(stderr, " function_end = %d\n", function_end);
#endif
if (offset >= codeptr->code_size) {
return 0;
} else {
return make_fixnum(offset);
}
}
}
}
#else
static int
compute_offset(os_context_t * scp, lispobj code, boolean function_end)
struct code *codeptr = (struct code *) PTR(code);
#ifdef parisc
unsigned long pc = SC_PC(scp) & ~3;
#else
unsigned long pc = SC_PC(scp);
#endif
code_start = (unsigned long) codeptr
+ HeaderValue(codeptr->header) * sizeof(lispobj);
if (offset >= codeptr->code_size) {
return make_fixnum(offset);
}
void
handle_breakpoint(int signal, int subcode, os_context_t * scp)
{
lispobj code;
fake_foreign_function_call(scp);
code = find_code(scp);
#if 0
fprintf(stderr, "handle_breakpoint\n");
fprintf(stderr, " offset = %d\n", compute_offset(scp, code, 0));
#endif
funcall3(SymbolFunction(HANDLE_BREAKPOINT),
compute_offset(scp, code, 0), code, alloc_sap(scp));
undo_fake_foreign_function_call(scp);
}
#else
void
handle_breakpoint(int signal, int subcode, os_context_t * scp)
lispobj code, scp_sap = alloc_sap(scp);
/*
* Don't disallow recursive breakpoint traps. Otherwise, we can't
* use debugger breakpoints anywhere in here.
*/
sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
compute_offset(scp, code, 0), code, scp_sap);
#ifndef i386
void *
handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
lispobj code, lra;
int known_return_p;
codeptr = (struct code *) PTR(code);
offset = compute_offset(scp, code, 1);
#if 0
printf("handle_function_end:\n");
printf(" code = 0x%08x\n", code);
printf(" codeptr = %p\n", codeptr);
printf(" offset = %d\n", fixnum_value(offset));
fflush(stdout);
#endif
if (offset < 0) {
/*
* We were in the function end breakpoint. Which means we are
* in a bogus LRA, so compute where the code-component of this
* bogus lra object starts. Adjust code, and codeptr
* appropriately so the breakpoint handler can do the right
* thing.
*/
unsigned int pc;
pc = SC_PC(scp);
offset = -offset;
/*
* Some magic here. pc points to the trap instruction. The
* offset gives us where the function_end_breakpoint_guts
* begins. But we need to back up some more to get to the
* code-component object. See MAKE-BOGUS-LRA in
* debug-int.lisp
*/
code = pc - fixnum_value(offset);
code -= sizeof(struct code) + BOGUS_LRA_CONSTANTS * sizeof(lispobj);
code += type_OtherPointer;
codeptr = (struct code *) PTR(code);
#if 0
printf(" pc = 0x%08x\n", pc);
printf(" code = 0x%08x\n", code);
printf(" codeptr = %p\n", codeptr);
fflush(stdout);
#endif
known_return_p = codeptr->constants[KNOWN_RETURN_P_SLOT] != NIL;
lispobj *args = current_control_stack_pointer;
/*
* Because HANDLE_BREAKPOINT can GC, the LRA could move, and
* we need to know where it went so we can return to the
* correct place. We do this by saving the LRA on the Lisp
* stack. If GC moves the LRA, the stack entry will get
* updated appropriately too.
*/
current_control_stack_pointer += 1;
args[0] = lra;
funcall3(SymbolFunction(HANDLE_BREAKPOINT), offset, code, alloc_sap(scp));
/*
* Breakpoint handling done. Get the (possibly changed) LRA
* value off the stack so we know where to return to.
*/
lra = args[0];
current_control_stack_pointer -= 1;
#ifdef reg_CODE
/*
* With the known-return convention, we definitely do NOT want
* to mangle the CODE register because it isn't pointing to
* the bogus LRA but to the actual routine.
*/
if (!known_return_p) {
SC_REG(scp, reg_CODE) = lra;
}
undo_fake_foreign_function_call(scp);
return (void *) (lra - type_OtherPointer + sizeof(lispobj));
void *
handle_function_end_breakpoint(int signal, int subcode, os_context_t * scp)
lispobj code, scp_sap = alloc_sap(scp);
struct code *codeptr;
fake_foreign_function_call(scp);
code = find_code(scp);
codeptr = (struct code *) PTR(code);
/*
* Don't disallow recursive breakpoint traps. Otherwise, we can't
* use debugger breakpoints anywhere in here.
*/
sigprocmask(SIG_SETMASK, &scp->uc_sigmask, NULL);
funcall3(SymbolFunction(HANDLE_BREAKPOINT),
compute_offset(scp, code, 1), code, scp_sap);
return compute_pc(codeptr->constants[REAL_LRA_SLOT],