#include <Carbon/Carbon.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdarg.h>
#include <pthread.h>
#include <assert.h>
#include <mach/mach.h>
void *exception_handler(void *arg)
{
extern boolean_t exc_server();
mach_port_t port = (mach_port_t) arg;
mach_msg_server(exc_server, 2048, port, 0);
abort(); // without this GCC complains (it doesn't know that mach_msg_server never returns)
}
void setup_mach_exception_port()
{
static mach_port_t exception_port = MACH_PORT_NULL;
mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exception_port);
mach_port_insert_right(mach_task_self(), exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);
task_set_exception_ports(mach_task_self(), EXC_MASK_ALL, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
pthread_t returned_thread;
pthread_create(&returned_thread, NULL, exception_handler, (void*) exception_port);
}
void test_crash()
{
char *obj = NULL;
*obj = "foo";
}
struct macosx_exception_info
{
exception_mask_t masks[EXC_TYPES_COUNT];
mach_port_t ports[EXC_TYPES_COUNT];
exception_behavior_t behaviors[EXC_TYPES_COUNT];
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
mach_msg_type_number_t count;
};
struct macosx_exception_info info;
kern_return_t macosx_save_exception_ports (task_t task, struct macosx_exception_info *info)
{
kern_return_t kret;
info->count = (sizeof (info->ports) / sizeof (info->ports[0]));
kret = task_get_exception_ports
(task,
EXC_MASK_ALL,
info->masks, &info->count, info->ports, info->behaviors, info->flavors);
if (kret != KERN_SUCCESS)
return kret;
return KERN_SUCCESS;
}
kern_return_t
macosx_restore_exception_ports (task_t task,
struct macosx_exception_info *info)
{
int i;
kern_return_t kret;
for (i = 0; i < info->count; i++)
{
kret = task_set_exception_ports
(task, info->masks[i], info->ports[i], info->behaviors[i],
info->flavors[i]);
if (kret != KERN_SUCCESS)
return kret;
}
return KERN_SUCCESS;
}
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)
{
fprintf(stderr, "catch_exception_raise %d\n", exception);
macosx_restore_exception_ports(mach_task_self(),&info);
return KERN_SUCCESS; // loops infinitely...
}
void crash_thread_proc(void* data)
{
test_crash();
}
void SetMyExceptionHandler()
{
extern 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) ;
static int i = 0;
if ( i == 0 )
{
i = 1;
macosx_save_exception_ports(mach_task_self(), &info);
setup_mach_exception_port();
printf("Set Exception Handler\n");
}
}