--- /dev/null
+/* Fault handler information. MacOSX version.
+Copyright (C) 1993-1999, 2002-2003 Bruno Haible <clisp.org at bruno>
+Copyright (C) 2003 Paolo Bonzini <gnu.org at bonzini>
+
+Used under BSD license with permission from Paolo Bonzini and Bruno Haible,
+2005-03-10 */
+
+#ifdef __APPLE__
+
+#include "mach_signal.h"
+
+/* The following sources were used as a *reference* for this exception handling
+ code:
+ 1. Apple's mach/xnu documentation
+ 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
+ omnigroup's macosx-dev list.
+ www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html */
+
+/* The exception port on which our thread listens. */
+static mach_port_t our_exception_port;
+
+/* Communication area for the exception state and thread state. */
+static SIGSEGV_THREAD_STATE_TYPE save_thread_state;
+
+/* A handler that is called in the faulting thread. It terminates the thread. */
+static void
+terminating_handler ()
+{
+ /* Dump core. */
+ raise (SIGSEGV);
+
+ /* Seriously. */
+ abort ();
+}
+
+
+/* Handle an exception by invoking the user's fault handler and/or forwarding
+ the duty to the previously installed handlers. */
+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,
+ mach_msg_type_number_t code_count)
+{
+#ifdef SIGSEGV_EXC_STATE_TYPE
+ SIGSEGV_EXC_STATE_TYPE exc_state;
+#endif
+ SIGSEGV_THREAD_STATE_TYPE thread_state;
+ mach_msg_type_number_t state_count;
+ unsigned long addr;
+ unsigned long sp;
+
+ /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_get_state.html. */
+#ifdef SIGSEGV_EXC_STATE_TYPE
+ state_count = SIGSEGV_EXC_STATE_COUNT;
+ if (thread_get_state (thread, SIGSEGV_EXC_STATE_FLAVOR,
+ (void *) &exc_state, &state_count)
+ != KERN_SUCCESS)
+ {
+ /* The thread is supposed to be suspended while the exception handler
+ is called. This shouldn't fail. */
+ return KERN_FAILURE;
+ }
+#endif
+
+ state_count = SIGSEGV_THREAD_STATE_COUNT;
+ if (thread_get_state (thread, SIGSEGV_THREAD_STATE_FLAVOR,
+ (void *) &thread_state, &state_count)
+ != KERN_SUCCESS)
+ {
+ /* The thread is supposed to be suspended while the exception handler
+ is called. This shouldn't fail. */
+ return KERN_FAILURE;
+ }
+
+ addr = (unsigned long) (SIGSEGV_FAULT_ADDRESS (thread_state, exc_state));
+ sp = (unsigned long) (SIGSEGV_STACK_POINTER (thread_state));
+
+ /* Got the thread's state. Now extract the address that caused the
+ fault and invoke the user's handler. */
+ save_thread_state = thread_state;
+
+ /* If the fault address is near the stack pointer, it's a stack overflow.
+ Otherwise, treat it like a normal SIGSEGV. */
+ SIGSEGV_PROGRAM_COUNTER (thread_state) = (unsigned long) terminating_handler;
+
+ /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_set_state.html. */
+ if (thread_set_state (thread, SIGSEGV_THREAD_STATE_FLAVOR,
+ (void *) &thread_state, state_count)
+ != KERN_SUCCESS)
+ {
+ return KERN_FAILURE;
+ }
+ return KERN_SUCCESS;
+}
+
+
+/* The main function of the thread listening for exceptions. */
+static void *
+mach_exception_thread (void *arg)
+{
+ for (;;)
+ {
+ /* These two structures contain some private kernel data. We don't need
+ to access any of it so we don't bother defining a proper struct. The
+ correct definitions are in the xnu source code. */
+ /* Buffer for a message to be received. */
+ struct
+ {
+ mach_msg_header_t head;
+ mach_msg_body_t msgh_body;
+ char data[1024];
+ }
+ msg;
+ /* Buffer for a reply message. */
+ struct
+ {
+ mach_msg_header_t head;
+ char data[1024];
+ }
+ reply;
+
+ mach_msg_return_t retval;
+
+ /* Wait for a message on the exception port. */
+ retval = mach_msg (&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0,
+ sizeof (msg), our_exception_port,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (retval != MACH_MSG_SUCCESS)
+ {
+ abort ();
+ }
+
+ /* Handle the message: Call exc_server, which will call
+ catch_exception_raise and produce a reply message. */
+ exc_server (&msg.head, &reply.head);
+
+ /* Send the reply. */
+ if (mach_msg (&reply.head, MACH_SEND_MSG, reply.head.msgh_size,
+ 0, MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)
+ != MACH_MSG_SUCCESS)
+ {
+ abort ();
+ }
+ }
+}
+
+
+/* Initialize the Mach exception handler thread.
+ Return 0 if OK, -1 on error. */
+int mach_initialize ()
+{
+ mach_port_t self;
+ exception_mask_t mask;
+ pthread_attr_t attr;
+ pthread_t thread;
+
+ self = mach_task_self ();
+
+ /* Allocate a port on which the thread shall listen for exceptions. */
+ if (mach_port_allocate (self, MACH_PORT_RIGHT_RECEIVE, &our_exception_port)
+ != KERN_SUCCESS)
+ return -1;
+
+ /* See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_port_insert_right.html. */
+ if (mach_port_insert_right (self, our_exception_port, our_exception_port,
+ MACH_MSG_TYPE_MAKE_SEND)
+ != KERN_SUCCESS)
+ return -1;
+
+ /* The exceptions we want to catch. Only EXC_BAD_ACCESS is interesting
+ for us (see above in function catch_exception_raise). */
+ mask = EXC_MASK_BAD_ACCESS;
+
+ /* Create the thread listening on the exception port. */
+ if (pthread_attr_init (&attr) != 0)
+ return -1;
+ if (pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED) != 0)
+ return -1;
+ if (pthread_create (&thread, &attr, mach_exception_thread, NULL) != 0)
+ return -1;
+ pthread_attr_destroy (&attr);
+
+ /* Replace the exception port info for these exceptions with our own.
+ Note that we replace the exception port for the entire task, not only
+ for a particular thread. This has the effect that when our exception
+ port gets the message, the thread specific exception port has already
+ been asked, and we don't need to bother about it.
+ See http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/task_set_exception_ports.html. */
+ if (task_set_exception_ports (self, mask, our_exception_port,
+ EXCEPTION_DEFAULT, MACHINE_THREAD_STATE)
+ != KERN_SUCCESS)
+ return -1;
+
+ return 0;
+}
+
+#endif
--- /dev/null
+#ifdef __APPLE__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/thread_status.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
+
+/* For MacOSX. */
+#ifndef SS_DISABLE
+#define SS_DISABLE SA_DISABLE
+#endif
+
+/* This is not defined in any header, although documented. */
+
+/* http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/exc_server.html says:
+ The exc_server function is the MIG generated server handling function
+ to handle messages from the kernel relating to the occurrence of an
+ exception in a thread. Such messages are delivered to the exception port
+ set via thread_set_exception_ports or task_set_exception_ports. When an
+ exception occurs in a thread, the thread sends an exception message to its
+ exception port, blocking in the kernel waiting for the receipt of a reply.
+ The exc_server function performs all necessary argument handling for this
+ kernel message and calls catch_exception_raise, catch_exception_raise_state
+ or catch_exception_raise_state_identity, which should handle the exception.
+ If the called routine returns KERN_SUCCESS, a reply message will be sent,
+ allowing the thread to continue from the point of the exception; otherwise,
+ no reply message is sent and the called routine must have dealt with the
+ exception thread directly. */
+extern boolean_t
+ exc_server (mach_msg_header_t *request_msg,
+ mach_msg_header_t *reply_msg);
+
+
+/* http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/catch_exception_raise.html
+ These functions are defined in this file, and called by exc_server.
+ FIXME: What needs to be done when this code is put into a shared library? */
+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,
+ mach_msg_type_number_t code_count);
+kern_return_t
+catch_exception_raise_state (mach_port_t exception_port,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t code_count,
+ thread_state_flavor_t *flavor,
+ thread_state_t in_state,
+ mach_msg_type_number_t in_state_count,
+ thread_state_t out_state,
+ mach_msg_type_number_t *out_state_count);
+kern_return_t
+catch_exception_raise_state_identity (mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ thread_state_flavor_t *flavor,
+ thread_state_t in_state,
+ mach_msg_type_number_t in_state_count,
+ thread_state_t out_state,
+ mach_msg_type_number_t *out_state_count);
+
+#define SIGSEGV_EXC_STATE_TYPE ppc_exception_state_t
+#define SIGSEGV_EXC_STATE_FLAVOR PPC_EXCEPTION_STATE
+#define SIGSEGV_EXC_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
+#define SIGSEGV_THREAD_STATE_TYPE ppc_thread_state_t
+#define SIGSEGV_THREAD_STATE_FLAVOR PPC_THREAD_STATE
+#define SIGSEGV_THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT
+#define SIGSEGV_FAULT_ADDRESS(thr_state,exc_state) (exc_state).dar
+#define SIGSEGV_STACK_POINTER(thr_state) (thr_state).r1
+#define SIGSEGV_PROGRAM_COUNTER(thr_state) (thr_state).srr0
+
+int mach_initialize ();
+
+#endif