f3f414b8d3293d98bb08a07b63db880db4dacba3
[sbcl.git] / src / runtime / x86-64-arch.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
14 #include "sbcl.h"
15 #include "runtime.h"
16 #include "globals.h"
17 #include "validate.h"
18 #include "os.h"
19 #include "sbcl.h"
20 #include "arch.h"
21 #include "lispregs.h"
22 #include "signal.h"
23 #include "alloc.h"
24 #include "interrupt.h"
25 #include "interr.h"
26 #include "breakpoint.h"
27 #include "thread.h"
28 #include "pseudo-atomic.h"
29
30 #include "genesis/static-symbols.h"
31 #include "genesis/symbol.h"
32
33 #define BREAKPOINT_INST 0xcc    /* INT3 */
34
35 unsigned long fast_random_state = 1;
36
37 void arch_init(void)
38 {}
39
40 os_vm_address_t
41 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
42 {
43     return (os_vm_address_t)code->si_addr;
44 }
45
46 \f
47 /*
48  * hacking signal contexts
49  *
50  * (This depends both on architecture, which determines what we might
51  * want to get to, and on OS, which determines how we get to it.)
52  */
53
54 os_context_register_t *
55 context_eflags_addr(os_context_t *context)
56 {
57 #if defined __linux__ || defined __sun
58     /* KLUDGE: As of kernel 2.2.14 on Red Hat 6.2, there's code in the
59      * <sys/ucontext.h> file to define symbolic names for offsets into
60      * gregs[], but it's conditional on __USE_GNU and not defined, so
61      * we need to do this nasty absolute index magic number thing
62      * instead. */
63     return &context->uc_mcontext.gregs[17];
64 #elif defined __FreeBSD__
65     return &context->uc_mcontext.mc_rflags;
66 #elif defined LISP_FEATURE_DARWIN
67     return CONTEXT_ADDR_FROM_STEM(rflags);
68 #elif defined __OpenBSD__
69     return &context->sc_rflags;
70 #elif defined __NetBSD__
71     return CONTEXT_ADDR_FROM_STEM(RFLAGS);
72 #else
73 #error unsupported OS
74 #endif
75 }
76 \f
77 void arch_skip_instruction(os_context_t *context)
78 {
79     /* Assuming we get here via an INT3 xxx instruction, the PC now
80      * points to the interrupt code (a Lisp value) so we just move
81      * past it. Skip the code; after that, if the code is an
82      * error-trap or cerror-trap then skip the data bytes that follow. */
83
84     int vlen;
85     long code;
86
87
88     /* Get and skip the Lisp interrupt code. */
89     code = *(char*)(*os_context_pc_addr(context))++;
90     switch (code)
91         {
92         case trap_Error:
93         case trap_Cerror:
94             /* Lisp error arg vector length */
95             vlen = *(char*)(*os_context_pc_addr(context))++;
96             /* Skip Lisp error arg data bytes. */
97             while (vlen-- > 0) {
98                 ++*os_context_pc_addr(context);
99             }
100             break;
101
102         case trap_Breakpoint:           /* not tested */
103         case trap_FunEndBreakpoint: /* not tested */
104             break;
105
106         case trap_PendingInterrupt:
107         case trap_Halt:
108         case trap_SingleStepAround:
109         case trap_SingleStepBefore:
110             /* only needed to skip the Code */
111             break;
112
113         default:
114             fprintf(stderr,"[arch_skip_inst invalid code %ld\n]\n",code);
115             break;
116         }
117
118     FSHOW((stderr,
119            "/[arch_skip_inst resuming at %x]\n",
120            *os_context_pc_addr(context)));
121 }
122
123 unsigned char *
124 arch_internal_error_arguments(os_context_t *context)
125 {
126     return 1 + (unsigned char *)(*os_context_pc_addr(context));
127 }
128
129 boolean
130 arch_pseudo_atomic_atomic(os_context_t *context)
131 {
132     return get_pseudo_atomic_atomic(arch_os_get_current_thread());
133 }
134
135 void
136 arch_set_pseudo_atomic_interrupted(os_context_t *context)
137 {
138     struct thread *thread = arch_os_get_current_thread();
139     set_pseudo_atomic_interrupted(thread);
140 }
141
142 void
143 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
144 {
145     struct thread *thread = arch_os_get_current_thread();
146     clear_pseudo_atomic_interrupted(thread);
147 }
148 \f
149 /*
150  * This stuff seems to get called for TRACE and debug activity.
151  */
152
153 unsigned int
154 arch_install_breakpoint(void *pc)
155 {
156     unsigned int result = *(unsigned int*)pc;
157
158     *(char*)pc = BREAKPOINT_INST;               /* x86 INT3       */
159     *((char*)pc+1) = trap_Breakpoint;           /* Lisp trap code */
160
161     return result;
162 }
163
164 void
165 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
166 {
167     *((char *)pc) = orig_inst & 0xff;
168     *((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
169 }
170 \f
171 /* When single stepping, single_stepping holds the original instruction
172  * PC location. */
173 unsigned int *single_stepping = NULL;
174 #ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
175 unsigned int  single_step_save1;
176 unsigned int  single_step_save2;
177 unsigned int  single_step_save3;
178 #endif
179
180 void
181 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
182 {
183     unsigned int *pc = (unsigned int*)(*os_context_pc_addr(context));
184
185     /* Put the original instruction back. */
186     *((char *)pc) = orig_inst & 0xff;
187     *((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
188
189 #ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
190     /* Install helper instructions for the single step:
191      * pushf; or [esp],0x100; popf. */
192     single_step_save1 = *(pc-3);
193     single_step_save2 = *(pc-2);
194     single_step_save3 = *(pc-1);
195     *(pc-3) = 0x9c909090;
196     *(pc-2) = 0x00240c81;
197     *(pc-1) = 0x9d000001;
198 #else
199     *context_eflags_addr(context) |= 0x100;
200 #endif
201
202     single_stepping = pc;
203
204 #ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
205     *os_context_pc_addr(context) = (os_context_register_t)((char *)pc - 9);
206 #endif
207 }
208
209 void
210 arch_handle_breakpoint(os_context_t *context)
211 {
212     --*os_context_pc_addr(context);
213     handle_breakpoint(context);
214 }
215
216 void
217 arch_handle_fun_end_breakpoint(os_context_t *context)
218 {
219     --*os_context_pc_addr(context);
220     *os_context_pc_addr(context) =
221         (unsigned long)handle_fun_end_breakpoint(context);
222 }
223
224 void
225 arch_handle_single_step_trap(os_context_t *context, int trap)
226 {
227     arch_skip_instruction(context);
228     /* On x86-64 the fdefn / function is always in RAX, so we pass
229      * 0 as the register_offset. */
230     handle_single_step_trap(context, trap, 0);
231 }
232
233 \f
234 void
235 sigtrap_handler(int signal, siginfo_t *info, os_context_t *context)
236 {
237     unsigned int trap;
238
239     if (single_stepping && (signal==SIGTRAP))
240     {
241 #ifdef CANNOT_GET_TO_SINGLE_STEP_FLAG
242         /* Un-install single step helper instructions. */
243         *(single_stepping-3) = single_step_save1;
244         *(single_stepping-2) = single_step_save2;
245         *(single_stepping-1) = single_step_save3;
246 #else
247         *context_eflags_addr(context) ^= 0x100;
248 #endif
249         /* Re-install the breakpoint if possible. */
250         if ((char *)*os_context_pc_addr(context) ==
251             (char *)single_stepping + 1) {
252             fprintf(stderr, "warning: couldn't reinstall breakpoint\n");
253         } else {
254             *((char *)single_stepping) = BREAKPOINT_INST;       /* x86 INT3 */
255             *((char *)single_stepping+1) = trap_Breakpoint;
256         }
257
258         single_stepping = NULL;
259         return;
260     }
261
262     /* This is just for info in case the monitor wants to print an
263      * approximation. */
264     current_control_stack_pointer =
265         (lispobj *)*os_context_sp_addr(context);
266
267     /* On entry %eip points just after the INT3 byte and aims at the
268      * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
269      * number of bytes will follow, the first is the length of the byte
270      * arguments to follow. */
271     trap = *(unsigned char *)(*os_context_pc_addr(context));
272
273     handle_trap(context, trap);
274 }
275
276 void
277 sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context) {
278     /* Triggering SIGTRAP using int3 is unreliable on OS X/x86, so
279      * we need to use illegal instructions for traps.
280      */
281 #if defined(LISP_FEATURE_DARWIN) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
282     if (*((unsigned short *)*os_context_pc_addr(context)) == 0x0b0f) {
283         *os_context_pc_addr(context) += 2;
284         return sigtrap_handler(signal, siginfo, context);
285     }
286 #endif
287
288     fake_foreign_function_call(context);
289     lose("Unhandled SIGILL.");
290 }
291
292 #ifdef X86_64_SIGFPE_FIXUP
293 #define MXCSR_IE (0x01)         /* Invalid Operation */
294 #define MXCSR_DE (0x02)         /* Denormal */
295 #define MXCSR_ZE (0x04)         /* Devide-by-Zero */
296 #define MXCSR_OE (0x08)         /* Overflow */
297 #define MXCSR_UE (0x10)         /* Underflow */
298 #define MXCSR_PE (0x20)         /* Precision */
299
300 static inline int
301 mxcsr_to_code(unsigned int mxcsr)
302 {
303     /* Extract unmasked exception bits. */
304     mxcsr &= ~(mxcsr >> 7) & 0x3F;
305
306     /* This order is defined at "Intel 64 and IA-32 Architectures
307      * Software Developerfs Manual" Volume 1: "Basic Architecture",
308      * 4.9.2 "Floating-Point Exception Priority". */
309     if (mxcsr & MXCSR_IE)
310         return FPE_FLTINV;
311     else if (mxcsr & MXCSR_ZE)
312         return FPE_FLTDIV;
313     else if (mxcsr & MXCSR_DE)
314         return FPE_FLTUND;
315     else if (mxcsr & MXCSR_OE)
316         return FPE_FLTOVF;
317     else if (mxcsr & MXCSR_UE)
318         return FPE_FLTUND;
319     else if (mxcsr & MXCSR_PE)
320         return FPE_FLTRES;
321
322     return 0;
323 }
324
325 static void
326 sigfpe_handler(int signal, siginfo_t *siginfo, os_context_t *context)
327 {
328     unsigned int *mxcsr = arch_os_context_mxcsr_addr(context);
329
330     if (siginfo->si_code == 0) { /* XMM exception */
331         siginfo->si_code = mxcsr_to_code(*mxcsr);
332
333         /* Clear sticky exception flag. */
334         *mxcsr &= ~0x3F;
335     }
336
337     interrupt_handle_now(signal, siginfo, context);
338 }
339 #endif
340
341 void
342 arch_install_interrupt_handlers()
343 {
344     SHOW("entering arch_install_interrupt_handlers()");
345
346     /* Note: The old CMU CL code here used sigtrap_handler() to handle
347      * SIGILL as well as SIGTRAP. I couldn't see any reason to do
348      * things that way. So, I changed to separate handlers when
349      * debugging a problem on OpenBSD, where SBCL wasn't catching
350      * SIGILL properly, but was instead letting the process be
351      * terminated with an "Illegal instruction" output. If this change
352      * turns out to break something (maybe breakpoint handling on some
353      * OS I haven't tested on?) and we have to go back to the old CMU
354      * CL way, I hope there will at least be a comment to explain
355      * why.. -- WHN 2001-06-07 */
356 #if !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER)
357     undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
358     undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
359 #endif
360
361 #ifdef X86_64_SIGFPE_FIXUP
362     undoably_install_low_level_interrupt_handler(SIGFPE, sigfpe_handler);
363 #endif
364
365     SHOW("returning from arch_install_interrupt_handlers()");
366 }
367 \f
368 #ifdef LISP_FEATURE_LINKAGE_TABLE
369 /* FIXME: It might be cleaner to generate these from the lisp side of
370  * things.
371  */
372
373 void
374 arch_write_linkage_table_jmp(char * reloc, void * fun)
375 {
376     unsigned long addr = (unsigned long) fun;
377     int i;
378
379     *reloc++ = 0xFF; /* Opcode for near jump to absolute reg/mem64. */
380     *reloc++ = 0x25; /* ModRM #b00 100 101, i.e. RIP-relative. */
381     *reloc++ = 0x00; /* 32-bit displacement field = 0 */
382     *reloc++ = 0x00; /* ... */
383     *reloc++ = 0x00; /* ... */
384     *reloc++ = 0x00; /* ... */
385
386     for (i = 0; i < 8; i++) {
387         *reloc++ = addr & 0xff;
388         addr >>= 8;
389     }
390
391     /* write a nop for good measure. */
392     *reloc = 0x90;
393 }
394
395 void
396 arch_write_linkage_table_ref(void * reloc, void * data)
397 {
398     *(unsigned long *)reloc = (unsigned long)data;
399 }
400
401 #endif
402
403 /* These setup and check *both* the sse2 and x87 FPUs. While lisp code
404    only uses the sse2 FPU, other code (such as libc) may use the x87 FPU.
405  */
406
407 unsigned int
408 arch_get_fp_modes()
409 {
410     unsigned int temp;
411     unsigned int result;
412     /* return the x87 exception flags ored in with the sse2
413      * control+status flags */
414     asm ("fnstsw %0" : "=m" (temp));
415     result = temp;
416     result &= 0x3F;
417     asm ("stmxcsr %0" : "=m" (temp));
418     result |= temp;
419     /* flip exception mask bits */
420     return result ^ (0x3F << 7);
421 }
422
423 struct fpenv
424 {
425     unsigned short cw;
426     unsigned short unused1;
427     unsigned short sw;
428     unsigned short unused2;
429     unsigned int other_regs[5];
430 };
431
432 void
433 arch_set_fp_modes(unsigned int mxcsr)
434 {
435     struct fpenv f_env;
436     unsigned int temp;
437
438     /* turn trap enable bits into exception mask */
439     mxcsr ^= 0x3F << 7;
440
441     /* set x87 modes */
442     asm ("fnstenv %0" : "=m" (f_env));
443     /* set control word: always long double precision
444      * get traps and rounding from mxcsr word */
445     f_env.cw = 0x300 | ((mxcsr >> 7) & 0x3F) | (((mxcsr >> 13) & 0x3) << 10);
446     /* set status word: only override exception flags, from mxcsr */
447     f_env.sw &= ~0x3F;
448     f_env.sw |= (mxcsr & 0x3F);
449
450     asm ("fldenv %0" : : "m" (f_env));
451
452     /* now, simply, load up the mxcsr register */
453     temp = mxcsr;
454     asm ("ldmxcsr %0" : : "m" (temp));
455 }