/* this is the thread which forwards of exceptions read from the exception server off to our exception catchers and then back out to the other thread */ void exception_thread(void *shared_thread_state) { mach_msg_header_t *message; mach_msg_header_t *reply; kern_return_t retval; #ifdef USE_THREAD_LOCAL pthread_setspecific(scheme_thread_local_key, shared_thread_state); #endif /* allocate the space for the message and reply */ message = (mach_msg_header_t*)malloc(sizeof(mach_exc_msg_t)); reply = (mach_msg_header_t*)malloc(sizeof(mach_reply_msg_t)); /* do this loop forever */ while(1) { /* block until we get an exception message */ retval = mach_msg(message, MACH_RCV_MSG, 0, sizeof(mach_exc_msg_t), exc_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); /* forward off the handling of this message */ if(!exc_server(message, reply)) { GCPRINT(GCOUTF, "INTERNAL ERROR: exc_server() didn't like something\n"); abort(); } /* send the message back out to the thread */ retval = mach_msg(reply, MACH_SEND_MSG, sizeof(mach_reply_msg_t), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); } }
/* * This message server catches server exceptions. It runs in a dedicated thread. */ void * server_exception_catcher( void *arg) { struct server_thread_priv_data priv_data; kern_return_t kr; #define MSG_BUFFER_SIZE 8192 union request_msg { mach_msg_header_t hdr; mig_reply_error_t death_pill; char space[MSG_BUFFER_SIZE]; } *msg_buffer_1, *msg_buffer_2; mach_msg_header_t *request; mig_reply_error_t *reply; cthread_set_name(cthread_self(), "server exc catcher"); server_thread_set_priv_data(cthread_self(), &priv_data); kr = vm_allocate(mach_task_self(), (vm_address_t *) &msg_buffer_1, 2 * sizeof *msg_buffer_1, TRUE); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("server_exception_catcher: vm_allocate")); panic("server_exception_catcher"); } msg_buffer_2 = msg_buffer_1 + 1; request = &msg_buffer_1->hdr; reply = &msg_buffer_2->death_pill; do { kr = mach_msg(request, MACH_RCV_MSG, 0, sizeof *msg_buffer_1, server_exception_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kr != MACH_MSG_SUCCESS) { MACH3_DEBUG(1, kr, ("server_exception_catcher: mach_msg")); panic("server_exception_catcher: receive"); } if (exc_server(request, &reply->Head)) {} else { printk("server_exception_catcher: invalid message" "(id = %d = 0x%x)\n", request->msgh_id, request->msgh_id); } panic("server_exception_catcher: what now ?"); } while (1); cthread_detach(cthread_self()); cthread_exit((void *) 0); /*NOTREACHED*/ return (void *) 0; }
static any_t exc_thread(ports_t *port_p) { kern_return_t r; char *msg_data[2][64]; msg_header_t *imsg = (msg_header_t *)msg_data[0], *omsg = (msg_header_t *)msg_data[1]; /* Wait for exceptions */ while(1) { imsg->msg_size = 64; imsg->msg_local_port = port_p->exc_port; r = msg_receive(imsg, MSG_OPTION_NONE, 0); if (r == RCV_SUCCESS) { /* Give the message to the Mach exception server. */ if (exc_server(imsg,omsg)) { /* send the reply message that exc_serv gave us. */ r = msg_send(omsg, MSG_OPTION_NONE, 0); if (r != SEND_SUCCESS) { mach_error("exc_thread msg_send",r); exit(1); } } else { /* exc_server refused to handle the imsg. */ exit(2); } } else { /* msg_receive returned an error. */ mach_error("exc_thread msg_receive",r); exit(3); } /* Pass the message to the old exception handler, if necessary. */ if (pass_on == TRUE) { imsg->msg_remote_port = port_p->old_exc_port; imsg->msg_local_port = port_p->clear_port; r = msg_send(imsg, MSG_OPTION_NONE, 0); if (r != SEND_SUCCESS) { mach_error("msg_send to old_exc_port",r); exit(4); } } } }
/* FUNCTIONS */ static void *exc_thread(void *junk) { mach_msg_return_t r; /* 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. */ struct { mach_msg_header_t head; char data[256]; } reply; struct { mach_msg_header_t head; mach_msg_body_t msgh_body; char data[1024]; } msg; for(;;) { r = mach_msg( &msg.head, MACH_RCV_MSG|MACH_RCV_LARGE, 0, sizeof(msg), exception_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if(r != MACH_MSG_SUCCESS) DIE("mach_msg"); /* Handle the message (calls catch_exception_raise) */ if(!exc_server(&msg.head,&reply.head)) DIE("exc_server"); /* Send the reply */ r = mach_msg( &reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if(r != MACH_MSG_SUCCESS) DIE("mach_msg"); } /* not reached */ }
/* * Exception thread handler. */ static void * mach_exception_thread (void *arg) { for (;;) { mach_exception_msg_t request; mach_exception_msg_t reply; mach_msg_return_t result; /* receive from "mach_exception_port" */ result = mach_msg (&request.msg.header, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof (request), mach_exception_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); g_assert (result == MACH_MSG_SUCCESS); /* dispatch to catch_exception_raise () */ exc_server (&request.msg.header, &reply.msg.header); /* send back to sender */ result = mach_msg (&reply.msg.header, MACH_SEND_MSG, reply.msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); /* If we try to abort the thread while delivering an exception. The port will be gone since the kernel setup a send once port to deliver the resume message and thread_abort will consume it. */ g_assert (result == MACH_MSG_SUCCESS || result == MACH_SEND_INVALID_DEST); } return NULL; }
/* 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(); } } return NULL; // quiet warning }
/* * Exception thread handler. */ static void * mach_exception_thread (void *arg) { for (;;) { mach_exception_msg_t request; mach_exception_msg_t reply; mach_msg_return_t result; /* receive from "mach_exception_port" */ result = mach_msg (&request.msg.header, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof (request), mach_exception_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); g_assert (result == MACH_MSG_SUCCESS); /* dispatch to catch_exception_raise () */ exc_server (&request.msg.header, &reply.msg.header); /* send back to sender */ result = mach_msg (&reply.msg.header, MACH_SEND_MSG, reply.msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); g_assert (result == MACH_MSG_SUCCESS); } return NULL; }
void *ExceptionHandlerThread(void *thread_arg) { mach_port_t handler_port = (mach_port_t) (uintptr_t) thread_arg; while (1) { struct { mach_msg_header_t header; uint8_t data[256]; } receive; mach_msg_header_t reply; kern_return_t rc; receive.header.msgh_local_port = handler_port; receive.header.msgh_size = sizeof(receive); rc = mach_msg(&receive.header, MACH_RCV_MSG | MACH_RCV_LARGE, 0, receive.header.msgh_size, handler_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); CHECK(rc == KERN_SUCCESS); CHECK(exc_server(&receive.header, &reply)); exit(1); } return NULL; }
static void *mach_exception_thread(void *data) { while (true) { struct { mach_msg_header_t head; mach_msg_body_t msgh_body; char data[1024]; } msg; struct { mach_msg_header_t head; char data[1024]; } reply; // wait for a message on the exception port mach_msg_return_t ret = mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(msg), s_listen_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (ret != MACH_MSG_SUCCESS) { LOG_INFO("mach_msg receive failed with %d %s", ret, mach_error_string(ret)); break; } // call exc_server, which will call back into catch_exception_raise exc_server(&msg.head, &reply.head); // send the reply ret = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (ret != MACH_MSG_SUCCESS) { LOG_INFO("mach_msg send failed with %d %s", ret, mach_error_string(ret)); break; } } return NULL; }
/* * This message server catches user task exceptions. Most user exceptions * will be received on the thread exception port. This server servers * only exceptions from unknown threads or from external debuggers. * It runs in a dedicated thread. */ void * task_exception_catcher( void *arg) { struct server_thread_priv_data priv_data; kern_return_t kr; #define MSG_BUFFER_SIZE 8192 union request_msg { mach_msg_header_t hdr; mig_reply_error_t death_pill; char space[MSG_BUFFER_SIZE]; } *msg_buffer_1, *msg_buffer_2; mach_msg_header_t *request; mig_reply_error_t *reply; mach_msg_header_t *tmp; cthread_set_name(cthread_self(), "task exc catcher"); server_thread_set_priv_data(cthread_self(), &priv_data); uniproc_enter(); kr = vm_allocate(mach_task_self(), (vm_address_t *) &msg_buffer_1, 2 * sizeof *msg_buffer_1, TRUE); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("task_exception_catcher: vm_allocate")); panic("task_exception_catcher"); } msg_buffer_2 = msg_buffer_1 + 1; request = &msg_buffer_1->hdr; reply = &msg_buffer_2->death_pill; do { uniproc_exit(); kr = mach_msg(request, MACH_RCV_MSG, 0, sizeof *msg_buffer_1, user_trap_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kr != MACH_MSG_SUCCESS) { MACH3_DEBUG(1, kr, ("task_exception_catcher: mach_msg")); panic("task_exception_catcher: receive"); } uniproc_enter(); if (exc_server(request, &reply->Head)) {} else { printk("trap_exception_catcher: invalid message" "(id = %d = 0x%x)\n", request->msgh_id, request->msgh_id); } if (reply->Head.msgh_remote_port == MACH_PORT_NULL) { /* no reply port, just get another request */ continue; } if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && reply->RetCode == MIG_NO_REPLY) { /* deallocate reply port right */ (void) mach_port_deallocate(mach_task_self(), reply->Head.msgh_remote_port); continue; } /* Send reply to request and receive another */ uniproc_exit(); kr = mach_msg(&reply->Head, MACH_SEND_MSG, reply->Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); uniproc_enter(); if (kr != MACH_MSG_SUCCESS) { if (kr == MACH_SEND_INVALID_DEST) { /* deallocate reply port right */ /* XXX should destroy reply msg */ (void) mach_port_deallocate(mach_task_self(), reply->Head.msgh_remote_port); } else { MACH3_DEBUG(0, kr, ("mach_msg")); panic("task_exception_catcher: send"); } } tmp = request; request = (mach_msg_header_t *) reply; reply = (mig_reply_error_t *) tmp; } while (1); cthread_detach(cthread_self()); cthread_exit((void *) 0); /*NOTREACHED*/ return (void *) 0; }
/*++ Function : SEHExceptionThread Entry point for the thread that will listen for exception in any other thread. Parameters : void *args - not used Return value : Never returns --*/ void *SEHExceptionThread(void *args) { mach_msg_return_t MachRet; // Handle exceptions forever. while (1) { char buf[512]; mach_msg_header_t *msg = (mach_msg_header_t *)buf; MachRet = mach_msg(msg, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(buf), s_ExceptionPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (MachRet == MACH_RCV_TOO_LARGE) { UTIL_SetLastErrorFromMach(MachRet); ExitProcess(GetLastError()); } if (MachRet != MACH_MSG_SUCCESS) { UTIL_SetLastErrorFromMach(MachRet); ExitProcess(GetLastError()); } if (msg->msgh_id == SET_THREAD_MESSAGE_ID) { MSG_SET_THREAD *MsgSet = (MSG_SET_THREAD *)msg; MachRet = thread_suspend(MsgSet->m_ThreadPort); if (MachRet != KERN_SUCCESS) { UTIL_SetLastErrorFromMach(MachRet); ExitProcess(GetLastError()); } if (!CONTEXT_SetThreadContextOnPort(MsgSet->m_ThreadPort, &MsgSet->m_ThreadContext)) { ExitProcess(GetLastError()); } MachRet = thread_resume(MsgSet->m_ThreadPort); if (MachRet != KERN_SUCCESS) { UTIL_SetLastErrorFromMach(MachRet); ExitProcess(GetLastError()); } } else { char *MsgReply[512]; mach_msg_header_t *reply = (mach_msg_header_t *)MsgReply; // Pass the message to exc_server which in turn calls catch_exception_raise exc_server(msg, reply); // Send the reply message back MachRet = mach_msg(reply, MACH_SEND_MSG | MACH_MSG_OPTION_NONE, reply->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (MachRet != KERN_SUCCESS) { UTIL_SetLastErrorFromMach(MachRet); ExitProcess(GetLastError()); } } } // Check for more errors }
/* 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; #ifdef DEBUG_EXCEPTION_HANDLING fprintf (stderr, "Exception thread going to sleep\n"); #endif /* 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); #ifdef DEBUG_EXCEPTION_HANDLING fprintf (stderr, "Exception thread woke up\n"); #endif if (retval != MACH_MSG_SUCCESS) { #ifdef DEBUG_EXCEPTION_HANDLING fprintf (stderr, "mach_msg receive failed with %d %s\n", (int) retval, mach_error_string (retval)); #endif abort (); } /* Handle the message: Call exc_server, which will call catch_exception_raise and produce a reply message. */ #ifdef DEBUG_EXCEPTION_HANDLING fprintf (stderr, "Calling exc_server\n"); #endif exc_server (&msg.head, &reply.head); #ifdef DEBUG_EXCEPTION_HANDLING fprintf (stderr, "Finished exc_server\n"); #endif /* 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) { #ifdef DEBUG_EXCEPTION_HANDLING fprintf (stderr, "mach_msg send failed\n"); #endif abort (); } #ifdef DEBUG_EXCEPTION_HANDLING fprintf (stderr, "Reply successful\n"); #endif } }