diff options
Diffstat (limited to 'tools/debugserver/source/MacOSX/MachException.cpp')
-rw-r--r-- | tools/debugserver/source/MacOSX/MachException.cpp | 513 |
1 files changed, 0 insertions, 513 deletions
diff --git a/tools/debugserver/source/MacOSX/MachException.cpp b/tools/debugserver/source/MacOSX/MachException.cpp deleted file mode 100644 index 01e5892d487d..000000000000 --- a/tools/debugserver/source/MacOSX/MachException.cpp +++ /dev/null @@ -1,513 +0,0 @@ -//===-- MachException.cpp ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Created by Greg Clayton on 6/18/07. -// -//===----------------------------------------------------------------------===// - -#include "MachException.h" -#include "DNB.h" -#include "DNBError.h" -#include "DNBLog.h" -#include "MachProcess.h" -#include "PThreadMutex.h" -#include "SysSignal.h" -#include <errno.h> -#include <sys/ptrace.h> -#include <sys/types.h> - -// Routine mach_exception_raise -extern "C" kern_return_t -catch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, - mach_port_t task, exception_type_t exception, - mach_exception_data_t code, - mach_msg_type_number_t codeCnt); - -extern "C" kern_return_t catch_mach_exception_raise_state( - mach_port_t exception_port, exception_type_t exception, - const mach_exception_data_t code, mach_msg_type_number_t codeCnt, - int *flavor, const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt); - -// Routine mach_exception_raise_state_identity -extern "C" kern_return_t catch_mach_exception_raise_state_identity( - mach_port_t exception_port, mach_port_t thread, mach_port_t task, - exception_type_t exception, mach_exception_data_t code, - mach_msg_type_number_t codeCnt, int *flavor, thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt); - -extern "C" boolean_t mach_exc_server(mach_msg_header_t *InHeadP, - mach_msg_header_t *OutHeadP); - -// Note: g_message points to the storage allocated to catch the data from -// catching the current exception raise. It's populated when we catch a raised -// exception which can't immediately be replied to. -// -// If it becomes possible to catch exceptions from multiple threads -// simultaneously, accesses to g_message would need to be mutually exclusive. -static MachException::Data *g_message = NULL; - -extern "C" kern_return_t catch_mach_exception_raise_state( - mach_port_t exc_port, exception_type_t exc_type, - const mach_exception_data_t exc_data, mach_msg_type_number_t exc_data_count, - int *flavor, const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt) { - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { - DNBLogThreaded("::%s ( exc_port = 0x%4.4x, exc_type = %d ( %s ), exc_data " - "= 0x%llx, exc_data_count = %d)", - __FUNCTION__, exc_port, exc_type, - MachException::Name(exc_type), (uint64_t)exc_data, - exc_data_count); - } - return KERN_FAILURE; -} - -extern "C" kern_return_t catch_mach_exception_raise_state_identity( - mach_port_t exc_port, mach_port_t thread_port, mach_port_t task_port, - exception_type_t exc_type, mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count, int *flavor, - thread_state_t old_state, mach_msg_type_number_t old_stateCnt, - thread_state_t new_state, mach_msg_type_number_t *new_stateCnt) { - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { - DNBLogThreaded("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = " - "0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { 0x%llx, " - "0x%llx })", - __FUNCTION__, exc_port, thread_port, task_port, exc_type, - MachException::Name(exc_type), exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - - return KERN_FAILURE; -} - -extern "C" kern_return_t -catch_mach_exception_raise(mach_port_t exc_port, mach_port_t thread_port, - mach_port_t task_port, exception_type_t exc_type, - mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count) { - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { - DNBLogThreaded("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = " - "0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { 0x%llx, " - "0x%llx })", - __FUNCTION__, exc_port, thread_port, task_port, exc_type, - MachException::Name(exc_type), exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - g_message->exc_type = 0; - g_message->exc_data.clear(); - - if (task_port == g_message->task_port) { - g_message->task_port = task_port; - g_message->thread_port = thread_port; - g_message->exc_type = exc_type; - g_message->AppendExceptionData(exc_data, exc_data_count); - return KERN_SUCCESS; - } else if (!MachTask::IsValid(g_message->task_port)) { - // Our original exception port isn't valid anymore check for a SIGTRAP - if (exc_type == EXC_SOFTWARE && exc_data_count == 2 && - exc_data[0] == EXC_SOFT_SIGNAL && exc_data[1] == SIGTRAP) { - // We got a SIGTRAP which indicates we might have exec'ed and possibly - // lost our old task port during the exec, so we just need to switch over - // to using this new task port - g_message->task_port = task_port; - g_message->thread_port = thread_port; - g_message->exc_type = exc_type; - g_message->AppendExceptionData(exc_data, exc_data_count); - return KERN_SUCCESS; - } - } - return KERN_FAILURE; -} - -void MachException::Message::Dump() const { - DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_msg { bits = 0x%8.8x size = 0x%8.8x " - "remote-port = 0x%8.8x local-port = 0x%8.8x " - "reserved = 0x%8.8x id = 0x%8.8x } ", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id); - - DNBLogThreadedIf(LOG_EXCEPTIONS, "reply_msg { bits = 0x%8.8x size = 0x%8.8x " - "remote-port = 0x%8.8x local-port = 0x%8.8x " - "reserved = 0x%8.8x id = 0x%8.8x }", - reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, - reply_msg.hdr.msgh_local_port, reply_msg.hdr.msgh_reserved, - reply_msg.hdr.msgh_id); - - state.Dump(); -} - -bool MachException::Data::GetStopInfo( - struct DNBThreadStopInfo *stop_info) const { - // Zero out the structure. - memset(stop_info, 0, sizeof(struct DNBThreadStopInfo)); - - if (exc_type == 0) { - stop_info->reason = eStopTypeInvalid; - return true; - } - - // We always stop with a mach exceptions - stop_info->reason = eStopTypeException; - // Save the EXC_XXXX exception type - stop_info->details.exception.type = exc_type; - - // Fill in a text description - const char *exc_name = MachException::Name(exc_type); - char *desc = stop_info->description; - const char *end_desc = desc + DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH; - if (exc_name) - desc += - snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%s", exc_name); - else - desc += - snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%i", exc_type); - - stop_info->details.exception.data_count = exc_data.size(); - - int soft_signal = SoftSignal(); - if (soft_signal) { - if (desc < end_desc) { - const char *sig_str = SysSignal::Name(soft_signal); - snprintf(desc, end_desc - desc, " EXC_SOFT_SIGNAL( %i ( %s ))", - soft_signal, sig_str ? sig_str : "unknown signal"); - } - } else { - // No special disassembly for exception data, just - size_t idx; - if (desc < end_desc) { - desc += snprintf(desc, end_desc - desc, " data[%llu] = {", - (uint64_t)stop_info->details.exception.data_count); - - for (idx = 0; - desc < end_desc && idx < stop_info->details.exception.data_count; - ++idx) - desc += snprintf( - desc, end_desc - desc, "0x%llx%c", (uint64_t)exc_data[idx], - ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ',')); - } - } - - // Copy the exception data - size_t i; - for (i = 0; i < stop_info->details.exception.data_count; i++) - stop_info->details.exception.data[i] = exc_data[i]; - - return true; -} - -void MachException::Data::DumpStopReason() const { - int soft_signal = SoftSignal(); - if (soft_signal) { - const char *signal_str = SysSignal::Name(soft_signal); - if (signal_str) - DNBLog("signal(%s)", signal_str); - else - DNBLog("signal(%i)", soft_signal); - return; - } - DNBLog("%s", Name(exc_type)); -} - -kern_return_t MachException::Message::Receive(mach_port_t port, - mach_msg_option_t options, - mach_msg_timeout_t timeout, - mach_port_t notify_port) { - DNBError err; - const bool log_exceptions = DNBLogCheckLogBit(LOG_EXCEPTIONS); - mach_msg_timeout_t mach_msg_timeout = - options & MACH_RCV_TIMEOUT ? timeout : 0; - if (log_exceptions && ((options & MACH_RCV_TIMEOUT) == 0)) { - // Dump this log message if we have no timeout in case it never returns - DNBLogThreaded("::mach_msg ( msg->{bits = %#x, size = %u remote_port = " - "%#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option " - "= %#x, send_size = 0, rcv_size = %llu, rcv_name = %#x, " - "timeout = %u, notify = %#x)", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, - (uint64_t)sizeof(exc_msg.data), port, mach_msg_timeout, - notify_port); - } - - err = ::mach_msg(&exc_msg.hdr, - options, // options - 0, // Send size - sizeof(exc_msg.data), // Receive size - port, // exception port to watch for exception on - mach_msg_timeout, // timeout in msec (obeyed only if - // MACH_RCV_TIMEOUT is ORed into the - // options parameter) - notify_port); - - // Dump any errors we get - if (log_exceptions) { - err.LogThreaded("::mach_msg ( msg->{bits = %#x, size = %u remote_port = " - "%#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = %u, rcv_size = %u, rcv_name = " - "%#x, timeout = %u, notify = %#x)", - exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, 0, - sizeof(exc_msg.data), port, mach_msg_timeout, notify_port); - } - return err.Status(); -} - -bool MachException::Message::CatchExceptionRaise(task_t task) { - bool success = false; - state.task_port = task; - 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; -} - -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); - } - } - - DNBLogThreadedIf( - LOG_EXCEPTIONS, "::mach_msg ( msg->{bits = %#x, size = %u, remote_port = " - "%#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, " - "option = %#x, send_size = %u, rcv_size = %u, rcv_name = " - "%#x, timeout = %u, notify = %#x)", - reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, - reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id, - MACH_SEND_MSG | MACH_SEND_INTERRUPT, reply_msg.hdr.msgh_size, 0, - MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - - err = ::mach_msg(&reply_msg.hdr, MACH_SEND_MSG | MACH_SEND_INTERRUPT, - reply_msg.hdr.msgh_size, 0, MACH_PORT_NULL, - MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - - if (err.Fail()) { - if (err.Status() == MACH_SEND_INTERRUPTED) { - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - err.LogThreaded("::mach_msg() - send interrupted"); - // TODO: keep retrying to reply??? - } else { - if (state.task_port == process->Task().TaskPort()) { - DNBLogThreaded("error: mach_msg() returned an error when replying to a " - "mach exception: error = %u", - err.Status()); - } else { - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - err.LogThreaded("::mach_msg() - failed (child of task)"); - } - } - } - - return err.Status(); -} - -void MachException::Data::Dump() const { - const char *exc_type_name = MachException::Name(exc_type); - DNBLogThreadedIf( - LOG_EXCEPTIONS, " state { task_port = 0x%4.4x, thread_port = " - "0x%4.4x, exc_type = %i (%s) ...", - task_port, thread_port, exc_type, exc_type_name ? exc_type_name : "???"); - - const size_t exc_data_count = exc_data.size(); - // Dump any special exception data contents - int soft_signal = SoftSignal(); - if (soft_signal != 0) { - const char *sig_str = SysSignal::Name(soft_signal); - DNBLogThreadedIf(LOG_EXCEPTIONS, - " exc_data: EXC_SOFT_SIGNAL (%i (%s))", - soft_signal, sig_str ? sig_str : "unknown signal"); - } else { - // No special disassembly for this data, just dump the data - size_t idx; - for (idx = 0; idx < exc_data_count; ++idx) { - DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_data[%llu]: 0x%llx", - (uint64_t)idx, (uint64_t)exc_data[idx]); - } - } -} - -// The EXC_MASK_ALL value hard-coded here so that lldb can be built -// on a new OS with an older deployment target . The new OS may have -// an addition to its EXC_MASK_ALL that the old OS will not recognize - -// <mach/exception_types.h> doesn't vary the value based on the deployment -// target. So we need a known set of masks that can be assumed to be -// valid when running on an older OS. We'll fall back to trying -// PREV_EXC_MASK_ALL if the EXC_MASK_ALL value lldb was compiled with is -// not recognized. - -#define PREV_EXC_MASK_ALL (EXC_MASK_BAD_ACCESS | \ - EXC_MASK_BAD_INSTRUCTION | \ - EXC_MASK_ARITHMETIC | \ - EXC_MASK_EMULATION | \ - EXC_MASK_SOFTWARE | \ - EXC_MASK_BREAKPOINT | \ - EXC_MASK_SYSCALL | \ - EXC_MASK_MACH_SYSCALL | \ - EXC_MASK_RPC_ALERT | \ - EXC_MASK_RESOURCE | \ - EXC_MASK_GUARD | \ - EXC_MASK_MACHINE) - -#define LLDB_EXC_MASK EXC_MASK_ALL - -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; - count = 0; - } - return err.Status(); -} - -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(); -} - -const char *MachException::Name(exception_type_t exc_type) { - switch (exc_type) { - case EXC_BAD_ACCESS: - return "EXC_BAD_ACCESS"; - case EXC_BAD_INSTRUCTION: - return "EXC_BAD_INSTRUCTION"; - case EXC_ARITHMETIC: - return "EXC_ARITHMETIC"; - case EXC_EMULATION: - return "EXC_EMULATION"; - case EXC_SOFTWARE: - return "EXC_SOFTWARE"; - case EXC_BREAKPOINT: - return "EXC_BREAKPOINT"; - case EXC_SYSCALL: - return "EXC_SYSCALL"; - case EXC_MACH_SYSCALL: - return "EXC_MACH_SYSCALL"; - case EXC_RPC_ALERT: - return "EXC_RPC_ALERT"; - case EXC_CRASH: - return "EXC_CRASH"; - case EXC_RESOURCE: - return "EXC_RESOURCE"; -#ifdef EXC_GUARD - case EXC_GUARD: - return "EXC_GUARD"; -#endif -#ifdef EXC_CORPSE_NOTIFY - case EXC_CORPSE_NOTIFY: - return "EXC_CORPSE_NOTIFY"; -#endif -#ifdef EXC_CORPSE_VARIANT_BIT - case EXC_CORPSE_VARIANT_BIT: - return "EXC_CORPSE_VARIANT_BIT"; -#endif - default: - break; - } - return NULL; -} |