kern_return_t PLCrashMachExceptionForward()

in Source/PLCrashMachExceptionServer.m [527:643]


kern_return_t PLCrashMachExceptionForward (task_t task,
                                           thread_t thread,
                                           exception_type_t exception_type,
                                           mach_exception_data_t code,
                                           mach_msg_type_number_t code_count,
                                           plcrash_mach_exception_port_set_t *port_state)
{
#pragma clang diagnostic push
/**
 * Disable uninitialized variable warnings for `behavior`, `flavor`, `port` and `thread_state_count` which will be triggered 
 * if the build setting for Uninitialized Variables Warning is Yes (Aggressive)
 * behavior, flavor and port can be seen to be either initialized in the loop (found -> true) or the function will exit (found -> false)
 * thread_state_count will be initialized for all cases except behavior == EXCEPTION_DEFAULT, in which case the thread_state_count is not used in the `switch (behavior)` block
 */
#pragma clang diagnostic ignored "-Wconditional-uninitialized"

    exception_behavior_t behavior;
    thread_state_flavor_t flavor;
    mach_port_t port;
    
    /* Find a matching handler */
    exception_mask_t fwd_mask = exception_to_mask(exception_type);
    bool found = false;
    for (mach_msg_type_number_t i = 0; i < port_state->count; i++) {
        if (!MACH_PORT_VALID(port_state->ports[i]))
            continue;
        
        if ((port_state->masks[i] & fwd_mask) == 0)
            continue;
        
        found = true;
        port = port_state->ports[i];
        behavior = port_state->behaviors[i];
        flavor = port_state->flavors[i];
        break;
    }
    
    /* No handler found */
    if (!found) {
        return KERN_FAILURE;
    }
    
    thread_state_data_t thread_state;
    mach_msg_type_number_t thread_state_count;
    kern_return_t kr;
    
    /* We prefer 64-bit codes; if the user requests 32-bit codes, we need to map them */
    exception_data_type_t code32[code_count];
    for (mach_msg_type_number_t i = 0; i < code_count; i++) {
        code32[i] = (exception_data_type_t)code[i];
    }
    
    /* Strip the MACH_EXCEPTION_CODES modifier from the behavior flags */
    bool mach_exc_codes = false;
    if (behavior & MACH_EXCEPTION_CODES) {
        mach_exc_codes = true;
        behavior &= ~MACH_EXCEPTION_CODES;
    }
    
    /*
     * Fetch thread state if required. When not required, 'flavor' will be invalid (eg, THREAD_STATE_NONE or similar), and
     * fetching the thread state will simply fail.
     */
    if (behavior != EXCEPTION_DEFAULT) {
        thread_state_count = THREAD_STATE_MAX;
        kr = thread_get_state (thread, flavor, thread_state, &thread_state_count);
        if (kr != KERN_SUCCESS) {
            PLCF_DEBUG("Failed to fetch thread state for thread=0x%x, flavor=0x%x, kr=0x%x", thread, flavor, kr);
            return kr;
        }
    }
    
    /* Handle the supported behaviors */
    switch (behavior) {
        case EXCEPTION_DEFAULT:
            if (mach_exc_codes) {
#if PL_MACH64_EXC_API
                return mach_exception_raise(port, thread, task, exception_type, code, code_count);
#endif
            } else {
                return exception_raise(port, thread, task, exception_type, code32, code_count);
            }
            break;
            
        case EXCEPTION_STATE:
            if (mach_exc_codes) {
#if PL_MACH64_EXC_API
                return mach_exception_raise_state(port, exception_type, code, code_count, &flavor, thread_state,
                                                  thread_state_count, thread_state, &thread_state_count);
#endif
            } else {
                return exception_raise_state(port, exception_type, code32, code_count, &flavor, thread_state,
                                             thread_state_count, thread_state, &thread_state_count);
            }
            break;
            
        case EXCEPTION_STATE_IDENTITY:
            if (mach_exc_codes) {
#if PL_MACH64_EXC_API
                return mach_exception_raise_state_identity(port, thread, task, exception_type, code,
                                                           code_count, &flavor, thread_state, thread_state_count, thread_state, &thread_state_count);
#endif
            } else {
                return exception_raise_state_identity(port, thread, task, exception_type, code32,
                                                      code_count, &flavor, thread_state, thread_state_count, thread_state, &thread_state_count);
            }
            break;
            
        default:
            /* Handled below */
            break;
    }
    
    PLCF_DEBUG("Unsupported exception behavior: 0x%x (MACH_EXCEPTION_CODES=%s)", behavior, mach_exc_codes ? "true" : "false");
    return KERN_FAILURE;
#pragma clang diagnostic pop
}