0.9.9.12:
[sbcl.git] / src / runtime / win32-os.c
1 /*
2  * the Win32 incarnation of OS-dependent routines.  See also
3  * $(sbcl_arch)-win32-os.c
4  *
5  * This file (along with os.h) exports an OS-independent interface to
6  * the operating system VM facilities. Surprise surprise, this
7  * interface looks a lot like the Mach interface (but simpler in some
8  * places). For some operating systems, a subset of these functions
9  * will have to be emulated.
10  */
11
12 /*
13  * This software is part of the SBCL system. See the README file for
14  * more information.
15  *
16  * This software is derived from the CMU CL system, which was
17  * written at Carnegie Mellon University and released into the
18  * public domain. The software is in the public domain and is
19  * provided with absolutely no warranty. See the COPYING and CREDITS
20  * files for more information.
21  */
22
23 /*
24  * This file was copied from the Linux version of the same, and
25  * likely still has some linuxisms in it have haven't been elimiated
26  * yet.
27  */
28
29 #include <stdio.h>
30 #include <sys/param.h>
31 #include <sys/file.h>
32 #include "sbcl.h"
33 #include "./signal.h"
34 #include "os.h"
35 #include "arch.h"
36 #include "globals.h"
37 #include "sbcl.h"
38 #include "interrupt.h"
39 #include "interr.h"
40 #include "lispregs.h"
41 #include "runtime.h"
42 #include "monitor.h"
43 #include "alloc.h"
44 #include "genesis/primitive-objects.h"
45
46 #include <sys/types.h>
47 #include <signal.h>
48 #include <sys/time.h>
49 #include <sys/stat.h>
50 #include <unistd.h>
51
52 #include <excpt.h>
53
54 #include "validate.h"
55 #include "thread.h"
56 size_t os_vm_page_size;
57
58
59 #include "gc.h"
60 #include "gencgc-internal.h"
61
62 #if 0
63 int linux_sparc_siginfo_bug = 0;
64 int linux_supports_futex=0;
65 #endif
66
67 /* The exception handling function looks like this: */
68 EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *,
69                                        struct lisp_exception_frame *,
70                                        CONTEXT *,
71                                        void *);
72
73 void *base_seh_frame;
74
75 static void *get_seh_frame(void)
76 {
77     void* retval;
78     asm volatile ("movl %%fs:0,%0": "=r" (retval));
79     return retval;
80 }
81
82 static void set_seh_frame(void *frame)
83 {
84     asm volatile ("movl %0,%%fs:0": : "r" (frame));
85 }
86
87 static struct lisp_exception_frame *find_our_seh_frame(void)
88 {
89     struct lisp_exception_frame *frame = get_seh_frame();
90
91     while (frame->handler != handle_exception)
92         frame = frame->next_frame;
93
94     return frame;
95 }
96
97 #if 0
98 inline static void *get_stack_frame(void)
99 {
100     void* retval;
101     asm volatile ("movl %%ebp,%0": "=r" (retval));
102     return retval;
103 }
104 #endif
105
106 void os_init(char *argv[], char *envp[])
107 {
108     SYSTEM_INFO system_info;
109
110     GetSystemInfo(&system_info);
111     os_vm_page_size = system_info.dwPageSize;
112
113     base_seh_frame = get_seh_frame();
114 }
115
116
117 /*
118  * So we have three fun scenarios here.
119  *
120  * First, we could be being called to reserve the memory areas
121  * during initialization (prior to loading the core file).
122  *
123  * Second, we could be being called by the GC to commit a page
124  * that has just been decommitted (for easy zero-fill).
125  *
126  * Third, we could be being called by create_thread_struct()
127  * in order to create the sundry and various stacks.
128  *
129  * The third case is easy to pick out because it passes an
130  * addr of 0.
131  *
132  * The second case is easy to pick out because it will be for
133  * a range of memory that is MEM_RESERVE rather than MEM_FREE.
134  *
135  * The second case is also an easy implement, because we leave
136  * the memory as reserved (since we do lazy commits).
137  */
138
139 os_vm_address_t
140 os_validate(os_vm_address_t addr, os_vm_size_t len)
141 {
142     MEMORY_BASIC_INFORMATION mem_info;
143
144     if (!addr) {
145         /* the simple case first */
146         os_vm_address_t real_addr;
147         if (!(real_addr = VirtualAlloc(addr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE))) {
148             perror("VirtualAlloc");
149             return 0;
150         }
151
152         return real_addr;
153     }
154
155     if (!VirtualQuery(addr, &mem_info, sizeof mem_info)) {
156         perror("VirtualQuery");
157         return 0;
158     }
159
160     if ((mem_info.State == MEM_RESERVE) && (mem_info.RegionSize >=len)) return addr;
161
162     if (mem_info.State == MEM_RESERVE) {
163         fprintf(stderr, "validation of reserved space too short.\n");
164         fflush(stderr);
165     }
166
167     if (!VirtualAlloc(addr, len, (mem_info.State == MEM_RESERVE)? MEM_COMMIT: MEM_RESERVE, PAGE_EXECUTE_READWRITE)) {
168         perror("VirtualAlloc");
169         return 0;
170     }
171
172     return addr;
173 }
174
175 /*
176  * For os_invalidate(), we merely decommit the memory rather than
177  * freeing the address space. This loses when freeing per-thread
178  * data and related memory since it leaks address space. It's not
179  * too lossy, however, since the two scenarios I'm aware of are
180  * fd-stream buffers, which are pooled rather than torched, and
181  * thread information, which I hope to pool (since windows creates
182  * threads at its own whim, and we probably want to be able to
183  * have them callback without funky magic on the part of the user,
184  * and full-on thread allocation is fairly heavyweight). Someone
185  * will probably shoot me down on this with some pithy comment on
186  * the use of (setf symbol-value) on a special variable. I'm happy
187  * for them.
188  */
189
190 void
191 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
192 {
193     if (!VirtualFree(addr, len, MEM_DECOMMIT)) {
194         perror("VirtualFree");
195     }
196 }
197
198 /*
199  * os_map() is called to map a chunk of the core file into memory.
200  *
201  * Unfortunately, Windows semantics completely screws this up, so
202  * we just add backing store from the swapfile to where the chunk
203  * goes and read it up like a normal file. We could consider using
204  * a lazy read (demand page) setup, but that would mean keeping an
205  * open file pointer for the core indefinately (and be one more
206  * thing to maintain).
207  */
208
209 os_vm_address_t
210 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
211 {
212     os_vm_size_t count;
213
214     fprintf(stderr, "os_map: %d, 0x%x, %p, 0x%x.\n", fd, offset, addr, len);
215     fflush(stderr);
216
217     if (!VirtualAlloc(addr, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) {
218         perror("VirtualAlloc");
219         lose("os_map: VirtualAlloc failure");
220     }
221
222     if (lseek(fd, offset, SEEK_SET) == -1) {
223         lose("os_map: Seek failure.");
224     }
225
226     count = read(fd, addr, len);
227     if (count != len) {
228         fprintf(stderr, "expected 0x%x, read 0x%x.\n", len, count);
229         lose("os_map: Failed to read enough bytes.");
230     }
231
232     return addr;
233 }
234
235 static DWORD os_protect_modes[8] = {
236     PAGE_NOACCESS,
237     PAGE_READONLY,
238     PAGE_READWRITE,
239     PAGE_READWRITE,
240     PAGE_EXECUTE,
241     PAGE_EXECUTE_READ,
242     PAGE_EXECUTE_READWRITE,
243     PAGE_EXECUTE_READWRITE,
244 };
245
246 void
247 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
248 {
249     DWORD old_prot;
250
251     if (!VirtualProtect(address, length, os_protect_modes[prot], &old_prot)) {
252         fprintf(stderr, "VirtualProtect failed, code 0x%lx.\n", GetLastError());
253         fflush(stderr);
254     }
255 }
256
257 /* FIXME: Now that FOO_END, rather than FOO_SIZE, is the fundamental
258  * description of a space, we could probably punt this and just do
259  * (FOO_START <= x && x < FOO_END) everywhere it's called. */
260 static boolean
261 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
262 {
263     char* beg = (char*)((long)sbeg);
264     char* end = (char*)((long)sbeg) + slen;
265     char* adr = (char*)a;
266     return (adr >= beg && adr < end);
267 }
268
269 boolean
270 is_valid_lisp_addr(os_vm_address_t addr)
271 {
272     struct thread *th;
273     if(in_range_p(addr, READ_ONLY_SPACE_START, READ_ONLY_SPACE_SIZE) ||
274        in_range_p(addr, STATIC_SPACE_START   , STATIC_SPACE_SIZE) ||
275        in_range_p(addr, DYNAMIC_SPACE_START  , DYNAMIC_SPACE_SIZE))
276         return 1;
277     for_each_thread(th) {
278         if(((os_vm_address_t)th->control_stack_start <= addr) && (addr < (os_vm_address_t)th->control_stack_end))
279             return 1;
280         if(in_range_p(addr, (unsigned long)th->binding_stack_start, BINDING_STACK_SIZE))
281             return 1;
282     }
283     return 0;
284 }
285
286 /*
287  * any OS-dependent special low-level handling for signals
288  */
289
290 /* A tiny bit of interrupt.c state we want our paws on. */
291 extern boolean internal_errors_enabled;
292
293 /*
294  * FIXME: There is a potential problem with foreign code here.
295  * If we are running foreign code instead of lisp code and an
296  * exception occurs we arrange a call into Lisp. If the
297  * foreign code has installed an exception handler, we run the
298  * very great risk of throwing through their exception handler
299  * without asking it to unwind. This is more a problem with
300  * non-sigtrap (EXCEPTION_BREAKPOINT) exceptions, as they could
301  * reasonably be expected to happen in foreign code. We need to
302  * figure out the exception handler unwind semantics and adhere
303  * to them (probably by abusing the Lisp unwind-protect system)
304  * if we are going to handle this scenario correctly.
305  *
306  * A good explanation of the exception handling semantics is
307  * http://win32assembly.online.fr/Exceptionhandling.html .
308  * We will also need to handle this ourselves when foreign
309  * code tries to unwind -us-.
310  *
311  * When unwinding through foreign code we should unwind the
312  * Lisp stack to the entry from foreign code, then unwind the
313  * foreign code stack to the entry from Lisp, then resume
314  * unwinding in Lisp.
315  */
316
317 EXCEPTION_DISPOSITION sigtrap_emulator(CONTEXT *context,
318                                        struct lisp_exception_frame *exception_frame)
319 {
320     if (*((char *)context->Eip + 1) == trap_ContextRestore) {
321         /*
322          * This is the cleanup for what is immediately below, and
323          * for the generic exception handling further below. We
324          * have to memcpy() the original context (emulated sigtrap
325          * or normal exception) over our context and resume it.
326          */
327         memcpy(context, &exception_frame->context, sizeof(CONTEXT));
328         return ExceptionContinueExecution;
329
330     } else { /* Not a trap_ContextRestore, must be a sigtrap. */
331         /* sigtrap_trampoline is defined in x86-assem.S. */
332         extern void sigtrap_trampoline;
333
334         /*
335          * Unlike some other operating systems, Win32 leaves EIP
336          * pointing to the breakpoint instruction.
337          */
338         context->Eip++;
339
340         /*
341          * We're not on an alternate stack like we would be in some
342          * other operating systems, and we don't want to risk leaking
343          * any important resources if we throw out of the sigtrap
344          * handler, so we need to copy off our context to a "safe"
345          * place and then monkey with the return EIP to point to a
346          * trampoline which calls another function which copies the
347          * context out to a really-safe place and then calls the real
348          * sigtrap handler. When the real sigtrap handler returns, the
349          * trampoline then contains another breakpoint with a code of
350          * trap_ContextRestore (see above). Essentially the same
351          * mechanism is used by the generic exception path. There is
352          * a small window of opportunity between us copying the
353          * context to the "safe" place and the sigtrap wrapper copying
354          * it to the really-safe place (allocated in its stack frame)
355          * during which the context can be smashed. The only scenario
356          * I can come up with for this, however, involves a stack
357          * overflow occuring at just the wrong time (which makes one
358          * wonder how stack overflow exceptions even happen, given
359          * that we don't switch stacks for exception processing...)
360          */
361         memcpy(&exception_frame->context, context, sizeof(CONTEXT));
362         context->Eax = context->Eip;
363         context->Eip = (unsigned long)&sigtrap_trampoline;
364
365         /* and return */
366         return ExceptionContinueExecution;
367     }
368 }
369
370 void sigtrap_wrapper(void)
371 {
372     /*
373      * This is the wrapper around the sigtrap handler called from
374      * the trampoline returned to from the function above.
375      *
376      * There actually is a point to some of the commented-out code
377      * in this function, although it really belongs to the callback
378      * wrappers. Once it is installed there, it can probably be
379      * removed from here.
380      */
381
382     extern void sigtrap_handler(int signal, siginfo_t *info, void *context);
383
384 /*     volatile struct { */
385 /*      void *handler[2]; */
386     CONTEXT context;
387 /*     } handler; */
388
389     struct lisp_exception_frame *frame = find_our_seh_frame();
390
391 /*     wos_install_interrupt_handlers(handler); */
392 /*     handler.handler[0] = get_seh_frame(); */
393 /*     handler.handler[1] = &handle_exception; */
394 /*     set_seh_frame(&handler); */
395
396     memcpy(&context, &frame->context, sizeof(CONTEXT));
397     sigtrap_handler(0, NULL, &context);
398     memcpy(&frame->context, &context, sizeof(CONTEXT));
399
400 /*     set_seh_frame(handler.handler[0]); */
401 }
402
403 EXCEPTION_DISPOSITION handle_exception(EXCEPTION_RECORD *exception_record,
404                                        struct lisp_exception_frame *exception_frame,
405                                        CONTEXT *context,
406                                        void *dc) /* FIXME: What's dc again? */
407 {
408
409     /* For EXCEPTION_ACCESS_VIOLATION only. */
410     void *fault_address = (void *)exception_record->ExceptionInformation[1];
411
412     if (exception_record->ExceptionCode == EXCEPTION_BREAKPOINT) {
413         /* Pick off sigtrap case first. */
414         return sigtrap_emulator(context, exception_frame);
415
416     } else if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
417                is_valid_lisp_addr(fault_address)) {
418         /* Pick off GC-related memory fault next. */
419         MEMORY_BASIC_INFORMATION mem_info;
420
421         if (!VirtualQuery(fault_address, &mem_info, sizeof mem_info)) {
422             fprintf(stderr, "VirtualQuery: 0x%lx.\n", GetLastError());
423             lose("handle_exception: VirtualQuery failure");
424         }
425
426         if (mem_info.State == MEM_RESERVE) {
427             /* First use new page, lets get some memory for it. */
428             if (!VirtualAlloc(mem_info.BaseAddress, os_vm_page_size,
429                               MEM_COMMIT, PAGE_EXECUTE_READWRITE)) {
430                 fprintf(stderr, "VirtualAlloc: 0x%lx.\n", GetLastError());
431                 lose("handle_exception: VirtualAlloc failure");
432
433             } else {
434                 /*
435                  * Now, if the page is supposedly write-protected and this
436                  * is a write, tell the gc that it's been hit.
437                  *
438                  * FIXME: Are we supposed to fall-through to the Lisp
439                  * exception handler if the gc doesn't take the wp violation?
440                  */
441                 if (exception_record->ExceptionInformation[0]) {
442                     int index = find_page_index(fault_address);
443                     if ((index != -1) && (page_table[index].write_protected)) {
444                         gencgc_handle_wp_violation(fault_address);
445                     }
446                 }
447                 return ExceptionContinueExecution;
448             }
449
450         } else if (gencgc_handle_wp_violation(fault_address)) {
451             /* gc accepts the wp violation, so resume where we left off. */
452             return ExceptionContinueExecution;
453         }
454
455         /* All else failed, drop through to the lisp-side exception handler. */
456     }
457
458     /*
459      * If we fall through to here then we need to either forward
460      * the exception to the lisp-side exception handler if it's
461      * set up, or drop to LDB.
462      */
463
464     if (internal_errors_enabled) {
465         /* exception_trampoline is defined in x86-assem.S. */
466         extern void exception_trampoline;
467
468         /*
469          * We're making the somewhat arbitrary decision that
470          * having internal errors enabled means that lisp has
471          * sufficient marbles to be able to handle exceptions.
472          *
473          * Exceptions aren't supposed to happen during cold
474          * init or reinit anyway.
475          */
476
477         /*
478          * We use the same mechanism as the sigtrap emulator above
479          * with just a couple changes. We obviously use a different
480          * trampoline and wrapper function, we kill out any live
481          * floating point exceptions, and we save off the exception
482          * record as well as the context.
483          */
484
485         /* Save off context and exception information */
486         memcpy(&exception_frame->context, context, sizeof(CONTEXT));
487         memcpy(&exception_frame->exception, exception_record, sizeof(EXCEPTION_RECORD));
488
489         /* Set up to activate trampoline when we return */
490         context->Eax = context->Eip;
491         context->Eip = (unsigned long)&exception_trampoline;
492
493         /* Make sure a floating-point trap doesn't kill us */
494         context->FloatSave.StatusWord &= ~0x3f;
495
496         /* And return */
497         return ExceptionContinueExecution;
498     }
499
500     fprintf(stderr, "Exception Code: 0x%lx.\n", exception_record->ExceptionCode);
501     fprintf(stderr, "Faulting IP: 0x%lx.\n", (DWORD)exception_record->ExceptionAddress);
502     if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
503         MEMORY_BASIC_INFORMATION mem_info;
504
505         if (VirtualQuery(fault_address, &mem_info, sizeof mem_info)) {
506             fprintf(stderr, "page status: 0x%lx.\n", mem_info.State);
507         }
508
509         fprintf(stderr, "Was writing: %ld, where: 0x%lx.\n",
510                 exception_record->ExceptionInformation[0],
511                 (DWORD)fault_address);
512     }
513
514     fflush(stderr);
515
516     fake_foreign_function_call(context);
517     monitor_or_something();
518
519     return ExceptionContinueSearch;
520 }
521
522 void handle_win32_exception_wrapper(void)
523 {
524     struct lisp_exception_frame *frame = find_our_seh_frame();
525     CONTEXT context;
526     EXCEPTION_RECORD exception_record;
527     lispobj context_sap;
528     lispobj exception_record_sap;
529
530     memcpy(&context, &frame->context, sizeof(CONTEXT));
531     memcpy(&exception_record, &frame->exception, sizeof(EXCEPTION_RECORD));
532
533     fake_foreign_function_call(&context);
534
535     /* Allocate the SAP objects while the "interrupts" are still
536      * disabled. */
537     context_sap = alloc_sap(&context);
538     exception_record_sap = alloc_sap(&exception_record);
539
540     funcall2(SymbolFunction(HANDLE_WIN32_EXCEPTION), context_sap,
541              exception_record_sap);
542
543     undo_fake_foreign_function_call(&context);
544
545     memcpy(&frame->context, &context, sizeof(CONTEXT));
546 }
547
548 void
549 wos_install_interrupt_handlers(struct lisp_exception_frame *handler)
550 {
551     handler->next_frame = get_seh_frame();
552     handler->handler = &handle_exception;
553     set_seh_frame(handler);
554 }
555
556 void bcopy(const void *src, void *dest, size_t n)
557 {
558     MoveMemory(dest, src, n);
559 }
560
561 /*
562  * The stubs below are replacements for the windows versions,
563  * which can -fail- when used in our memory spaces because they
564  * validate the memory spaces they are passed in a way that
565  * denies our exception handler a chance to run.
566  */
567
568 void *memmove(void *dest, const void *src, size_t n)
569 {
570     if (dest < src) {
571         int i;
572         for (i = 0; i < n; i++) *(((char *)dest)+i) = *(((char *)src)+i);
573     } else {
574         while (n--) *(((char *)dest)+n) = *(((char *)src)+n);
575     }
576     return dest;
577 }
578
579 void *memcpy(void *dest, const void *src, size_t n)
580 {
581     while (n--) *(((char *)dest)+n) = *(((char *)src)+n);
582     return dest;
583 }
584
585 char *dirname(char *path)
586 {
587     static char buf[PATH_MAX + 1];
588     size_t pathlen = strlen(path);
589     int i;
590
591     if (pathlen >= sizeof(buf)) {
592         lose("Pathname too long in dirname.\n");
593         return NULL;
594     }
595
596     strcpy(buf, path);
597     for (i = pathlen; i >= 0; --i) {
598         if (buf[i] == '/' || buf[i] == '\\') {
599             buf[i] = '\0';
600             break;
601         }
602     }
603
604     return buf;
605 }
606
607 /* This is a manually-maintained version of ldso_stubs.S. */
608
609 void scratch(void)
610 {
611     strerror(42);
612     asin(0);
613     acos(0);
614     sinh(0);
615     cosh(0);
616     hypot(0, 0);
617     write(0, 0, 0);
618     close(0);
619     rename(0,0);
620     getcwd(0,0);
621     dup(0);
622     LoadLibrary(0);
623     GetProcAddress(0, 0);
624     FreeLibrary(0);
625     mkdir(0);
626     isatty(0);
627     access(0,0);
628     GetLastError();
629     FormatMessageA(0, 0, 0, 0, 0, 0, 0);
630     _get_osfhandle(0);
631     ReadFile(0, 0, 0, 0, 0);
632     WriteFile(0, 0, 0, 0, 0);
633     PeekNamedPipe(0, 0, 0, 0, 0, 0);
634     FlushConsoleInputBuffer(0);
635     PeekConsoleInput(0, 0, 0, 0);
636     Sleep(0);
637 }
638
639 char *
640 os_get_runtime_executable_path()
641 {
642     char path[MAX_PATH + 1];
643     DWORD bufsize = sizeof(path);
644     DWORD size;
645
646     if ((size = GetModuleFileNameA(NULL, path, bufsize)) == 0)
647         return NULL;
648     else if (size == bufsize && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
649         return NULL;
650
651     return copied_string(path);
652 }
653
654 /* EOF */