1311128Sdim//===-- MachException.cpp ---------------------------------------*- C++ -*-===// 2311128Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6311128Sdim// 7311128Sdim//===----------------------------------------------------------------------===// 8311128Sdim// 9311128Sdim// Created by Greg Clayton on 6/18/07. 10311128Sdim// 11311128Sdim//===----------------------------------------------------------------------===// 12311128Sdim 13311128Sdim#include "MachException.h" 14311128Sdim 15311128Sdim// C includes 16311128Sdim#include <errno.h> 17311128Sdim#include <sys/ptrace.h> 18311128Sdim#include <sys/types.h> 19311128Sdim 20311128Sdim// C++ includes 21311128Sdim#include <mutex> 22311128Sdim 23311128Sdim// LLDB includes 24311128Sdim#include "lldb/Target/UnixSignals.h" 25311128Sdim#include "lldb/Utility/LLDBAssert.h" 26321369Sdim#include "lldb/Utility/Log.h" 27321369Sdim#include "lldb/Utility/Status.h" 28321369Sdim#include "lldb/Utility/Stream.h" 29311128Sdim 30311128Sdimusing namespace lldb; 31311128Sdimusing namespace lldb_private; 32311128Sdimusing namespace lldb_private::process_darwin; 33311128Sdim 34311128Sdim// Routine mach_exception_raise 35311128Sdimextern "C" kern_return_t 36311128Sdimcatch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, 37311128Sdim mach_port_t task, exception_type_t exception, 38311128Sdim mach_exception_data_t code, 39311128Sdim mach_msg_type_number_t codeCnt); 40311128Sdim 41311128Sdimextern "C" kern_return_t catch_mach_exception_raise_state( 42311128Sdim mach_port_t exception_port, exception_type_t exception, 43311128Sdim const mach_exception_data_t code, mach_msg_type_number_t codeCnt, 44311128Sdim int *flavor, const thread_state_t old_state, 45311128Sdim mach_msg_type_number_t old_stateCnt, thread_state_t new_state, 46311128Sdim mach_msg_type_number_t *new_stateCnt); 47311128Sdim 48311128Sdim// Routine mach_exception_raise_state_identity 49311128Sdimextern "C" kern_return_t catch_mach_exception_raise_state_identity( 50311128Sdim mach_port_t exception_port, mach_port_t thread, mach_port_t task, 51311128Sdim exception_type_t exception, mach_exception_data_t code, 52311128Sdim mach_msg_type_number_t codeCnt, int *flavor, thread_state_t old_state, 53311128Sdim mach_msg_type_number_t old_stateCnt, thread_state_t new_state, 54311128Sdim mach_msg_type_number_t *new_stateCnt); 55311128Sdim 56311128Sdimextern "C" boolean_t mach_exc_server(mach_msg_header_t *InHeadP, 57311128Sdim mach_msg_header_t *OutHeadP); 58311128Sdim 59311128Sdimstatic MachException::Data *g_message = NULL; 60311128Sdim 61311128Sdimextern "C" kern_return_t catch_mach_exception_raise_state( 62311128Sdim mach_port_t exc_port, exception_type_t exc_type, 63311128Sdim const mach_exception_data_t exc_data, mach_msg_type_number_t exc_data_count, 64311128Sdim int *flavor, const thread_state_t old_state, 65311128Sdim mach_msg_type_number_t old_stateCnt, thread_state_t new_state, 66311128Sdim mach_msg_type_number_t *new_stateCnt) { 67311128Sdim // TODO change to LIBLLDB_LOG_EXCEPTION 68311128Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 69311128Sdim if (log) { 70360784Sdim LLDB_LOGF(log, 71360784Sdim "::%s(exc_port = 0x%4.4x, exc_type = %d (%s), " 72360784Sdim "exc_data = 0x%llx, exc_data_count = %d)", 73360784Sdim __FUNCTION__, exc_port, exc_type, MachException::Name(exc_type), 74360784Sdim (uint64_t)exc_data, exc_data_count); 75311128Sdim } 76311128Sdim return KERN_FAILURE; 77311128Sdim} 78311128Sdim 79311128Sdimextern "C" kern_return_t catch_mach_exception_raise_state_identity( 80311128Sdim mach_port_t exc_port, mach_port_t thread_port, mach_port_t task_port, 81311128Sdim exception_type_t exc_type, mach_exception_data_t exc_data, 82311128Sdim mach_msg_type_number_t exc_data_count, int *flavor, 83311128Sdim thread_state_t old_state, mach_msg_type_number_t old_stateCnt, 84311128Sdim thread_state_t new_state, mach_msg_type_number_t *new_stateCnt) { 85311128Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 86311128Sdim if (log) { 87360784Sdim LLDB_LOGF(log, 88360784Sdim "::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, " 89360784Sdim "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d] = " 90360784Sdim "{ 0x%llx, 0x%llx })", 91360784Sdim __FUNCTION__, exc_port, thread_port, task_port, exc_type, 92360784Sdim MachException::Name(exc_type), exc_data_count, 93360784Sdim (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), 94360784Sdim (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); 95311128Sdim } 96311128Sdim 97311128Sdim return KERN_FAILURE; 98311128Sdim} 99311128Sdim 100311128Sdimextern "C" kern_return_t 101311128Sdimcatch_mach_exception_raise(mach_port_t exc_port, mach_port_t thread_port, 102311128Sdim mach_port_t task_port, exception_type_t exc_type, 103311128Sdim mach_exception_data_t exc_data, 104311128Sdim mach_msg_type_number_t exc_data_count) { 105311128Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 106311128Sdim if (log) { 107360784Sdim LLDB_LOGF(log, 108360784Sdim "::%s(exc_port = 0x%4.4x, thd_port = 0x%4.4x, " 109360784Sdim "tsk_port = 0x%4.4x, exc_type = %d (%s), exc_data[%d] " 110360784Sdim "= { 0x%llx, 0x%llx })", 111360784Sdim __FUNCTION__, exc_port, thread_port, task_port, exc_type, 112360784Sdim MachException::Name(exc_type), exc_data_count, 113360784Sdim (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), 114360784Sdim (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); 115311128Sdim } 116311128Sdim 117311128Sdim if (task_port == g_message->task_port) { 118311128Sdim g_message->task_port = task_port; 119311128Sdim g_message->thread_port = thread_port; 120311128Sdim g_message->exc_type = exc_type; 121311128Sdim g_message->exc_data.resize(exc_data_count); 122311128Sdim ::memcpy(&g_message->exc_data[0], exc_data, 123311128Sdim g_message->exc_data.size() * sizeof(mach_exception_data_type_t)); 124311128Sdim return KERN_SUCCESS; 125311128Sdim } 126311128Sdim return KERN_FAILURE; 127311128Sdim} 128311128Sdim 129311128Sdimbool MachException::Data::GetStopInfo(struct ThreadStopInfo *stop_info, 130311128Sdim const UnixSignals &signals, 131311128Sdim Stream &stream) const { 132311128Sdim if (!stop_info) 133311128Sdim return false; 134311128Sdim 135311128Sdim // Zero out the structure. 136311128Sdim memset(stop_info, 0, sizeof(struct ThreadStopInfo)); 137311128Sdim 138311128Sdim if (exc_type == 0) { 139311128Sdim stop_info->reason = eStopReasonInvalid; 140311128Sdim return true; 141311128Sdim } 142311128Sdim 143311128Sdim // We always stop with a mach exception. 144311128Sdim stop_info->reason = eStopReasonException; 145311128Sdim // Save the EXC_XXXX exception type. 146311128Sdim stop_info->details.exception.type = exc_type; 147311128Sdim 148311128Sdim // Fill in a text description 149311128Sdim const char *exc_name = MachException::Name(exc_type); 150311128Sdim if (exc_name) 151311128Sdim stream.Printf("%s", exc_name); 152311128Sdim else 153311128Sdim stream.Printf("%i", exc_type); 154311128Sdim 155311128Sdim stop_info->details.exception.data_count = exc_data.size(); 156311128Sdim 157311128Sdim int soft_signal = SoftSignal(); 158311128Sdim if (soft_signal) { 159311128Sdim const char *sig_str = signals.GetSignalAsCString(soft_signal); 160311128Sdim stream.Printf(" EXC_SOFT_SIGNAL( %i ( %s ))", soft_signal, 161311128Sdim sig_str ? sig_str : "unknown signal"); 162311128Sdim } else { 163311128Sdim // No special disassembly for exception data, just print it. 164311128Sdim size_t idx; 165311128Sdim stream.Printf(" data[%llu] = {", 166311128Sdim (uint64_t)stop_info->details.exception.data_count); 167311128Sdim 168311128Sdim for (idx = 0; idx < stop_info->details.exception.data_count; ++idx) { 169311128Sdim stream.Printf( 170311128Sdim "0x%llx%c", (uint64_t)exc_data[idx], 171311128Sdim ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ',')); 172311128Sdim } 173311128Sdim } 174311128Sdim 175311128Sdim // Copy the exception data 176311128Sdim for (size_t i = 0; i < stop_info->details.exception.data_count; i++) 177311128Sdim stop_info->details.exception.data[i] = exc_data[i]; 178311128Sdim 179311128Sdim return true; 180311128Sdim} 181311128Sdim 182321369SdimStatus MachException::Message::Receive(mach_port_t port, 183321369Sdim mach_msg_option_t options, 184321369Sdim mach_msg_timeout_t timeout, 185321369Sdim mach_port_t notify_port) { 186321369Sdim Status error; 187311128Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 188311128Sdim 189311128Sdim mach_msg_timeout_t mach_msg_timeout = 190311128Sdim options & MACH_RCV_TIMEOUT ? timeout : 0; 191311128Sdim if (log && ((options & MACH_RCV_TIMEOUT) == 0)) { 192311128Sdim // Dump this log message if we have no timeout in case it never returns 193360784Sdim LLDB_LOGF(log, 194360784Sdim "::mach_msg(msg->{bits = %#x, size = %u remote_port = %#x, " 195360784Sdim "local_port = %#x, reserved = 0x%x, id = 0x%x}, " 196360784Sdim "option = %#x, send_size = 0, rcv_size = %llu, " 197360784Sdim "rcv_name = %#x, timeout = %u, notify = %#x)", 198360784Sdim exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, 199360784Sdim exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, 200360784Sdim exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, 201360784Sdim (uint64_t)sizeof(exc_msg.data), port, mach_msg_timeout, 202360784Sdim notify_port); 203311128Sdim } 204311128Sdim 205311128Sdim mach_msg_return_t mach_err = 206311128Sdim ::mach_msg(&exc_msg.hdr, 207311128Sdim options, // options 208311128Sdim 0, // Send size 209311128Sdim sizeof(exc_msg.data), // Receive size 210311128Sdim port, // exception port to watch for 211311128Sdim // exception on 212311128Sdim mach_msg_timeout, // timeout in msec (obeyed only 213311128Sdim // if MACH_RCV_TIMEOUT is ORed 214311128Sdim // into the options parameter) 215311128Sdim notify_port); 216311128Sdim error.SetError(mach_err, eErrorTypeMachKernel); 217311128Sdim 218311128Sdim // Dump any errors we get 219311128Sdim if (error.Fail() && log) { 220360784Sdim LLDB_LOGF(log, 221360784Sdim "::mach_msg(msg->{bits = %#x, size = %u remote_port = %#x, " 222360784Sdim "local_port = %#x, reserved = 0x%x, id = 0x%x}, " 223360784Sdim "option = %#x, send_size = %u, rcv_size = %lu, rcv_name " 224360784Sdim "= %#x, timeout = %u, notify = %#x) failed: %s", 225360784Sdim exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, 226360784Sdim exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, 227360784Sdim exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, 0, 228360784Sdim sizeof(exc_msg.data), port, mach_msg_timeout, notify_port, 229360784Sdim error.AsCString()); 230311128Sdim } 231311128Sdim return error; 232311128Sdim} 233311128Sdim 234311128Sdimvoid MachException::Message::Dump(Stream &stream) const { 235311128Sdim stream.Printf(" exc_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = " 236311128Sdim "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = " 237311128Sdim "0x%8.8x }\n", 238311128Sdim exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, 239311128Sdim exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, 240311128Sdim exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id); 241311128Sdim 242311128Sdim stream.Printf(" reply_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = " 243311128Sdim "0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = " 244311128Sdim "0x%8.8x }", 245311128Sdim reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, 246311128Sdim reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, 247311128Sdim reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id); 248311128Sdim} 249311128Sdim 250311128Sdimbool MachException::Message::CatchExceptionRaise(task_t task) { 251311128Sdim bool success = false; 252311128Sdim state.task_port = task; 253311128Sdim g_message = &state; 254341825Sdim // The exc_server function is the MIG generated server handling function to 255341825Sdim // handle messages from the kernel relating to the occurrence of an exception 256341825Sdim // in a thread. Such messages are delivered to the exception port set via 257341825Sdim // thread_set_exception_ports or task_set_exception_ports. When an exception 258341825Sdim // occurs in a thread, the thread sends an exception message to its exception 259341825Sdim // port, blocking in the kernel waiting for the receipt of a reply. The 260341825Sdim // exc_server function performs all necessary argument handling for this 261341825Sdim // kernel message and calls catch_exception_raise, 262341825Sdim // catch_exception_raise_state or catch_exception_raise_state_identity, which 263341825Sdim // should handle the exception. If the called routine returns KERN_SUCCESS, a 264341825Sdim // reply message will be sent, allowing the thread to continue from the point 265341825Sdim // of the exception; otherwise, no reply message is sent and the called 266341825Sdim // routine must have dealt with the exception thread directly. 267311128Sdim if (mach_exc_server(&exc_msg.hdr, &reply_msg.hdr)) { 268311128Sdim success = true; 269311128Sdim } else { 270311128Sdim Log *log( 271311128Sdim GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 272360784Sdim LLDB_LOGF(log, 273360784Sdim "MachException::Message::%s(): mach_exc_server " 274360784Sdim "returned zero...", 275360784Sdim __FUNCTION__); 276311128Sdim } 277311128Sdim g_message = NULL; 278311128Sdim return success; 279311128Sdim} 280311128Sdim 281321369SdimStatus MachException::Message::Reply(::pid_t inferior_pid, task_t inferior_task, 282321369Sdim int signal) { 283311128Sdim // Reply to the exception... 284321369Sdim Status error; 285311128Sdim 286311128Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 287311128Sdim 288311128Sdim // If we had a soft signal, we need to update the thread first so it can 289311128Sdim // continue without signaling 290311128Sdim int soft_signal = state.SoftSignal(); 291311128Sdim if (soft_signal) { 292311128Sdim int state_pid = -1; 293311128Sdim if (inferior_task == state.task_port) { 294311128Sdim // This is our task, so we can update the signal to send to it 295311128Sdim state_pid = inferior_pid; 296311128Sdim soft_signal = signal; 297311128Sdim } else { 298311128Sdim auto mach_err = ::pid_for_task(state.task_port, &state_pid); 299311128Sdim if (mach_err) { 300311128Sdim error.SetError(mach_err, eErrorTypeMachKernel); 301360784Sdim LLDB_LOGF(log, 302360784Sdim "MachException::Message::%s(): pid_for_task() " 303360784Sdim "failed: %s", 304360784Sdim __FUNCTION__, error.AsCString()); 305311128Sdim return error; 306311128Sdim } 307311128Sdim } 308311128Sdim 309311128Sdim lldbassert(state_pid != -1); 310311128Sdim if (state_pid != -1) { 311311128Sdim errno = 0; 312311128Sdim caddr_t thread_port_caddr = (caddr_t)(uintptr_t)state.thread_port; 313311128Sdim if (::ptrace(PT_THUPDATE, state_pid, thread_port_caddr, soft_signal) != 0) 314311128Sdim error.SetError(errno, eErrorTypePOSIX); 315311128Sdim 316311128Sdim if (!error.Success()) { 317360784Sdim LLDB_LOGF(log, 318360784Sdim "::ptrace(request = PT_THUPDATE, pid = " 319360784Sdim "0x%4.4x, tid = 0x%4.4x, signal = %i)", 320360784Sdim state_pid, state.thread_port, soft_signal); 321311128Sdim return error; 322311128Sdim } 323311128Sdim } 324311128Sdim } 325311128Sdim 326360784Sdim LLDB_LOGF(log, 327360784Sdim "::mach_msg ( msg->{bits = %#x, size = %u, remote_port " 328360784Sdim "= %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, " 329360784Sdim "option = %#x, send_size = %u, rcv_size = %u, rcv_name " 330360784Sdim "= %#x, timeout = %u, notify = %#x)", 331360784Sdim reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, 332360784Sdim reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, 333360784Sdim reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id, 334360784Sdim MACH_SEND_MSG | MACH_SEND_INTERRUPT, reply_msg.hdr.msgh_size, 0, 335360784Sdim MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 336311128Sdim 337311128Sdim auto mach_err = 338311128Sdim ::mach_msg(&reply_msg.hdr, MACH_SEND_MSG | MACH_SEND_INTERRUPT, 339311128Sdim reply_msg.hdr.msgh_size, 0, MACH_PORT_NULL, 340311128Sdim MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 341311128Sdim if (mach_err) 342311128Sdim error.SetError(mach_err, eErrorTypeMachKernel); 343311128Sdim 344311128Sdim // Log our error if we have one. 345311128Sdim if (error.Fail() && log) { 346311128Sdim if (error.GetError() == MACH_SEND_INTERRUPTED) { 347311128Sdim log->PutCString("::mach_msg() - send interrupted"); 348311128Sdim // TODO: keep retrying to reply??? 349311128Sdim } else if (state.task_port == inferior_task) { 350360784Sdim LLDB_LOGF(log, 351360784Sdim "mach_msg(): returned an error when replying " 352360784Sdim "to a mach exception: error = %u (%s)", 353360784Sdim error.GetError(), error.AsCString()); 354311128Sdim } else { 355360784Sdim LLDB_LOGF(log, "::mach_msg() - failed (child of task): %u (%s)", 356360784Sdim error.GetError(), error.AsCString()); 357311128Sdim } 358311128Sdim } 359311128Sdim 360311128Sdim return error; 361311128Sdim} 362311128Sdim 363311128Sdim#define PREV_EXC_MASK_ALL \ 364311128Sdim (EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | \ 365311128Sdim EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | \ 366311128Sdim EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | \ 367311128Sdim EXC_MASK_MACHINE) 368311128Sdim 369311128Sdim// Don't listen for EXC_RESOURCE, it should really get handled by the system 370311128Sdim// handler. 371311128Sdim 372311128Sdim#ifndef EXC_RESOURCE 373311128Sdim#define EXC_RESOURCE 11 374311128Sdim#endif 375311128Sdim 376311128Sdim#ifndef EXC_MASK_RESOURCE 377311128Sdim#define EXC_MASK_RESOURCE (1 << EXC_RESOURCE) 378311128Sdim#endif 379311128Sdim 380311128Sdim#define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE) 381311128Sdim 382321369SdimStatus MachException::PortInfo::Save(task_t task) { 383321369Sdim Status error; 384311128Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 385311128Sdim 386360784Sdim LLDB_LOGF(log, "MachException::PortInfo::%s(task = 0x%4.4x)", __FUNCTION__, 387360784Sdim task); 388311128Sdim 389341825Sdim // Be careful to be able to have debugserver built on a newer OS than what it 390341825Sdim // is currently running on by being able to start with all exceptions and 391341825Sdim // back off to just what is supported on the current system 392311128Sdim mask = LLDB_EXC_MASK; 393311128Sdim 394311128Sdim count = (sizeof(ports) / sizeof(ports[0])); 395311128Sdim auto mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports, 396311128Sdim behaviors, flavors); 397311128Sdim if (mach_err) 398311128Sdim error.SetError(mach_err, eErrorTypeMachKernel); 399311128Sdim 400311128Sdim if (log) { 401311128Sdim if (error.Success()) { 402360784Sdim LLDB_LOGF(log, 403360784Sdim "::task_get_exception_ports(task = 0x%4.4x, mask = " 404360784Sdim "0x%x, maskCnt => %u, ports, behaviors, flavors)", 405360784Sdim task, mask, count); 406311128Sdim } else { 407360784Sdim LLDB_LOGF(log, 408360784Sdim "::task_get_exception_ports(task = 0x%4.4x, mask = 0x%x, " 409360784Sdim "maskCnt => %u, ports, behaviors, flavors) error: %u (%s)", 410360784Sdim task, mask, count, error.GetError(), error.AsCString()); 411311128Sdim } 412311128Sdim } 413311128Sdim 414311128Sdim if ((error.GetError() == KERN_INVALID_ARGUMENT) && 415311128Sdim (mask != PREV_EXC_MASK_ALL)) { 416311128Sdim mask = PREV_EXC_MASK_ALL; 417311128Sdim count = (sizeof(ports) / sizeof(ports[0])); 418311128Sdim mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports, 419311128Sdim behaviors, flavors); 420311128Sdim error.SetError(mach_err, eErrorTypeMachKernel); 421311128Sdim if (log) { 422311128Sdim if (error.Success()) { 423360784Sdim LLDB_LOGF(log, 424360784Sdim "::task_get_exception_ports(task = 0x%4.4x, " 425360784Sdim "mask = 0x%x, maskCnt => %u, ports, behaviors, " 426360784Sdim "flavors)", 427360784Sdim task, mask, count); 428311128Sdim } else { 429360784Sdim LLDB_LOGF(log, 430360784Sdim "::task_get_exception_ports(task = 0x%4.4x, mask = " 431360784Sdim "0x%x, maskCnt => %u, ports, behaviors, flavors) " 432360784Sdim "error: %u (%s)", 433360784Sdim task, mask, count, error.GetError(), error.AsCString()); 434311128Sdim } 435311128Sdim } 436311128Sdim } 437311128Sdim if (error.Fail()) { 438311128Sdim mask = 0; 439311128Sdim count = 0; 440311128Sdim } 441311128Sdim return error; 442311128Sdim} 443311128Sdim 444321369SdimStatus MachException::PortInfo::Restore(task_t task) { 445321369Sdim Status error; 446311128Sdim 447311128Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); 448311128Sdim 449360784Sdim LLDB_LOGF(log, "MachException::PortInfo::Restore(task = 0x%4.4x)", task); 450311128Sdim 451311128Sdim uint32_t i = 0; 452311128Sdim if (count > 0) { 453311128Sdim for (i = 0; i < count; i++) { 454311128Sdim auto mach_err = ::task_set_exception_ports(task, masks[i], ports[i], 455311128Sdim behaviors[i], flavors[i]); 456311128Sdim if (mach_err) 457311128Sdim error.SetError(mach_err, eErrorTypeMachKernel); 458311128Sdim if (log) { 459311128Sdim if (error.Success()) { 460360784Sdim LLDB_LOGF(log, 461360784Sdim "::task_set_exception_ports(task = 0x%4.4x, " 462360784Sdim "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " 463360784Sdim "behavior = 0x%8.8x, new_flavor = 0x%8.8x)", 464360784Sdim task, masks[i], ports[i], behaviors[i], flavors[i]); 465311128Sdim } else { 466360784Sdim LLDB_LOGF(log, 467360784Sdim "::task_set_exception_ports(task = 0x%4.4x, " 468360784Sdim "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " 469360784Sdim "behavior = 0x%8.8x, new_flavor = 0x%8.8x): " 470360784Sdim "error %u (%s)", 471360784Sdim task, masks[i], ports[i], behaviors[i], flavors[i], 472360784Sdim error.GetError(), error.AsCString()); 473311128Sdim } 474311128Sdim } 475311128Sdim 476311128Sdim // Bail if we encounter any errors 477311128Sdim if (error.Fail()) 478311128Sdim break; 479311128Sdim } 480311128Sdim } 481311128Sdim 482311128Sdim count = 0; 483311128Sdim return error; 484311128Sdim} 485311128Sdim 486311128Sdimconst char *MachException::Name(exception_type_t exc_type) { 487311128Sdim switch (exc_type) { 488311128Sdim case EXC_BAD_ACCESS: 489311128Sdim return "EXC_BAD_ACCESS"; 490311128Sdim case EXC_BAD_INSTRUCTION: 491311128Sdim return "EXC_BAD_INSTRUCTION"; 492311128Sdim case EXC_ARITHMETIC: 493311128Sdim return "EXC_ARITHMETIC"; 494311128Sdim case EXC_EMULATION: 495311128Sdim return "EXC_EMULATION"; 496311128Sdim case EXC_SOFTWARE: 497311128Sdim return "EXC_SOFTWARE"; 498311128Sdim case EXC_BREAKPOINT: 499311128Sdim return "EXC_BREAKPOINT"; 500311128Sdim case EXC_SYSCALL: 501311128Sdim return "EXC_SYSCALL"; 502311128Sdim case EXC_MACH_SYSCALL: 503311128Sdim return "EXC_MACH_SYSCALL"; 504311128Sdim case EXC_RPC_ALERT: 505311128Sdim return "EXC_RPC_ALERT"; 506311128Sdim#ifdef EXC_CRASH 507311128Sdim case EXC_CRASH: 508311128Sdim return "EXC_CRASH"; 509311128Sdim#endif 510311128Sdim default: 511311128Sdim break; 512311128Sdim } 513311128Sdim return NULL; 514311128Sdim} 515