#include #include #include #include #include #include #include "nextstep-nat-inferior.h" #include "nextstep-nat-excthread.h" #include "nextstep-nat-mutils.h" #include "defs.h" #include "gdbcmd.h" static FILE *excthread_stderr = NULL; static FILE *excthread_stderr_re = NULL; static int excthread_debugflag = 0; static int excthread_debug (const char *fmt, ...) { va_list ap; if (excthread_debugflag) { va_start (ap, fmt); fprintf (excthread_stderr, "[%d excthread]: ", getpid ()); vfprintf (excthread_stderr, fmt, ap); va_end (ap); return 0; } else { return 0; } } /* A re-entrant version for use by the signal handling thread */ void excthread_debug_re (const char *fmt, ...) { va_list ap; if (excthread_debugflag) { va_start (ap, fmt); fprintf (excthread_stderr_re, "[%d excthread]: ", getpid ()); vfprintf (excthread_stderr_re, fmt, ap); va_end (ap); fflush (excthread_stderr_re); } } static void next_exception_thread (void *arg); static next_exception_thread_message *static_message = NULL; kern_return_t catch_exception_raise_state (mach_port_t port, exception_type_t exception_type, exception_data_t exception_data, mach_msg_type_number_t data_count, thread_state_flavor_t *state_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) { return KERN_FAILURE; } kern_return_t catch_exception_raise_state_identity (mach_port_t port, mach_port_t thread_port, mach_port_t task_port, exception_type_t exception_type, exception_data_t exception_data, mach_msg_type_number_t data_count, thread_state_flavor_t *state_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 kret; kret = mach_port_deallocate (mach_task_self(), task_port); MACH_CHECK_ERROR (kret); kret = mach_port_deallocate (mach_task_self(), thread_port); MACH_CHECK_ERROR (kret); return KERN_FAILURE; } kern_return_t catch_exception_raise (mach_port_t port, mach_port_t thread_port, mach_port_t task_port, exception_type_t exception_type, exception_data_t exception_data, mach_msg_type_number_t data_count) { #if 0 kret = mach_port_deallocate (mach_task_self(), task_port); MACH_CHECK_ERROR (kret); kret = mach_port_deallocate (mach_task_self(), thread_port); MACH_CHECK_ERROR (kret); #endif static_message->task_port = task_port; static_message->thread_port = thread_port; static_message->exception_type = exception_type; static_message->exception_data = exception_data; static_message->data_count = data_count; return KERN_SUCCESS; } void next_exception_thread_init (next_exception_thread_status *s) { s->transmit_fd = -1; s->receive_fd = -1; s->inferior_exception_port = PORT_NULL; memset (&s->saved_exceptions, 0, sizeof (s->saved_exceptions)); memset (&s->saved_exceptions_step, 0, sizeof (s->saved_exceptions_step)); s->saved_exceptions_stepping = 0; s->exception_thread = THREAD_NULL; } void next_exception_thread_create (next_exception_thread_status *s, task_t task) { int fd[2]; int ret; kern_return_t kret; ret = pipe (fd); CHECK_FATAL (ret == 0); s->transmit_fd = fd[1]; s->receive_fd = fd[0]; kret = mach_port_allocate (mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &s->inferior_exception_port); MACH_CHECK_ERROR (kret); kret = mach_port_insert_right (mach_task_self(), s->inferior_exception_port, s->inferior_exception_port, MACH_MSG_TYPE_MAKE_SEND); MACH_CHECK_ERROR (kret); if (inferior_bind_exception_port_flag) { next_save_exception_ports (task, &s->saved_exceptions); kret = task_set_exception_ports (task, EXC_MASK_ALL, s->inferior_exception_port, EXCEPTION_DEFAULT, THREAD_STATE_NONE); MACH_CHECK_ERROR (kret); } s->exception_thread = gdb_thread_fork ((gdb_thread_fn_t) &next_exception_thread, s); } void next_exception_thread_destroy (next_exception_thread_status *s) { if (s->exception_thread != THREAD_NULL) { gdb_thread_kill (s->exception_thread); } if (s->receive_fd > 0) { delete_file_handler (s->receive_fd); close (s->receive_fd); } if (s->transmit_fd > 0) close (s->transmit_fd); next_exception_thread_init (s); } void next_exception_thread_debug (FILE *f, next_exception_thread_status *s) { fprintf (f, " [EXCEPTION THREAD]\n"); } static void next_exception_thread (void *arg) { next_exception_thread_status *s = (next_exception_thread_status *) arg; CHECK_FATAL (s != NULL); for (;;) { unsigned char msgin_data[1024]; msg_header_t *msgin_hdr = (msg_header_t *) msgin_data; unsigned char msgout_data[1024]; msg_header_t *msgout_hdr = (msg_header_t *) msgout_data; next_exception_thread_message msgsend; kern_return_t kret; pthread_testcancel (); excthread_debug_re ("next_exception_thread: waiting for exceptions\n"); kret = mach_msg (msgin_hdr, (MACH_RCV_MSG | MACH_RCV_INTERRUPT), 0, sizeof (msgin_data), s->inferior_exception_port, 0, MACH_PORT_NULL); if (kret == MACH_RCV_INTERRUPTED) { continue; } if (kret != KERN_SUCCESS) { fprintf (excthread_stderr_re, "next_exception_thread: error receiving exception message: %s (0x%lx)\n", MACH_ERROR_STRING (kret), (unsigned long) kret); abort (); } static_message = &msgsend; excthread_debug_re ("next_exception_thread: handling exception\n"); kret = exc_server (msgin_hdr, msgout_hdr); static_message = NULL; kret = thread_suspend (msgsend.thread_port); if (kret != KERN_SUCCESS) { fprintf (excthread_stderr_re, "next_exception_thread: unable to suspend thread generating exception: %s (0x%lx)\n", MACH_ERROR_STRING (kret), (unsigned long) kret); abort (); } excthread_debug_re ("next_exception_thread: sending event\n"); kret = mach_msg (msgout_hdr, (MACH_SEND_MSG | MACH_SEND_INTERRUPT), msgout_hdr->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kret == MACH_SEND_INTERRUPTED) { continue; } if (kret != KERN_SUCCESS) { fprintf (excthread_stderr_re, "next_exception_thread: error sending exception reply: %s (0x%lx)\n", MACH_ERROR_STRING (kret), (unsigned long) kret); abort (); } write (s->transmit_fd, &msgsend, sizeof (msgsend)); } } void _initialize_nextstep_nat_excthread () { struct cmd_list_element *cmd = NULL; excthread_stderr = fdopen (fileno (stderr), "w+"); excthread_stderr_re = fdopen (fileno (stderr), "w+"); cmd = add_set_cmd ("debug-exceptions", class_obscure, var_boolean, (char *) &excthread_debugflag, "Set if printing exception thread debugging statements.", &setlist); add_show_from_set (cmd, &showlist); }