Source/PLCrashAsyncMachExceptionInfo.c (98 lines of code) (raw):

/* * Author: Landon Fuller <landonf@plausiblelabs.com> * * Copyright (c) 2013 Plausible Labs Cooperative, Inc. * All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "PLCrashAsyncMachExceptionInfo.h" #include "PLCrashFeatureConfig.h" #if PLCRASH_FEATURE_MACH_EXCEPTIONS /** * @ingroup plcrash_async_mach_exception_info * @{ */ /** * @internal * * Map a Mach exception to its BSD signal representation. * * @param exception_type Mach exception type. * @param codes Mach exception codes. * @param code_count The number of codes provided. * @param cpu_type The target architecture on which the exception was generated, encoded as a Mach-O CPU type. Interpreting Mach exception data is * architecture-specific. If the CPU type is unknown, CPU_TYPE_ANY may be provided. * @param siginfo The siginfo structure to be initialized. * * @warning Mapping to BSD signal information is primarily supported to maintain backwards compatibility with existing report handlers * that expect to receive BSD signal data, rather than Mach exception data. Note, however, that the returned signal info may not exactly match the * kernel exception-to-signal mappings implemented in xnu. As such, when Mach exception data is available, its use should be preferred. */ bool plcrash_async_mach_exception_get_siginfo (exception_type_t exception_type, mach_exception_data_t codes, mach_msg_type_number_t code_count, cpu_type_t cpu_type, siginfo_t *siginfo) { if (code_count < 2) { PLCF_DEBUG("Unexpected Mach code count of %u; can't map to UNIX exception", code_count); return false; } mach_exception_code_t code = codes[0]; mach_exception_subcode_t subcode = codes[1]; /* Set the si_signo and si_addr */ switch (exception_type) { case EXC_BAD_ACCESS: /* * XXX: Stack overflow should result in a SIGSEGV, but a guard page access will trigger KERN_PROTECTION_FAILURE (SIGBUS). * To map to SIGSEGV in this case, we would need to know whether the faulting address is within the stack guard pages -- * since this is not available, we'll map to the incorrect SIGBUS. */ if (code == KERN_INVALID_ADDRESS) { siginfo->si_signo = SIGSEGV; } else { siginfo->si_signo = SIGBUS; } siginfo->si_addr = (void *)subcode; break; case EXC_BAD_INSTRUCTION: siginfo->si_signo = SIGILL; siginfo->si_addr = (void *)subcode; break; case EXC_ARITHMETIC: siginfo->si_signo = SIGFPE; siginfo->si_addr = (void *)subcode; break; case EXC_EMULATION: siginfo->si_signo = SIGEMT; siginfo->si_addr = (void *)subcode; break; case EXC_SOFTWARE: switch (code) { case EXC_UNIX_BAD_SYSCALL: siginfo->si_signo = SIGSYS; break; case EXC_UNIX_BAD_PIPE: siginfo->si_signo = SIGPIPE; break; case EXC_UNIX_ABORT: siginfo->si_signo = SIGABRT; break; case EXC_SOFT_SIGNAL: siginfo->si_signo = SIGKILL; break; default: PLCF_DEBUG("Unexpected EXC_SOFTWARE code of %lld", code); siginfo->si_signo = SIGABRT; break; } siginfo->si_addr = (void *)subcode; break; case EXC_BREAKPOINT: siginfo->si_signo = SIGTRAP; siginfo->si_addr = (void *)subcode; break; default: return false; } /* Set the si_code */ switch (siginfo->si_signo) { case SIGSEGV: switch (code) { case KERN_PROTECTION_FAILURE: siginfo->si_code = SEGV_ACCERR; break; case KERN_INVALID_ADDRESS: siginfo->si_code = SEGV_MAPERR; break; default: siginfo->si_code = SEGV_NOOP; break; } break; case SIGBUS: siginfo->si_code = BUS_ADRERR; break; case SIGILL: siginfo->si_code = ILL_NOOP; break; case SIGFPE: siginfo->si_code = FPE_NOOP; break; case SIGTRAP: siginfo->si_code = TRAP_BRKPT; break; case SIGEMT: case SIGSYS: case SIGPIPE: case SIGABRT: case SIGKILL: siginfo->si_code = 0x0; break; default: return false; } return true; } /** * @} plcrash_async_mach_exception_info */ #endif /* PLCRASH_FEATURE_MACH_EXCEPTIONS */