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 "sbcl.h"
16 #include "runtime.h"
17 #include "os.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 #include "thread.h"
25 #include "genesis/code.h"
26 #include "genesis/fdefn.h"
27 
28 #ifdef LISP_FEATURE_X86_64
29 #define REAL_LRA_SLOT 0
30 #define KNOWN_RETURN_P_SLOT 2
31 #define BOGUS_LRA_CONSTANTS 3
32 #elif defined(LISP_FEATURE_X86)
33 #define REAL_LRA_SLOT 1
34 #define KNOWN_RETURN_P_SLOT 3
35 #define BOGUS_LRA_CONSTANTS 4
36 #else
37 #define REAL_LRA_SLOT 0
38 #define KNOWN_RETURN_P_SLOT 1
39 #define BOGUS_LRA_CONSTANTS 2
40 #endif
41 
compute_pc(lispobj code_obj,int pc_offset)42 static void *compute_pc(lispobj code_obj, int pc_offset)
43 {
44     struct code *code;
45 
46     code = (struct code *)native_pointer(code_obj);
47     return (void *)((char *)code + code_header_words(code->header)*sizeof(lispobj)
48                     + pc_offset);
49 }
50 
breakpoint_install(lispobj code_obj,int pc_offset)51 unsigned int breakpoint_install(lispobj code_obj, int pc_offset)
52 {
53     return arch_install_breakpoint(compute_pc(code_obj, pc_offset));
54 }
55 
breakpoint_remove(lispobj code_obj,int pc_offset,unsigned int orig_inst)56 void breakpoint_remove(lispobj code_obj, int pc_offset,
57                        unsigned int orig_inst)
58 {
59     arch_remove_breakpoint(compute_pc(code_obj, pc_offset), orig_inst);
60 }
61 
breakpoint_do_displaced_inst(os_context_t * context,unsigned int orig_inst)62 void breakpoint_do_displaced_inst(os_context_t* context,
63                                   unsigned int orig_inst)
64 {
65     /* on platforms with sigreturn(), we go directly back from
66      * arch_do_displaced_inst() to lisp code, so we need to clean up
67      * our bindings now.  (side note: I'd love to know in exactly what
68      * scenario the speed of breakpoint handling is critical enough to
69      * justify this maintenance mess)
70      *
71      * -dan 2001.08.09 */
72 
73 #if (defined(LISP_FEATURE_SPARC) && defined (solaris))
74     undo_fake_foreign_function_call(context);
75 #endif
76     arch_do_displaced_inst(context, orig_inst);
77 }
78 
find_code(os_context_t * context)79 lispobj find_code(os_context_t *context)
80 {
81 #ifdef reg_CODE
82     lispobj code = *os_context_register_addr(context, reg_CODE);
83     lispobj header;
84 
85     if (lowtag_of(code) != OTHER_POINTER_LOWTAG)
86         return NIL;
87 
88     header = *(lispobj *)(code-OTHER_POINTER_LOWTAG);
89 
90     if (widetag_of(header) == CODE_HEADER_WIDETAG)
91         return code;
92     else
93         return code - HeaderValue(header)*sizeof(lispobj);
94 #else
95     lispobj codeptr =
96         (lispobj)component_ptr_from_pc((lispobj *)(*os_context_pc_addr(context)));
97 
98     if (codeptr == 0)
99         return NIL;
100     else
101         return codeptr + OTHER_POINTER_LOWTAG;
102 #endif
103 }
104 
compute_offset(os_context_t * context,lispobj code)105 static long compute_offset(os_context_t *context, lispobj code)
106 {
107     if (code == NIL)
108         return 0;
109     else {
110         uword_t code_start;
111         struct code *codeptr = (struct code *)native_pointer(code);
112 #ifdef LISP_FEATURE_HPPA
113         uword_t pc = *os_context_pc_addr(context) & ~3;
114 #else
115         uword_t pc = *os_context_pc_addr(context);
116 #endif
117 
118         code_start = (uword_t)codeptr
119             + code_header_words(codeptr->header)*sizeof(lispobj);
120         if (pc < code_start)
121             return 0;
122         else {
123             uword_t offset = pc - code_start;
124             if (offset >= (uword_t)fixnum_value(codeptr->code_size))
125                 return 0;
126             else
127                 return make_fixnum(offset);
128         }
129     }
130 }
131 
handle_breakpoint(os_context_t * context)132 void handle_breakpoint(os_context_t *context)
133 {
134     lispobj code;
135     DX_ALLOC_SAP(context_sap, context);
136 
137     fake_foreign_function_call(context);
138 
139 #ifndef LISP_FEATURE_SB_SAFEPOINT
140     unblock_gc_signals(0, 0);
141 #endif
142     code = find_code(context);
143 
144 #ifndef LISP_FEATURE_WIN32
145     /* Don't disallow recursive breakpoint traps. Otherwise, we can't
146      * use debugger breakpoints anywhere in here. */
147     thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
148 #endif
149 
150     funcall3(StaticSymbolFunction(HANDLE_BREAKPOINT),
151              compute_offset(context, code),
152              code,
153              context_sap);
154 
155     undo_fake_foreign_function_call(context);
156 }
157 
handle_fun_end_breakpoint(os_context_t * context)158 void *handle_fun_end_breakpoint(os_context_t *context)
159 {
160     lispobj code, lra;
161     struct code *codeptr;
162     DX_ALLOC_SAP(context_sap, context);
163 
164     fake_foreign_function_call(context);
165 
166 #ifndef LISP_FEATURE_SB_SAFEPOINT
167     unblock_gc_signals(0, 0);
168 #endif
169 
170     code = find_code(context);
171     codeptr = (struct code *)native_pointer(code);
172 
173 #ifndef LISP_FEATURE_WIN32
174     /* Don't disallow recursive breakpoint traps. Otherwise, we can't
175      * use debugger breakpoints anywhere in here. */
176     thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
177 #endif
178 
179     funcall3(StaticSymbolFunction(HANDLE_BREAKPOINT),
180              compute_offset(context, code),
181              code,
182              context_sap);
183 
184     lra = codeptr->constants[REAL_LRA_SLOT];
185 
186 #ifdef LISP_FEATURE_PPC
187     /* PPC now passes LRA objects in reg_LRA during return.  Other
188      * platforms should as well, but haven't been fixed yet. */
189     *os_context_register_addr(context, reg_LRA) = lra;
190 #else
191 #ifdef reg_CODE
192     *os_context_register_addr(context, reg_CODE) = lra;
193 #endif
194 #endif
195 
196     undo_fake_foreign_function_call(context);
197 
198 #ifdef reg_LRA
199     return (void *)(lra-OTHER_POINTER_LOWTAG+sizeof(lispobj));
200 #else
201     return compute_pc(lra, fixnum_value(codeptr->constants[REAL_LRA_SLOT+1]));
202 #endif
203 }
204 
205 void
handle_single_step_trap(os_context_t * context,int kind,int register_offset)206 handle_single_step_trap (os_context_t *context, int kind, int register_offset)
207 {
208     fake_foreign_function_call(context);
209 
210 #ifndef LISP_FEATURE_WIN32
211     thread_sigmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
212 #endif
213 
214     funcall2(StaticSymbolFunction(HANDLE_SINGLE_STEP_TRAP),
215              make_fixnum(kind),
216              make_fixnum(register_offset));
217 
218     undo_fake_foreign_function_call(context); /* blocks signals again */
219 }
220