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
|