bool plcrash_async_mach_exception_get_siginfo()

in Source/PLCrashAsyncMachExceptionInfo.c [55:177]


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;
}