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
}