0.6.12.48:
[sbcl.git] / src / runtime / breakpoint.c
1 /*
2  * This software is part of the SBCL system. See the README file for
3  * more information.
4  *
5  * This software is derived from the CMU CL system, which was
6  * written at Carnegie Mellon University and released into the
7  * public domain. The software is in the public domain and is
8  * provided with absolutely no warranty. See the COPYING and CREDITS
9  * files for more information.
10  */
11
12 #include <stdio.h>
13 #include <signal.h>
14
15 #include "runtime.h"
16 #include "os.h"
17 #include "sbcl.h"
18 #include "interrupt.h"
19 #include "arch.h"
20 #include "lispregs.h"
21 #include "globals.h"
22 #include "alloc.h"
23 #include "breakpoint.h"
24
25 #define REAL_LRA_SLOT 0
26 #ifndef __i386__
27 #define KNOWN_RETURN_P_SLOT 1
28 #define BOGUS_LRA_CONSTANTS 2
29 #else
30 #define KNOWN_RETURN_P_SLOT 2
31 #define BOGUS_LRA_CONSTANTS 3
32 #endif
33
34 static void *compute_pc(lispobj code_obj, int pc_offset)
35 {
36     struct code *code;
37
38     code = (struct code *)native_pointer(code_obj);
39     return (void *)((char *)code + HeaderValue(code->header)*sizeof(lispobj)
40                     + pc_offset);
41 }
42
43 unsigned long breakpoint_install(lispobj code_obj, int pc_offset)
44 {
45     return arch_install_breakpoint(compute_pc(code_obj, pc_offset));
46 }
47
48 void breakpoint_remove(lispobj code_obj, int pc_offset,
49                        unsigned long orig_inst)
50 {
51     arch_remove_breakpoint(compute_pc(code_obj, pc_offset), orig_inst);
52 }
53
54 void breakpoint_do_displaced_inst(os_context_t* context,
55                                   unsigned long orig_inst)
56 {
57 #if !defined(hpux) && !defined(irix) && !defined(__i386__)
58     undo_fake_foreign_function_call(context);
59 #endif
60     arch_do_displaced_inst(context, orig_inst);
61 }
62
63 #ifndef __i386__
64 static lispobj find_code(os_context_t *context)
65 {
66 #ifdef reg_CODE
67     lispobj code = *os_context_register_addr(context, reg_CODE);
68     lispobj header;
69
70     if (LowtagOf(code) != type_OtherPointer)
71         return NIL;
72
73     header = *(lispobj *)(code-type_OtherPointer);
74
75     if (TypeOf(header) == type_CodeHeader)
76         return code;
77     else
78         return code - HeaderValue(header)*sizeof(lispobj);
79 #else
80     return NIL;
81 #endif
82 }
83 #endif
84
85 #ifdef __i386__
86 static lispobj find_code(os_context_t *context)
87 {
88   lispobj codeptr =
89       (lispobj)component_ptr_from_pc((lispobj *)(*os_context_pc_addr(context)));
90
91   if (codeptr == 0) {
92       return NIL;
93   } else {
94       return codeptr + type_OtherPointer;
95   }
96 }
97 #endif
98
99 static int compute_offset(os_context_t *context, lispobj code)
100 {
101     if (code == NIL)
102         return 0;
103     else {
104         unsigned long code_start;
105         struct code *codeptr = (struct code *)native_pointer(code);
106 #ifdef parisc
107         unsigned long pc = *os_context_pc_addr(context) & ~3;
108 #else
109         unsigned long pc = *os_context_pc_addr(context);
110 #endif
111
112         code_start = (unsigned long)codeptr
113             + HeaderValue(codeptr->header)*sizeof(lispobj);
114         if (pc < code_start)
115             return 0;
116         else {
117             int offset = pc - code_start;
118             if (offset >= codeptr->code_size)
119                 return 0;
120             else
121                 return make_fixnum(offset);
122         }
123     }
124 }
125
126 #ifndef __i386__
127 void handle_breakpoint(int signal, siginfo_t *info, os_context_t *context)
128 {
129     lispobj code;
130
131     fake_foreign_function_call(context);
132
133     code = find_code(context);
134
135     funcall3(SymbolFunction(HANDLE_BREAKPOINT),
136              compute_offset(context, code),
137              code,
138              alloc_sap(context));
139
140     undo_fake_foreign_function_call(context);
141 }
142 #else
143 void handle_breakpoint(int signal, siginfo_t* info, os_context_t *context)
144 {
145     lispobj code, context_sap = alloc_sap(context);
146
147     fake_foreign_function_call(context);
148
149     code = find_code(context);
150
151     /* Don't disallow recursive breakpoint traps. Otherwise, we can't
152      * use debugger breakpoints anywhere in here. */
153     sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
154
155     funcall3(SymbolFunction(HANDLE_BREAKPOINT),
156              compute_offset(context, code),
157              code,
158              context_sap);
159
160     undo_fake_foreign_function_call(context);
161 }
162 #endif
163
164 #ifndef __i386__
165 void *handle_function_end_breakpoint(int signal, siginfo_t *info,
166                                      os_context_t *context)
167 {
168     lispobj code, lra;
169     struct code *codeptr;
170
171     fake_foreign_function_call(context);
172
173     code = find_code(context);
174     codeptr = (struct code *)native_pointer(code);
175
176     funcall3(SymbolFunction(HANDLE_BREAKPOINT),
177              compute_offset(context, code),
178              code,
179              alloc_sap(context));
180
181     lra = codeptr->constants[REAL_LRA_SLOT];
182 #ifdef reg_CODE
183     if (codeptr->constants[KNOWN_RETURN_P_SLOT] == NIL) {
184         *os_context_register_addr(context, reg_CODE) = lra;
185     }
186 #endif
187     undo_fake_foreign_function_call(context);
188     return (void *)(lra-type_OtherPointer+sizeof(lispobj));
189 }
190 #else
191 void *handle_function_end_breakpoint(int signal, siginfo_t *info,
192                                      os_context_t *context)
193 {
194     lispobj code, context_sap = alloc_sap(context);
195     struct code *codeptr;
196
197     fake_foreign_function_call(context);
198
199     code = find_code(context);
200     codeptr = (struct code *)native_pointer(code);
201
202     /* Don't disallow recursive breakpoint traps. Otherwise, we can't
203      * use debugger breakpoints anywhere in here. */
204     sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
205
206     funcall3(SymbolFunction(HANDLE_BREAKPOINT),
207              compute_offset(context, code),
208              code,
209              context_sap);
210
211     undo_fake_foreign_function_call(context);
212
213     return compute_pc(codeptr->constants[REAL_LRA_SLOT],
214                       fixnum_value(codeptr->constants[REAL_LRA_SLOT+1]));
215 }
216 #endif