#include <mach_kdb.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/message.h>
#include <mach/port.h>
#include <mach/mig_errors.h>
#include <mach/thread_status.h>
#include <mach/exception_types.h>
#include <ipc/port.h>
#include <ipc/ipc_entry.h>
#include <ipc/ipc_object.h>
#include <ipc/ipc_notify.h>
#include <ipc/ipc_space.h>
#include <ipc/ipc_pset.h>
#include <ipc/ipc_machdep.h>
#include <kern/etap_macros.h>
#include <kern/counters.h>
#include <kern/ipc_tt.h>
#include <kern/task.h>
#include <kern/thread.h>
#include <kern/thread_swap.h>
#include <kern/processor.h>
#include <kern/sched.h>
#include <kern/sched_prim.h>
#include <kern/host.h>
#include <kern/misc_protos.h>
#include <string.h>
#include <mach/exc.h>
#if MACH_KDB
#include <ddb/db_trap.h>
#endif
#if MACH_KDB
#include <ddb/db_output.h>
#if iPSC386 || iPSC860
boolean_t debug_user_with_kdb = TRUE;
#else
boolean_t debug_user_with_kdb = FALSE;
#endif
#endif
unsigned long c_thr_exc_raise = 0;
unsigned long c_thr_exc_raise_state = 0;
unsigned long c_thr_exc_raise_state_id = 0;
unsigned long c_tsk_exc_raise = 0;
unsigned long c_tsk_exc_raise_state = 0;
unsigned long c_tsk_exc_raise_state_id = 0;
void
exception_deliver(
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt,
struct exception_action *excp,
mutex_t *mutex)
{
thread_act_t a_self = current_act();
ipc_port_t exc_port;
int behavior;
int flavor;
kern_return_t kr;
if (!a_self->active)
thread_exception_return();
mutex_lock(mutex);
exc_port = excp->port;
if (!IP_VALID(exc_port)) {
mutex_unlock(mutex);
return;
}
ip_lock(exc_port);
if (!ip_active(exc_port)) {
ip_unlock(exc_port);
mutex_unlock(mutex);
return;
}
ip_reference(exc_port);
exc_port->ip_srights++;
ip_unlock(exc_port);
flavor = excp->flavor;
behavior = excp->behavior;
mutex_unlock(mutex);
switch (behavior) {
case EXCEPTION_STATE: {
mach_msg_type_number_t state_cnt;
natural_t state[ THREAD_MACHINE_STATE_MAX ];
c_thr_exc_raise_state++;
state_cnt = state_count[flavor];
kr = thread_getstatus(a_self, flavor,
(thread_state_t)state,
&state_cnt);
if (kr == KERN_SUCCESS) {
kr = exception_raise_state(exc_port, exception,
code, codeCnt,
&flavor,
state, state_cnt,
state, &state_cnt);
if (kr == MACH_MSG_SUCCESS)
kr = thread_setstatus(a_self, flavor,
(thread_state_t)state,
state_cnt);
}
if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
thread_exception_return();
return;
}
case EXCEPTION_DEFAULT:
c_thr_exc_raise++;
kr = exception_raise(exc_port,
retrieve_act_self_fast(a_self),
retrieve_task_self_fast(a_self->task),
exception,
code, codeCnt);
if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
thread_exception_return();
return;
case EXCEPTION_STATE_IDENTITY: {
mach_msg_type_number_t state_cnt;
natural_t state[ THREAD_MACHINE_STATE_MAX ];
c_thr_exc_raise_state_id++;
state_cnt = state_count[flavor];
kr = thread_getstatus(a_self, flavor,
(thread_state_t)state,
&state_cnt);
if (kr == KERN_SUCCESS) {
kr = exception_raise_state_identity(exc_port,
retrieve_act_self_fast(a_self),
retrieve_task_self_fast(a_self->task),
exception,
code, codeCnt,
&flavor,
state, state_cnt,
state, &state_cnt);
if (kr == MACH_MSG_SUCCESS)
kr = thread_setstatus(a_self, flavor,
(thread_state_t)state,
state_cnt);
}
if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
thread_exception_return();
return;
}
default:
panic ("bad exception behavior!");
}
}
void
exception(
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt)
{
thread_act_t thr_act;
task_t task;
host_priv_t host_priv;
struct exception_action *excp;
mutex_t *mutex;
assert(exception != EXC_RPC_ALERT);
if (exception == KERN_SUCCESS)
panic("exception");
thr_act = current_act();
mutex = mutex_addr(thr_act->lock);
excp = &thr_act->exc_actions[exception];
exception_deliver(exception, code, codeCnt, excp, mutex);
task = current_task();
mutex = mutex_addr(task->lock);
excp = &task->exc_actions[exception];
exception_deliver(exception, code, codeCnt, excp, mutex);
host_priv = host_priv_self();
mutex = mutex_addr(host_priv->lock);
excp = &host_priv->exc_actions[exception];
exception_deliver(exception, code, codeCnt, excp, mutex);
#if MACH_KDB
if (debug_user_with_kdb) {
db_printf("No exception server, calling kdb...\n");
thread_kdb_return();
}
#endif
(void) task_terminate(task);
thread_exception_return();
}
kern_return_t
bsd_exception(
exception_type_t exception,
exception_data_t code,
mach_msg_type_number_t codeCnt)
{
task_t task;
host_priv_t host_priv;
struct exception_action *excp;
mutex_t *mutex;
thread_act_t a_self = current_act();
ipc_port_t exc_port;
int behavior;
int flavor;
kern_return_t kr;
task = current_task();
mutex = mutex_addr(task->lock);
excp = &task->exc_actions[exception];
if (!a_self->active) {
return(KERN_FAILURE);
}
mutex_lock(mutex);
exc_port = excp->port;
if (!IP_VALID(exc_port)) {
mutex_unlock(mutex);
return(KERN_FAILURE);
}
ip_lock(exc_port);
if (!ip_active(exc_port)) {
ip_unlock(exc_port);
mutex_unlock(mutex);
return(KERN_FAILURE);
}
ip_reference(exc_port);
exc_port->ip_srights++;
ip_unlock(exc_port);
flavor = excp->flavor;
behavior = excp->behavior;
mutex_unlock(mutex);
switch (behavior) {
case EXCEPTION_STATE: {
mach_msg_type_number_t state_cnt;
natural_t state[ THREAD_MACHINE_STATE_MAX ];
c_thr_exc_raise_state++;
state_cnt = state_count[flavor];
kr = thread_getstatus(a_self, flavor,
(thread_state_t)state,
&state_cnt);
if (kr == KERN_SUCCESS) {
kr = exception_raise_state(exc_port, exception,
code, codeCnt,
&flavor,
state, state_cnt,
state, &state_cnt);
if (kr == MACH_MSG_SUCCESS)
kr = thread_setstatus(a_self, flavor,
(thread_state_t)state,
state_cnt);
}
if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
return(KERN_SUCCESS);
return(KERN_FAILURE);
}
case EXCEPTION_DEFAULT:
c_thr_exc_raise++;
kr = exception_raise(exc_port,
retrieve_act_self_fast(a_self),
retrieve_task_self_fast(a_self->task),
exception,
code, codeCnt);
if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
return(KERN_SUCCESS);
return(KERN_FAILURE);
case EXCEPTION_STATE_IDENTITY: {
mach_msg_type_number_t state_cnt;
natural_t state[ THREAD_MACHINE_STATE_MAX ];
c_thr_exc_raise_state_id++;
state_cnt = state_count[flavor];
kr = thread_getstatus(a_self, flavor,
(thread_state_t)state,
&state_cnt);
if (kr == KERN_SUCCESS) {
kr = exception_raise_state_identity(exc_port,
retrieve_act_self_fast(a_self),
retrieve_task_self_fast(a_self->task),
exception,
code, codeCnt,
&flavor,
state, state_cnt,
state, &state_cnt);
if (kr == MACH_MSG_SUCCESS)
kr = thread_setstatus(a_self, flavor,
(thread_state_t)state,
state_cnt);
}
if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
return(KERN_SUCCESS);
return(KERN_FAILURE);
}
default:
return(KERN_FAILURE);
}
return(KERN_FAILURE);
}