From: Cyrus H. <sl...@us...> - 2007-03-03 00:42:10
|
Update of /cvsroot/sbcl/sbcl/src/runtime In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv22077/src/runtime Modified Files: darwin-dlshim.c darwin-os.c interrupt.c purify.c run-program.c x86-64-arch.c x86-64-assem.S x86-64-bsd-os.c Added Files: Config.x86-64-darwin x86-64-darwin-os.c x86-64-darwin-os.h Log Message: 1.0.3.16: experimental x86-64/darwin suport * fix sb-posix time structs to match headers on darwin * comment out mtime sb-posix test as this isn't working ATM * add UD2A trap stuff to x86-64 and corresponding word-imm support * remove bogus extern-alien-name in boxed_region fixups * add compiler parameters for Darwin * add x86-64 darwin config file * some type safety fixes (proper types) in darwin-dlshim.c * use setpgid on Darwin * add signal context support x86-64/darwin * report trap instead of si_code for trap_Error/trap_Cerror * unsigned -> unsigned long in purify.c * add mach exception handler support for x86-64/darwin * x86-64 assembly hacks to make darwin's assembler happy * update x86-64-bsd-os.c to suppot darwin and mach exceptions * add x86-64-darwin-os.c/h * update LDSO stubs for x86-64 darwin --- NEW FILE: Config.x86-64-darwin --- # -*- makefile -*- for the C-level run-time support for SBCL # This software is part of the SBCL system. See the README file for # more information. # # This software is derived from the CMU CL system, which was # written at Carnegie Mellon University and released into the # public domain. The software is in the public domain and is # provided with absolutely no warranty. See the COPYING and CREDITS # files for more information. CFLAGS = -g -Wall -O2 -fdollars-in-identifiers OS_SRC = bsd-os.c x86-64-bsd-os.c darwin-os.c x86-64-darwin-os.c darwin-dlshim.c darwin-langinfo.c OS_LIBS = -lSystem -lc -ldl ASSEM_SRC = x86-64-assem.S ldso-stubs.S ARCH_SRC = x86-64-arch.c LINKFLAGS += -arch x86_64 -dynamic -twolevel_namespace -bind_at_load -pagezero_size 0x100000 OS_LIBS += $(shell if grep LISP_FEATURE_SB_THREAD genesis/config.h \ > /dev/null 2>&1; \ then echo "-lpthread"; fi) CFLAGS += -arch x86_64 -fno-omit-frame-pointer -pagezero_size 0x100000 GC_SRC = gencgc.c # Nothing to do for after-grovel-headers. .PHONY: after-grovel-headers after-grovel-headers: --- NEW FILE: x86-64-darwin-os.c --- #ifdef LISP_FEATURE_SB_THREAD #include <architecture/i386/table.h> #include <i386/user_ldt.h> #include <mach/mach_init.h> #endif #include "thread.h" #include "validate.h" #include "runtime.h" #include "interrupt.h" #include "x86-64-darwin-os.h" #include "genesis/fdefn.h" #include <mach/mach.h> #include <mach/mach_error.h> #include <mach/mach_types.h> #include <mach/sync_policy.h> #include <mach/machine/thread_state.h> #include <mach/machine/thread_status.h> #include <sys/_types.h> #include <sys/ucontext.h> #include <pthread.h> #include <assert.h> #include <stdlib.h> #include <stdio.h> #ifdef LISP_FEATURE_SB_THREAD pthread_mutex_t mach_exception_lock = PTHREAD_MUTEX_INITIALIZER; #endif #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER kern_return_t mach_thread_init(mach_port_t thread_exception_port); void sigill_handler(int signal, siginfo_t *siginfo, void *void_context); void sigtrap_handler(int signal, siginfo_t *siginfo, void *void_context); void memory_fault_handler(int signal, siginfo_t *siginfo, void *void_context); /* exc_server handles mach exception messages from the kernel and * calls catch exception raise. We use the system-provided * mach_msg_server, which, I assume, calls exc_server in a loop. * */ extern boolean_t exc_server(); /* This executes in the faulting thread as part of the signal * emulation. It is passed a context with the uc_mcontext field * pointing to a valid block of memory. */ void build_fake_signal_context(struct ucontext *context, x86_thread_state64_t *thread_state, x86_float_state64_t *float_state) { pthread_sigmask(0, NULL, &context->uc_sigmask); context->uc_mcontext->ss = *thread_state; context->uc_mcontext->fs = *float_state; } /* This executes in the faulting thread as part of the signal * emulation. It is effectively the inverse operation from above. */ void update_thread_state_from_context(x86_thread_state64_t *thread_state, x86_float_state64_t *float_state, struct ucontext *context) { *thread_state = context->uc_mcontext->ss; *float_state = context->uc_mcontext->fs; pthread_sigmask(SIG_SETMASK, &context->uc_sigmask, NULL); } /* Modify a context to push new data on its stack. */ void push_context(u64 data, x86_thread_state64_t *context) { u64 *stack_pointer; stack_pointer = (u64*) context->rsp; *(--stack_pointer) = data; context->rsp = (u64) stack_pointer; } void align_context_stack(x86_thread_state64_t *context) { /* 16byte align the stack (provided that the stack is, as it * should be, 8byte aligned. */ while (context->rsp & 15) push_context(0, context); } /* Stack allocation starts with a context that has a mod-4 ESP value * and needs to leave a context with a mod-16 ESP that will restore * the old ESP value and other register state when activated. The * first part of this is the recovery trampoline, which loads ESP from * EBP, pops EBP, and returns. */ asm(".globl _stack_allocation_recover; .align 4; _stack_allocation_recover: mov %rbp, %rsp; pop %rsi; pop %rdi; pop \ %rdx; pop %rcx; pop %r8; pop %r9; pop %rbp; ret;"); void open_stack_allocation(x86_thread_state64_t *context) { void stack_allocation_recover(void); push_context(context->rip, context); push_context(context->rbp, context); push_context(context->r9, context); push_context(context->r8, context); push_context(context->rcx, context); push_context(context->rdx, context); push_context(context->rsi, context); push_context(context->rdi, context); context->rbp = context->rsp; context->rip = (u64) stack_allocation_recover; align_context_stack(context); } /* Stack allocation of data starts with a context with a mod-16 ESP * value and reserves some space on it by manipulating the ESP * register. */ void *stack_allocate(x86_thread_state64_t *context, size_t size) { /* round up size to 16byte multiple */ size = (size + 15) & -16; context->rsp = ((u64)context->rsp) - size; return (void *)context->rsp; } /* Arranging to invoke a C function is tricky, as we have to assume * cdecl calling conventions (caller removes args) and x86/darwin * alignment requirements. The simplest way to arrange this, * actually, is to open a new stack allocation. * WARNING!!! THIS DOES NOT PRESERVE REGISTERS! */ void call_c_function_in_context(x86_thread_state64_t *context, void *function, int nargs, ...) { va_list ap; int i; u64 *stack_pointer; /* Set up to restore stack on exit. */ open_stack_allocation(context); /* Have to keep stack 16byte aligned on x86/darwin. */ for (i = (1 & -nargs); i; i--) { push_context(0, context); } context->rsp = ((u64)context->rsp) - nargs * 8; stack_pointer = (u64 *)context->rsp; va_start(ap, nargs); if (nargs > 0) context->rdi = va_arg(ap, u64); if (nargs > 1) context->rsi = va_arg(ap, u64); if (nargs > 2) context->rdx = va_arg(ap, u64); if (nargs > 3) context->rcx = va_arg(ap, u64); if (nargs > 4) context->r8 = va_arg(ap, u64); if (nargs > 5) context->r9 = va_arg(ap, u64); for (i = 6; i < nargs; i++) { stack_pointer[i] = va_arg(ap, u64); } va_end(ap); push_context(context->rip, context); context->rip = (u64) function; } void signal_emulation_wrapper(x86_thread_state64_t *thread_state, x86_float_state64_t *float_state, int signal, siginfo_t *siginfo, void (*handler)(int, siginfo_t *, void *)) { /* CLH: FIXME **NOTE: HACK ALERT!** Ideally, we would allocate * context and regs on the stack as local variables, but this * causes problems for the lisp debugger. When it walks the stack * for a back trace, it sees the 1) address of the local variable * on the stack and thinks that is a frame pointer to a lisp * frame, and, 2) the address of the sap that we alloc'ed in * dynamic space and thinks that is a return address, so it, * heuristicly (and wrongly), chooses that this should be * interpreted as a lisp frame instead of as a C frame. * We can work around this in this case by os_validating the * context (and regs just for symmetry). */ struct ucontext *context; struct mcontext *regs; context = (struct ucontext*) os_validate(0, sizeof(struct ucontext)); regs = (struct mcontext*) os_validate(0, sizeof(struct mcontext)); context->uc_mcontext = regs; /* when BSD signals are fired, they mask they signals in sa_mask which always seem to be the blockable_sigset, for us, so we need to: 1) save the current sigmask 2) block blockable signals 3) call the signal handler 4) restore the sigmask */ build_fake_signal_context(context, thread_state, float_state); block_blockable_signals(); handler(signal, siginfo, context); update_thread_state_from_context(thread_state, float_state, context); os_invalidate((os_vm_address_t)context, sizeof(struct ucontext)); os_invalidate((os_vm_address_t)regs, sizeof(struct mcontext)); /* Trap to restore the signal context. */ asm volatile ("mov %0, %%rax; mov %1, %%rbx; .quad 0xffffffffffff0b0f" : : "r" (thread_state), "r" (float_state)); } #if defined DUMP_CONTEXT void dump_context(x86_thread_state64_t *context) { int i; u64 *stack_pointer; printf("rax: %08lx rcx: %08lx rdx: %08lx rbx: %08lx\n", context->rax, context->rcx, context->rdx, context->rbx); printf("rsp: %08lx rbp: %08lx rsi: %08lx rdi: %08lx\n", context->rsp, context->rbp, context->rsi, context->rdi); printf("rip: %08lx eflags: %08lx\n", context->rip, context->rflags); printf("cs: %04hx ds: %04hx es: %04hx " "ss: %04hx fs: %04hx gs: %04hx\n", context->cs, context->ds, context->rs, context->ss, context->fs, context->gs); stack_pointer = (u64 *)context->rsp; for (i = 0; i < 48; i+=4) { printf("%08x: %08x %08x %08x %08x\n", context->rsp + (i * 4), stack_pointer[i], stack_pointer[i+1], stack_pointer[i+2], stack_pointer[i+3]); } } #endif void control_stack_exhausted_handler(int signal, siginfo_t *siginfo, void *void_context) { os_context_t *context = arch_os_get_context(&void_context); arrange_return_to_lisp_function (context, SymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR)); } void undefined_alien_handler(int signal, siginfo_t *siginfo, void *void_context) { os_context_t *context = arch_os_get_context(&void_context); arrange_return_to_lisp_function (context, SymbolFunction(UNDEFINED_ALIEN_VARIABLE_ERROR)); } kern_return_t catch_exception_raise(mach_port_t exception_port, mach_port_t thread, mach_port_t task, exception_type_t exception, exception_data_t code_vector, mach_msg_type_number_t code_count) { kern_return_t ret; int signal; siginfo_t* siginfo; #ifdef LISP_FEATURE_SB_THREAD thread_mutex_lock(&mach_exception_lock); #endif x86_thread_state64_t thread_state; mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; x86_float_state64_t float_state; mach_msg_type_number_t float_state_count = x86_FLOAT_STATE64_COUNT; x86_exception_state64_t exception_state; mach_msg_type_number_t exception_state_count = x86_EXCEPTION_STATE64_COUNT; x86_thread_state64_t backup_thread_state; x86_thread_state64_t *target_thread_state; x86_float_state64_t *target_float_state; os_vm_address_t addr; struct thread *th = (struct thread*) exception_port; FSHOW((stderr,"/entering catch_exception_raise with exception: %d\n", exception)); switch (exception) { case EXC_BAD_ACCESS: signal = SIGBUS; ret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&thread_state, &thread_state_count); ret = thread_get_state(thread, x86_FLOAT_STATE64, (thread_state_t)&float_state, &float_state_count); ret = thread_get_state(thread, x86_EXCEPTION_STATE64, (thread_state_t)&exception_state, &exception_state_count); addr = (void*)exception_state.faultvaddr; /* note the os_context hackery here. When the signal handler returns, * it won't go back to what it was doing ... */ if(addr >= CONTROL_STACK_GUARD_PAGE(th) && addr < CONTROL_STACK_GUARD_PAGE(th) + os_vm_page_size) { /* We hit the end of the control stack: disable guard page * protection so the error handler has some headroom, protect the * previous page so that we can catch returns from the guard page * and restore it. */ protect_control_stack_guard_page_thread(0, th); protect_control_stack_return_guard_page_thread(1, th); backup_thread_state = thread_state; open_stack_allocation(&thread_state); /* Save thread state */ target_thread_state = stack_allocate(&thread_state, sizeof(*target_thread_state)); (*target_thread_state) = backup_thread_state; /* Save float state */ target_float_state = stack_allocate(&thread_state, sizeof(*target_float_state)); (*target_float_state) = float_state; /* Set up siginfo */ siginfo = stack_allocate(&thread_state, sizeof(*siginfo)); /* what do we need to put in our fake siginfo? It looks like * the x86 code only uses si_signo and si_adrr. */ siginfo->si_signo = signal; siginfo->si_addr = (void*)exception_state.faultvaddr; call_c_function_in_context(&thread_state, signal_emulation_wrapper, 5, target_thread_state, target_float_state, signal, siginfo, control_stack_exhausted_handler); } else if(addr >= CONTROL_STACK_RETURN_GUARD_PAGE(th) && addr < CONTROL_STACK_RETURN_GUARD_PAGE(th) + os_vm_page_size) { /* We're returning from the guard page: reprotect it, and * unprotect this one. This works even if we somehow missed * the return-guard-page, and hit it on our way to new * exhaustion instead. */ protect_control_stack_guard_page_thread(1, th); protect_control_stack_return_guard_page_thread(0, th); } else if (addr >= undefined_alien_address && addr < undefined_alien_address + os_vm_page_size) { backup_thread_state = thread_state; open_stack_allocation(&thread_state); /* Save thread state */ target_thread_state = stack_allocate(&thread_state, sizeof(*target_thread_state)); (*target_thread_state) = backup_thread_state; target_float_state = stack_allocate(&thread_state, sizeof(*target_float_state)); (*target_float_state) = float_state; /* Set up siginfo */ siginfo = stack_allocate(&thread_state, sizeof(*siginfo)); /* what do we need to put in our fake siginfo? It looks like * the x86 code only uses si_signo and si_adrr. */ siginfo->si_signo = signal; siginfo->si_addr = (void*)exception_state.faultvaddr; call_c_function_in_context(&thread_state, signal_emulation_wrapper, 5, target_thread_state, target_float_state, signal, siginfo, undefined_alien_handler); } else { backup_thread_state = thread_state; open_stack_allocation(&thread_state); /* Save thread state */ target_thread_state = stack_allocate(&thread_state, sizeof(*target_thread_state)); (*target_thread_state) = backup_thread_state; target_float_state = stack_allocate(&thread_state, sizeof(*target_float_state)); (*target_float_state) = float_state; /* Set up siginfo */ siginfo = stack_allocate(&thread_state, sizeof(*siginfo)); /* what do we need to put in our fake siginfo? It looks like * the x86 code only uses si_signo and si_adrr. */ siginfo->si_signo = signal; siginfo->si_addr = (void*)exception_state.faultvaddr; call_c_function_in_context(&thread_state, signal_emulation_wrapper, 5, target_thread_state, target_float_state, signal, siginfo, memory_fault_handler); } ret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&thread_state, thread_state_count); ret = thread_set_state(thread, x86_FLOAT_STATE64, (thread_state_t)&float_state, float_state_count); #ifdef LISP_FEATURE_SB_THREAD thread_mutex_unlock(&mach_exception_lock); #endif return KERN_SUCCESS; case EXC_BAD_INSTRUCTION: ret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&thread_state, &thread_state_count); ret = thread_get_state(thread, x86_FLOAT_STATE64, (thread_state_t)&float_state, &float_state_count); ret = thread_get_state(thread, x86_EXCEPTION_STATE64, (thread_state_t)&exception_state, &exception_state_count); if (0xffffffffffff0b0f == *((u64 *)thread_state.rip)) { /* fake sigreturn. */ /* When we get here, thread_state.rax is a pointer to a * thread_state to restore. */ /* thread_state = *((thread_state_t *)thread_state.rax); */ ret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t) thread_state.rax, /* &thread_state, */ thread_state_count); ret = thread_set_state(thread, x86_FLOAT_STATE64, (thread_state_t) thread_state.rbx, /* &thread_state, */ float_state_count); } else { backup_thread_state = thread_state; open_stack_allocation(&thread_state); /* Save thread state */ target_thread_state = stack_allocate(&thread_state, sizeof(*target_thread_state)); (*target_thread_state) = backup_thread_state; target_float_state = stack_allocate(&thread_state, sizeof(*target_float_state)); (*target_float_state) = float_state; /* Set up siginfo */ siginfo = stack_allocate(&thread_state, sizeof(*siginfo)); /* what do we need to put in our fake siginfo? It looks like * the x86 code only uses si_signo and si_adrr. */ if (*((unsigned short *)target_thread_state->rip) == 0x0b0f) { signal = SIGTRAP; siginfo->si_signo = signal; siginfo->si_addr = (void*)exception_state.faultvaddr; target_thread_state->rip += 2; call_c_function_in_context(&thread_state, signal_emulation_wrapper, 5, target_thread_state, target_float_state, signal, siginfo, sigtrap_handler); } else { signal = SIGILL; siginfo->si_signo = signal; siginfo->si_addr = (void*)exception_state.faultvaddr; call_c_function_in_context(&thread_state, signal_emulation_wrapper, 5, target_thread_state, target_float_state, signal, siginfo, sigill_handler); } ret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&thread_state, thread_state_count); ret = thread_set_state(thread, x86_FLOAT_STATE64, (thread_state_t)&float_state, float_state_count); } #ifdef LISP_FEATURE_SB_THREAD thread_mutex_unlock(&mach_exception_lock); #endif return KERN_SUCCESS; default: #ifdef LISP_FEATURE_SB_THREAD thread_mutex_unlock(&mach_exception_lock); #endif return KERN_INVALID_RIGHT; } } void * mach_exception_handler(void *port) { mach_msg_server(exc_server, 2048, (mach_port_t) port, 0); /* mach_msg_server should never return, but it should dispatch mach * exceptions to our catch_exception_raise function */ abort(); } /* Sets up the thread that will listen for mach exceptions. note that the exception handlers will be run on this thread. This is different from the BSD-style signal handling situation in which the signal handlers run in the relevant thread directly. */ mach_port_t mach_exception_handler_port_set = MACH_PORT_NULL; pthread_t setup_mach_exception_handling_thread() { kern_return_t ret; pthread_t mach_exception_handling_thread = NULL; pthread_attr_t attr; /* allocate a mach_port for this process */ ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &mach_exception_handler_port_set); /* create the thread that will receive the mach exceptions */ FSHOW((stderr, "Creating mach_exception_handler thread!\n")); pthread_attr_init(&attr); pthread_create(&mach_exception_handling_thread, &attr, mach_exception_handler, (void*) mach_exception_handler_port_set); pthread_attr_destroy(&attr); return mach_exception_handling_thread; } /* tell the kernel that we want EXC_BAD_ACCESS exceptions sent to the exception port (which is being listened to do by the mach exception handling thread). */ kern_return_t mach_thread_init(mach_port_t thread_exception_port) { kern_return_t ret; /* allocate a named port for the thread */ FSHOW((stderr, "Allocating mach port %x\n", thread_exception_port)); ret = mach_port_allocate_name(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, thread_exception_port); if (ret) { lose("mach_port_allocate_name failed with return_code %d\n", ret); } /* establish the right for the thread_exception_port to send messages */ ret = mach_port_insert_right(mach_task_self(), thread_exception_port, thread_exception_port, MACH_MSG_TYPE_MAKE_SEND); if (ret) { lose("mach_port_insert_right failed with return_code %d\n", ret); } ret = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION, thread_exception_port, EXCEPTION_DEFAULT, THREAD_STATE_NONE); if (ret) { lose("thread_set_exception_port failed with return_code %d\n", ret); } ret = mach_port_move_member(mach_task_self(), thread_exception_port, mach_exception_handler_port_set); if (ret) { lose("mach_port_ failed with return_code %d\n", ret); } return ret; } void setup_mach_exceptions() { setup_mach_exception_handling_thread(); mach_thread_init(THREAD_STRUCT_TO_EXCEPTION_PORT(all_threads)); } pid_t mach_fork() { pid_t pid = fork(); if (pid == 0) { setup_mach_exceptions(); return pid; } else { return pid; } } #endif --- NEW FILE: x86-64-darwin-os.h --- #ifndef _X86_64_DARWIN_OS_H #define _X86_64_DARWIN_OS_H #include "darwin-os.h" typedef register_t os_context_register_t; static inline os_context_t *arch_os_get_context(void **void_context) { return (os_context_t *) *void_context; } #define CONTEXT_ADDR_FROM_STEM(stem) &context->uc_mcontext->ss.stem #define DARWIN_FIX_CONTEXT(context) #endif /* _X86_64_DARWIN_OS_H */ Index: darwin-dlshim.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/darwin-dlshim.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- darwin-dlshim.c 31 Aug 2006 07:48:06 -0000 1.1 +++ darwin-dlshim.c 3 Mar 2007 00:42:02 -0000 1.2 @@ -32,7 +32,7 @@ static char dl_self; /* I'm going to abuse this */ static int callback_count; -static struct mach_header* last_header; +static const struct mach_header* last_header; #define DLSYM_ERROR 1 #define DLOPEN_ERROR 2 @@ -40,7 +40,7 @@ static int last_error = 0; void -dlshim_image_callback(struct mach_header* ptr, unsigned long phooey) +dlshim_image_callback(const struct mach_header* ptr, intptr_t phooey) { callback_count++; last_header = ptr; @@ -159,7 +159,7 @@ NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); } if (NSIsSymbolNameDefinedInImage(img, "__init")) { - NSSymbol* initsymbol; + NSSymbol initsymbol; void (*initfunc) (void); initsymbol = NSLookupSymbolInImage(img, "__init", 0); initfunc = NSAddressOfSymbol(initsymbol); @@ -204,7 +204,7 @@ { if (handle == &dl_self) { if (NSIsSymbolNameDefined(symbol)) { - NSSymbol* retsym; + NSSymbol retsym; retsym = NSLookupAndBindSymbol(symbol); return NSAddressOfSymbol(retsym); } else { @@ -213,7 +213,7 @@ } } else { if (NSIsSymbolNameDefinedInImage(handle, symbol)) { - NSSymbol* retsym; + NSSymbol retsym; retsym = NSLookupSymbolInImage(handle, symbol, 0); return NSAddressOfSymbol(retsym); } else { Index: darwin-os.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/darwin-os.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- darwin-os.c 3 Jun 2006 20:26:52 -0000 1.2 +++ darwin-os.c 3 Mar 2007 00:42:02 -0000 1.3 @@ -28,7 +28,7 @@ os_get_runtime_executable_path() { char path[PATH_MAX + 1]; - uint32_t size = sizeof(path); + size_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == -1) return NULL; Index: interrupt.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/interrupt.c,v retrieving revision 1.120 retrieving revision 1.121 diff -u -d -r1.120 -r1.121 --- interrupt.c 26 Dec 2006 23:10:24 -0000 1.120 +++ interrupt.c 3 Mar 2007 00:42:02 -0000 1.121 @@ -747,7 +747,7 @@ struct thread *thread=arch_os_get_current_thread(); sigset_t ss; - if ((arch_pseudo_atomic_atomic(context) || + if ((arch_pseudo_atomic_atomic(context) || SymbolValue(GC_INHIBIT,thread) != NIL)) { SetSymbolValue(STOP_FOR_GC_PENDING,T,thread); if (SymbolValue(GC_INHIBIT,thread) == NIL) @@ -937,6 +937,7 @@ #elif defined(LISP_FEATURE_X86_64) u64 *sp=(u64 *)*os_context_register_addr(context,reg_RSP); + /* return address for call_into_lisp: */ *(sp-18) = (u64)post_signal_tramp; Index: purify.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/purify.c,v retrieving revision 1.65 retrieving revision 1.66 diff -u -d -r1.65 -r1.66 --- purify.c 6 Dec 2006 08:04:22 -0000 1.65 +++ purify.c 3 Mar 2007 00:42:03 -0000 1.66 @@ -657,7 +657,7 @@ void *constants_start_addr, *constants_end_addr; void *code_start_addr, *code_end_addr; lispobj fixups = NIL; - unsigned displacement = (unsigned)new_code - (unsigned)old_code; + unsigned long displacement = (unsigned long)new_code - (unsigned long)old_code; struct vector *fixups_vector; ncode_words = fixnum_value(new_code->code_size); @@ -703,21 +703,21 @@ for (i=0; i<length; i++) { unsigned offset = fixups_vector->data[i]; /* Now check the current value of offset. */ - unsigned old_value = - *(unsigned *)((unsigned)code_start_addr + offset); + unsigned long old_value = + *(unsigned long *)((unsigned long)code_start_addr + offset); /* If it's within the old_code object then it must be an * absolute fixup (relative ones are not saved) */ - if ((old_value>=(unsigned)old_code) - && (old_value<((unsigned)old_code + nwords * N_WORD_BYTES))) + if ((old_value>=(unsigned long)old_code) + && (old_value<((unsigned long)old_code + nwords * N_WORD_BYTES))) /* So add the dispacement. */ - *(unsigned *)((unsigned)code_start_addr + offset) = old_value + *(unsigned long *)((unsigned long)code_start_addr + offset) = old_value + displacement; else /* It is outside the old code object so it must be a relative * fixup (absolute fixups are not saved). So subtract the * displacement. */ - *(unsigned *)((unsigned)code_start_addr + offset) = old_value + *(unsigned long *)((unsigned long)code_start_addr + offset) = old_value - displacement; } } Index: run-program.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/run-program.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- run-program.c 18 Aug 2006 13:09:58 -0000 1.14 +++ run-program.c 3 Mar 2007 00:42:03 -0000 1.15 @@ -67,6 +67,8 @@ /* Put us in our own process group. */ #if defined(hpux) setsid(); +#elif defined(LISP_FEATURE_DARWIN) + setpgid(0, getpid()); #elif defined(SVR4) || defined(__linux__) || defined(__osf__) setpgrp(); #else Index: x86-64-arch.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/x86-64-arch.c,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- x86-64-arch.c 15 Dec 2006 02:57:53 -0000 1.16 +++ x86-64-arch.c 3 Mar 2007 00:42:03 -0000 1.17 @@ -62,6 +62,8 @@ return &context->uc_mcontext.gregs[17]; #elif defined __FreeBSD__ return &context->uc_mcontext.mc_rflags; +#elif defined LISP_FEATURE_DARWIN + return &context->uc_mcontext->ss.rflags; #elif defined __OpenBSD__ return &context->sc_eflags; #else @@ -270,8 +272,8 @@ case trap_Error: case trap_Cerror: - FSHOW((stderr, "<trap error/cerror %d>\n", code)); - interrupt_internal_error(signal, info, context, code==trap_Cerror); + FSHOW((stderr, "<trap error/cerror %d>\n", trap)); + interrupt_internal_error(signal, info, context, trap==trap_Cerror); break; case trap_Breakpoint: @@ -301,9 +303,20 @@ } } -static void +void sigill_handler(int signal, siginfo_t *siginfo, void *void_context) { os_context_t *context = (os_context_t*)void_context; + + /* Triggering SIGTRAP using int3 is unreliable on OS X/x86, so + * we need to use illegal instructions for traps. + */ +#if defined(LISP_FEATURE_DARWIN) && !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) + if (*((unsigned short *)*os_context_pc_addr(context)) == 0x0b0f) { + *os_context_pc_addr(context) += 2; + return sigtrap_handler(signal, siginfo, void_context); + } +#endif + fake_foreign_function_call(context); lose("fake_foreign_function_call fell through"); } @@ -373,8 +386,11 @@ * OS I haven't tested on?) and we have to go back to the old CMU * CL way, I hope there will at least be a comment to explain * why.. -- WHN 2001-06-07 */ +#if !defined(LISP_FEATURE_MACH_EXCEPTION_HANDLER) undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler); undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler); +#endif + #ifdef X86_64_SIGFPE_FIXUP undoably_install_low_level_interrupt_handler(SIGFPE, sigfpe_handler); #endif Index: x86-64-assem.S =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/x86-64-assem.S,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- x86-64-assem.S 6 Oct 2006 10:54:16 -0000 1.12 +++ x86-64-assem.S 3 Mar 2007 00:42:03 -0000 1.13 @@ -14,6 +14,7 @@ */ #define LANGUAGE_ASSEMBLY +#include "genesis/config.h" #include "validate.h" #include "sbcl.h" #include "genesis/closure.h" @@ -43,9 +44,52 @@ #define align_16byte 4 #endif +/* + * The assembler used for win32 doesn't like .type or .size directives, + * so we want to conditionally kill them out. So let's wrap them in macros + * that are defined to be no-ops on win32. Hopefully this still works on + * other platforms. + */ +#if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN) +#define TYPE(name) .type name,@function +#define SIZE(name) .size name,.-name +#define DOLLAR(name) $(name) +#else +#define TYPE(name) +#define SIZE(name) +#endif + +/* + * x86/darwin (as of MacOS X 10.4.5) doesn't reliably fire signal + * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have + * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or + * 0F 0B in low-endian notation, that causes SIGILL to fire. We check + * for this instruction in the SIGILL handler and if we see it, we + * advance the EIP by two bytes to skip over ud2 instruction and + * call sigtrap_handler. */ +#if defined(LISP_FEATURE_DARWIN) +#define TRAP ud2 +#else +#define TRAP int3 +#endif + +/* + * More Apple assembler hacks + */ + +#if defined(LISP_FEATURE_DARWIN) +/* global symbol x86-64 sym(%rip) hack:*/ +#define GSYM(name) name(%rip) +#define END() +#else +#define GSYM(name) $name +#define END() .end +#endif + + .text - .global GNAME(foreign_function_call_active) - .global GNAME(all_threads) + .globl GNAME(all_threads) + /* From lower to higher-numbered addresses, the stack contains @@ -58,13 +102,12 @@ */ .text .align align_16byte,0x90 - .global GNAME(call_into_c) - .type GNAME(call_into_c),@function + .globl GNAME(call_into_c) + TYPE(GNAME(call_into_c)) GNAME(call_into_c): /* ABI requires that the direction flag be clear on function * entry and exit. */ cld - push %rbp # Save old frame pointer. mov %rsp,%rbp # Establish new frame. @@ -81,12 +124,12 @@ mov %rbp,%rsp pop %rbp ret - .size GNAME(call_into_c), . - GNAME(call_into_c) + SIZE(GNAME(call_into_c)) .text - .global GNAME(call_into_lisp_first_time) - .type GNAME(call_into_lisp_first_time),@function + .globl GNAME(call_into_lisp_first_time) + TYPE(GNAME(call_into_lisp_first_time)) /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when * the stack changes. We don't worry too much about saving registers @@ -97,17 +140,17 @@ GNAME(call_into_lisp_first_time): push %rbp # Save old frame pointer. mov %rsp,%rbp # Establish new frame. - mov %rsp,ALIEN_STACK + SYMBOL_VALUE_OFFSET - mov GNAME(all_threads),%rax - mov THREAD_CONTROL_STACK_START_OFFSET(%rax) ,%rsp + mov %rsp,ALIEN_STACK + SYMBOL_VALUE_OFFSET + movq GSYM(GNAME(all_threads)),%rax + mov THREAD_CONTROL_STACK_START_OFFSET(%rax) ,%rsp /* don't think too hard about what happens if we get interrupted * here */ - add $THREAD_CONTROL_STACK_SIZE-16,%rsp + add $(THREAD_CONTROL_STACK_SIZE)-16,%rsp jmp Lstack .text - .global GNAME(call_into_lisp) - .type GNAME(call_into_lisp),@function + .globl GNAME(call_into_lisp) + TYPE(GNAME(call_into_lisp)) /* * amd64 calling convention: C expects that @@ -194,49 +237,49 @@ /* return value is already in rax where lisp expects it */ leave ret - .size GNAME(call_into_lisp), . - GNAME(call_into_lisp) + SIZE(GNAME(call_into_lisp)) /* support for saving and restoring the NPX state from C */ .text - .global GNAME(fpu_save) - .type GNAME(fpu_save),@function + .globl GNAME(fpu_save) + TYPE(GNAME(fpu_save)) .align 2,0x90 GNAME(fpu_save): mov 4(%rsp),%rax fnsave (%rax) # Save the NPX state. (resets NPX) ret - .size GNAME(fpu_save),.-GNAME(fpu_save) + SIZE(GNAME(fpu_save)) - .global GNAME(fpu_restore) - .type GNAME(fpu_restore),@function + .globl GNAME(fpu_restore) + TYPE(GNAME(fpu_restore)) .align 2,0x90 GNAME(fpu_restore): mov 4(%rsp),%rax frstor (%rax) # Restore the NPX state. ret - .size GNAME(fpu_restore),.-GNAME(fpu_restore) + SIZE(GNAME(fpu_restore)) /* * the undefined-function trampoline */ .text .align align_8byte,0x90 - .global GNAME(undefined_tramp) - .type GNAME(undefined_tramp),@function + .globl GNAME(undefined_tramp) + TYPE(GNAME(undefined_tramp)) GNAME(undefined_tramp): - int3 + TRAP .byte trap_Error .byte 2 .byte UNDEFINED_FUN_ERROR .byte sc_DescriptorReg # eax in the Descriptor-reg SC ret - .size GNAME(undefined_tramp), .-GNAME(undefined_tramp) + SIZE(GNAME(undefined_tramp)) .text .align align_8byte,0x90 - .global GNAME(alloc_tramp) - .type GNAME(alloc_tramp),@function + .globl GNAME(alloc_tramp) + TYPE(GNAME(alloc_tramp)) GNAME(alloc_tramp): push %rbp # Save old frame pointer. mov %rsp,%rbp # Establish new frame. @@ -250,7 +293,7 @@ push %r10 push %r11 mov 16(%rbp),%rdi - call alloc + call GNAME(alloc) mov %rax,16(%rbp) pop %r11 pop %r10 @@ -263,7 +306,7 @@ pop %rax pop %rbp ret - .size GNAME(alloc_tramp),.-GNAME(alloc_tramp) + SIZE(GNAME(alloc_tramp)) /* @@ -271,8 +314,8 @@ */ .text .align align_8byte,0x90 - .global GNAME(closure_tramp) - .type GNAME(closure_tramp),@function + .globl GNAME(closure_tramp) + TYPE(GNAME(closure_tramp)) GNAME(closure_tramp): mov FDEFN_FUN_OFFSET(%rax),%rax /* FIXME: The '*' after "jmp" in the next line is from PVE's @@ -282,24 +325,27 @@ * right. It would be good to find a way to force the flow of * control through here to test it. */ jmp *CLOSURE_FUN_OFFSET(%rax) - .size GNAME(closure_tramp), .-GNAME(closure_tramp) + SIZE(GNAME(closure_tramp)) .text .align align_8byte,0x90 - .global GNAME(funcallable_instance_tramp) - .type GNAME(funcallable_instance_tramp),@function -GNAME(funcallable_instance_tramp): + .globl GNAME(funcallable_instance_tramp) +#if !defined(LISP_FEATURE_DARWIN) + .type GNAME(funcallable_instance_tramp),@function +#endif + GNAME(funcallable_instance_tramp): mov FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(%rax),%rax /* KLUDGE: on this platform, whatever kind of function is in %rax * now, the first word of it contains the address to jump to. */ jmp *CLOSURE_FUN_OFFSET(%rax) +#if !defined(LISP_FEATURE_DARWIN) .size GNAME(funcallable_instance_tramp), .-GNAME(funcallable_instance_tramp) - +#endif /* * fun-end breakpoint magic */ .text - .global GNAME(fun_end_breakpoint_guts) + .globl GNAME(fun_end_breakpoint_guts) .align align_8byte GNAME(fun_end_breakpoint_guts): /* Multiple Value return */ @@ -310,32 +356,36 @@ mov %rsp,%rbx # Setup ebx - the ofp. sub $8,%rsp # Allocate one stack slot for the return value mov $8,%rcx # Setup ecx for one return value. +#if defined(LISP_FEATURE_DARWIN) + mov GSYM(NIL),%rdi # default second value + mov GSYM(NIL),%rsi # default third value +#else mov $NIL,%rdi # default second value mov $NIL,%rsi # default third value - +#endif multiple_value_return: - .global GNAME(fun_end_breakpoint_trap) + .globl GNAME(fun_end_breakpoint_trap) GNAME(fun_end_breakpoint_trap): - int3 + TRAP .byte trap_FunEndBreakpoint hlt # We should never return here. - .global GNAME(fun_end_breakpoint_end) + .globl GNAME(fun_end_breakpoint_end) GNAME(fun_end_breakpoint_end): - .global GNAME(do_pending_interrupt) - .type GNAME(do_pending_interrupt),@function + .globl GNAME(do_pending_interrupt) + TYPE(GNAME(do_pending_interrupt)) .align align_8byte,0x90 GNAME(do_pending_interrupt): - int3 + TRAP .byte trap_PendingInterrupt ret - .size GNAME(do_pending_interrupt),.-GNAME(do_pending_interrupt) + SIZE(GNAME(do_pending_interrupt)) .globl GNAME(post_signal_tramp) - .type GNAME(post_signal_tramp),@function + TYPE(GNAME(post_signal_tramp)) .align align_8byte,0x90 GNAME(post_signal_tramp): /* this is notionally the second half of a function whose first half @@ -359,12 +409,12 @@ popfq leave ret - .size GNAME(post_signal_tramp),.-GNAME(post_signal_tramp) + SIZE(GNAME(post_signal_tramp)) .text .align align_8byte,0x90 - .global GNAME(fast_bzero) - .type GNAME(fast_bzero),@function + .globl GNAME(fast_bzero) + TYPE(GNAME(fast_bzero)) GNAME(fast_bzero): /* A fast routine for zero-filling blocks of memory that are @@ -376,7 +426,7 @@ movups %xmm7, -16(%rsp) /* Save XMM register */ xorps %xmm7, %xmm7 /* Zero the XMM register */ jmp Lloop - .align 16 + .align align_16byte Lloop: /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the @@ -399,6 +449,6 @@ * since it's likely to be used immediately. */ Lend: ret - .size GNAME(fast_bzero), .-GNAME(fast_bzero) + SIZE(GNAME(fast_bzero)) - .end + END() Index: x86-64-bsd-os.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/x86-64-bsd-os.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- x86-64-bsd-os.c 15 Dec 2006 02:57:53 -0000 1.1 +++ x86-64-bsd-os.c 3 Mar 2007 00:42:03 -0000 1.2 @@ -8,6 +8,12 @@ #include <machine/fpu.h> #endif +#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER +#include <mach/mach.h> + +kern_return_t mach_thread_init(mach_port_t thread_exception_port); +#endif + /* KLUDGE: There is strong family resemblance in the signal context * stuff in FreeBSD and OpenBSD, but in detail they're different in * almost every line of code. It would be nice to find some way to @@ -19,7 +25,7 @@ * entails; unfortunately, currently the situation is worse, not * better, than in the above paragraph. */ -#if defined(LISP_FEATURE_FREEBSD) +#if defined(LISP_FEATURE_FREEBSD) || defined(LISP_FEATURE_DARWIN) os_context_register_t * os_context_register_addr(os_context_t *context, int offset) { @@ -85,6 +91,11 @@ #ifdef LISP_FEATURE_SB_THREAD pthread_setspecific(specials,thread); #endif + +#ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER + mach_thread_init(THREAD_STRUCT_TO_EXCEPTION_PORT(thread)); +#endif + #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK /* Signal handlers are run on the control stack, so if it is exhausted * we had better use an alternate stack for whatever signal tells us |