debugserver Mach exception messages and saved ports
The exception request/reply representation and the code that snapshots and restores a task’s prior exception handlers. It shows the lifecycle obligations around temporarily taking ownership of exception delivery.
MachException::Message::Reply source
kern_return_t MachException::Message::Reply(MachProcess *process, int signal) { // Reply to the exception... DNBError err; // If we had a soft signal, we need to update the thread first so it can // continue without signaling int soft_signal = state.SoftSignal(); if (soft_signal) { int state_pid = -1; if (process->Task().TaskPort() == state.task_port) { // This is our task, so we can update the signal to send to it state_pid = process->ProcessID(); soft_signal = signal; } else { err = ::pid_for_task(state.task_port, &state_pid); } assert(state_pid != -1); if (state_pid != -1) { errno = 0; if (::ptrace(PT_THUPDATE, state_pid, (caddr_t)((uintptr_t)state.thread_port), soft_signal) != 0) err.SetError(errno, DNBError::POSIX); else err.Clear(); if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) err.LogThreaded("::ptrace (request = PT_THUPDATE, pid = 0x%4.4x, tid = " "0x%4.4x, signal = %i)", state_pid, state.thread_port, soft_signal); … more in source
MachException::PortInfo::Save source
kern_return_t MachException::PortInfo::Save(task_t task) { DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, "MachException::PortInfo::Save ( task = 0x%4.4x )", task); // Be careful to be able to have debugserver built on a newer OS than what // it is currently running on by being able to start with all exceptions // and back off to just what is supported on the current system DNBError err; mask = LLDB_EXC_MASK; count = (sizeof(ports) / sizeof(ports[0])); err = ::task_get_exception_ports(task, mask, masks, &count, ports, behaviors, flavors); if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) err.LogThreaded("::task_get_exception_ports ( task = 0x%4.4x, mask = 0x%x, " "maskCnt => %u, ports, behaviors, flavors )", task, mask, count); if (err.Status() == KERN_INVALID_ARGUMENT && mask != PREV_EXC_MASK_ALL) { mask = PREV_EXC_MASK_ALL; count = (sizeof(ports) / sizeof(ports[0])); err = ::task_get_exception_ports(task, mask, masks, &count, ports, behaviors, flavors); if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) err.LogThreaded("::task_get_exception_ports ( task = 0x%4.4x, mask = " "0x%x, maskCnt => %u, ports, behaviors, flavors )", task, mask, count); } if (err.Fail()) { mask = 0; … more in source
MachException::PortInfo::Restore source
kern_return_t MachException::PortInfo::Restore(task_t task) { DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, "MachException::PortInfo::Restore( task = 0x%4.4x )", task); uint32_t i = 0; DNBError err; if (count > 0) { for (i = 0; i < count; i++) { err = ::task_set_exception_ports(task, masks[i], ports[i], behaviors[i], flavors[i]); if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) { err.LogThreaded("::task_set_exception_ports ( task = 0x%4.4x, " "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " "behavior = 0x%8.8x, new_flavor = 0x%8.8x )", task, masks[i], ports[i], behaviors[i], flavors[i]); // Bail if we encounter any errors } if (err.Fail()) break; } } count = 0; return err.Status(); }