bool MachException::Message::CatchExceptionRaise() { bool success = false; // locker will keep a mutex locked until it goes out of scope // PThreadMutex::Locker locker(&g_message_mutex); // DNBLogThreaded("calling mach_exc_server"); g_message = &state; // 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. if (mach_exc_server (&exc_msg.hdr, &reply_msg.hdr)) { success = true; } else if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { DNBLogThreaded("mach_exc_server returned zero..."); } g_message = NULL; return success; }
static void* exception_server (mach_port_t exceptionPort) { mach_msg_return_t rt; mach_msg_header_t *msg; mach_msg_header_t *reply; msg = safe_malloc(sizeof(union __RequestUnion__mach_exc_subsystem)); reply = safe_malloc(sizeof(union __ReplyUnion__mach_exc_subsystem)); while (1) { rt = mach_msg(msg, MACH_RCV_MSG, 0, sizeof(union __RequestUnion__mach_exc_subsystem), exceptionPort, 0, MACH_PORT_NULL); if (rt!= MACH_MSG_SUCCESS) { DEBUG_PRINT("[-exception_server] MACH_RCV_MSG stopped, exit from exception_server thread :%d\n", 1); return "MACH_RCV_MSG_FAILURE"; } /* * Call out to the mach_exc_server generated by mig and mach_exc.defs. * This will in turn invoke one of: * mach_catch_exception_raise() * mach_catch_exception_raise_state() * mach_catch_exception_raise_state_identity() * .. depending on the behavior specified when registering the Mach exception port. */ mach_exc_server(msg, reply); // Send the now-initialized reply rt = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); if (rt!= MACH_MSG_SUCCESS) { return "MACH_SEND_MSG_FAILURE"; } } }
bool TargetException::run() { m_stop = false; for (;;) { auto kr = mach_msg(&m_rcvMsg.head, MACH_RCV_MSG, 0, sizeof(m_rcvMsg), m_exceptionPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (m_stop) { return true; } if (kr != MACH_MSG_SUCCESS) { log(QString("mach_msg rcv failde: %1").arg(mach_error_string(kr)), LogType::Error); return false; } /* Handle the message (calls catch_exception_raise) */ // we should use mach_exc_server for 64bits if (mach_exc_server(&m_rcvMsg.head, &m_sendMsg.head) != TRUE) { log(QString("mach_exc_server failde"), LogType::Error); return false; } kr = mach_msg(&m_sendMsg.head, MACH_SEND_MSG, m_sendMsg.head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); if (kr != MACH_MSG_SUCCESS) { log(QString("mach_msg send failde: %1").arg(mach_error_string(kr)), LogType::Error); return false; } } }
static void ux_handler(void) { task_t self = current_task(); mach_port_name_t exc_port_name; mach_port_name_t exc_set_name; /* self->kernel_vm_space = TRUE; */ ux_handler_self = self; /* * Allocate a port set that we will receive on. */ if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_PORT_SET, &exc_set_name) != MACH_MSG_SUCCESS) panic("ux_handler: port_set_allocate failed"); /* * Allocate an exception port and use object_copyin to * translate it to the global name. Put it into the set. */ if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_RECEIVE, &exc_port_name) != MACH_MSG_SUCCESS) panic("ux_handler: port_allocate failed"); if (mach_port_move_member(get_task_ipcspace(ux_handler_self), exc_port_name, exc_set_name) != MACH_MSG_SUCCESS) panic("ux_handler: port_set_add failed"); if (ipc_object_copyin(get_task_ipcspace(self), exc_port_name, MACH_MSG_TYPE_MAKE_SEND, (void *) &ux_exception_port) != MACH_MSG_SUCCESS) panic("ux_handler: object_copyin(ux_exception_port) failed"); proc_list_lock(); thread_wakeup(&ux_exception_port); proc_list_unlock(); /* Message handling loop. */ for (;;) { struct rep_msg { mach_msg_header_t Head; NDR_record_t NDR; kern_return_t RetCode; } rep_msg; struct exc_msg { mach_msg_header_t Head; /* start of the kernel processed data */ mach_msg_body_t msgh_body; mach_msg_port_descriptor_t thread; mach_msg_port_descriptor_t task; /* end of the kernel processed data */ NDR_record_t NDR; exception_type_t exception; mach_msg_type_number_t codeCnt; mach_exception_data_t code; /* some times RCV_TO_LARGE probs */ char pad[512]; } exc_msg; mach_port_name_t reply_port; kern_return_t result; exc_msg.Head.msgh_local_port = CAST_MACH_NAME_TO_PORT(exc_set_name); exc_msg.Head.msgh_size = sizeof (exc_msg); #if 0 result = mach_msg_receive(&exc_msg.Head); #else result = mach_msg_receive(&exc_msg.Head, MACH_RCV_MSG, sizeof (exc_msg), exc_set_name, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, 0); #endif if (result == MACH_MSG_SUCCESS) { reply_port = CAST_MACH_PORT_TO_NAME(exc_msg.Head.msgh_remote_port); if (mach_exc_server(&exc_msg.Head, &rep_msg.Head)) { result = mach_msg_send(&rep_msg.Head, MACH_SEND_MSG, sizeof (rep_msg),MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL); if (reply_port != 0 && result != MACH_MSG_SUCCESS) mach_port_deallocate(get_task_ipcspace(ux_handler_self), reply_port); } } else if (result == MACH_RCV_TOO_LARGE) /* ignore oversized messages */; else panic("exception_handler"); } }