Exemplo n.º 1
0
/* The source code for Apple's GDB was used as a reference for the exception
   forwarding code. This code is similar to the GDB code only because there is 
   only one way to do it. */
static kern_return_t forward_exception(
        mach_port_t thread,
        mach_port_t task,
        exception_type_t exception,
        exception_data_t data,
        mach_msg_type_number_t data_count
) {
    int i;
    kern_return_t r;
    mach_port_t port;
    exception_behavior_t behavior;
    thread_state_flavor_t flavor;
    
    thread_state_data_t thread_state;
    mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
        
    for(i=0;i<old_exc_ports.count;i++)
        if(old_exc_ports.masks[i] & (1 << exception))
            break;
    if(i==old_exc_ports.count) ABORT("No handler for exception!");
    
    port = old_exc_ports.ports[i];
    behavior = old_exc_ports.behaviors[i];
    flavor = old_exc_ports.flavors[i];

    if(behavior != EXCEPTION_DEFAULT) {
        r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
        if(r != KERN_SUCCESS)
            ABORT("thread_get_state failed in forward_exception");
    }
    
    switch(behavior) {
        case EXCEPTION_DEFAULT:
            r = exception_raise(port,thread,task,exception,data,data_count);
            break;
        case EXCEPTION_STATE:
            r = exception_raise_state(port,thread,task,exception,data,
                data_count,&flavor,thread_state,thread_state_count,
                thread_state,&thread_state_count);
            break;
        case EXCEPTION_STATE_IDENTITY:
            r = exception_raise_state_identity(port,thread,task,exception,data,
                data_count,&flavor,thread_state,thread_state_count,
                thread_state,&thread_state_count);
            break;
        default:
            r = KERN_FAILURE; /* make gcc happy */
            ABORT("forward_exception: unknown behavior");
            break;
    }
    
    if(behavior != EXCEPTION_DEFAULT) {
        r = thread_set_state(thread,flavor,thread_state,thread_state_count);
        if(r != KERN_SUCCESS)
            ABORT("thread_set_state failed in forward_exception");
    }
    
    return r;
}
Exemplo n.º 2
0
void
osfmach3_trap_forward(
	exception_type_t		exc_type,
	exception_data_t		code,
	mach_msg_type_number_t		code_count,
	int				*flavor,
	thread_state_t			old_state,
	mach_msg_type_number_t		*icnt,
	thread_state_t			new_state,
	mach_msg_type_number_t		*ocnt)
{
	kern_return_t		kr;
	mach_msg_type_number_t	exc_count;
	exception_mask_t	exc_mask;
	mach_port_t		exc_port;
	exception_behavior_t	exc_behavior;
	thread_state_flavor_t	exc_flavor;
	mach_port_t		thread_port, task_port;

	/*
	 * Check if a debugger has changed the task exception port:
	 * if so, forward the exception to the debugger.
	 */
	exc_port = MACH_PORT_NULL;
	task_port = current->osfmach3.task->mach_task_port;
	thread_port = current->osfmach3.thread->mach_thread_port;
	exc_count = 1;
	kr = task_get_exception_ports(task_port,
				      1 << exc_type,
				      &exc_mask,
				      &exc_count,
				      &exc_port,
				      &exc_behavior,
				      &exc_flavor);
	if (kr != KERN_SUCCESS) {
		MACH3_DEBUG(1, kr,
			    ("osfmach3_trap_forward: "
			     "task_get_exception_ports(0x%x, 0x%x)",
			     task_port, 1 << exc_type));
		current->osfmach3.thread->exception_completed = FALSE;
		return;
	}
	if (!MACH_PORT_VALID(exc_port)) {
		current->osfmach3.thread->exception_completed = FALSE;
		return;
	}
	ASSERT(exc_mask == 1 << exc_type);
	if (exc_port == user_trap_port) {
		/*
		 * Nothing has changed. Process the exception normally.
		 */
		if (user_trap_port_refs++ >= 0x7000) {
			kr = mach_port_mod_refs(mach_task_self(),
						exc_port,
						MACH_PORT_RIGHT_SEND,
						-0x7000);
			if (kr != KERN_SUCCESS) {
				MACH3_DEBUG(1, kr,
					    ("osfmach3_trap_forward: "
					     "mach_port_mod_refs(0x%x)",
					     exc_port));
			}
			user_trap_port_refs -= 0x7000;
		}
		current->osfmach3.thread->exception_completed = FALSE;
		return;
	}
	/*
	 * A debugger has changed the exception port because it expects
	 * to intercept this type of exception. Forward the exception.
	 */
	switch (exc_behavior) {
	    case EXCEPTION_DEFAULT:
		current->osfmach3.thread->exception_completed = TRUE;
		server_thread_blocking(FALSE);
		kr = exception_raise(exc_port,
				     thread_port,
				     task_port,
				     exc_type,
				     code,
				     code_count);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "exception_raise(0x%x, 0x%x)",
				     exc_port, exc_type));
			break;
		}
		server_thread_blocking(FALSE);
		kr = thread_get_state(thread_port,
				      *flavor,
				      old_state,
				      icnt);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "thread_get_state(0x%x) [1]",
				     thread_port));
		}
		break;

	    case EXCEPTION_STATE:
		if (exc_flavor != *flavor) {
			printk("osfmach3_trap_forward: "
			       "can't forward exception_state - "
			       "got flavor 0x%x, want 0x%x\n",
			       *flavor, exc_flavor);
			current->osfmach3.thread->exception_completed = FALSE;
			break;
		}
		current->osfmach3.thread->exception_completed = TRUE;
		server_thread_blocking(FALSE);
		kr = exception_raise_state(exc_port,
					   exc_type,
					   code,
					   code_count,
					   flavor,
					   old_state,
					   *icnt,
					   new_state,
					   ocnt);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "exception_raise_state(0x%x, 0x%x)",
				     exc_port, exc_type));
		}
		break;

	    case EXCEPTION_STATE_IDENTITY:
		if (exc_flavor != *flavor) {
			printk("osfmach3_trap_forward: "
			       "can't forward exception_state_identity - "
			       "got flavor 0x%x, want 0x%x\n",
			       *flavor, exc_flavor);
			current->osfmach3.thread->exception_completed = FALSE;
			break;
		}
		current->osfmach3.thread->exception_completed = TRUE;
		server_thread_blocking(FALSE);
		kr = exception_raise_state_identity(exc_port,
						    thread_port,
						    task_port,
						    exc_type,
						    code,
						    code_count,
						    flavor,
						    old_state,
						    *icnt,
						    new_state,
						    ocnt);
		server_thread_unblocking(FALSE);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "exception_raise_state_identity"
				     "(0x%x, 0x%x)",
				     exc_port, exc_type));
		}
		break;

	    default:
		printk("osfmach3_trap_forward: "
		       "unknown behavior 0x%x for task exception 0x%x\n",
		       exc_behavior, exc_type);
		current->osfmach3.thread->exception_completed = FALSE;
		break;
	}

	if (exc_port != MACH_PORT_NULL) {
		kr = mach_port_deallocate(mach_task_self(), exc_port);
		if (kr != KERN_SUCCESS) {
			MACH3_DEBUG(1, kr,
				    ("osfmach3_trap_forward: "
				     "mach_port_deallocate(0x%x)",
				     exc_port));
		}
	}
}
Exemplo n.º 3
0
/*
 *	Routine:	exception_deliver
 *	Purpose:
 *		Make an upcall to the exception server provided.
 *	Conditions:
 *		Nothing locked and no resources held.
 *		Called from an exception context, so
 *		thread_exception_return and thread_kdb_return
 *		are possible.
 *	Returns:
 *		KERN_SUCCESS if the exception was handled
 */
kern_return_t 
exception_deliver(
	thread_t		thread,
	exception_type_t	exception,
	mach_exception_data_t	code,
	mach_msg_type_number_t  codeCnt,
	struct exception_action *excp,
	lck_mtx_t			*mutex)
{
	ipc_port_t		exc_port;
	exception_data_type_t	small_code[EXCEPTION_CODE_MAX];
	int			code64;
	int			behavior;
	int			flavor;
	kern_return_t		kr;

	/*
	 *  Save work if we are terminating.
	 *  Just go back to our AST handler.
	 */
	if (!thread->active)
		return KERN_SUCCESS;

	/*
	 * Snapshot the exception action data under lock for consistency.
	 * Hold a reference to the port over the exception_raise_* calls
	 * so it can't be destroyed.  This seems like overkill, but keeps
	 * the port from disappearing between now and when
	 * ipc_object_copyin_from_kernel is finally called.
	 */
	lck_mtx_lock(mutex);
	exc_port = excp->port;
	if (!IP_VALID(exc_port)) {
		lck_mtx_unlock(mutex);
		return KERN_FAILURE;
	}
	ip_lock(exc_port);
	if (!ip_active(exc_port)) {
		ip_unlock(exc_port);
		lck_mtx_unlock(mutex);
		return KERN_FAILURE;
	}
	ip_reference(exc_port);	
	exc_port->ip_srights++;
	ip_unlock(exc_port);

	flavor = excp->flavor;
	behavior = excp->behavior;
	lck_mtx_unlock(mutex);

	code64 = (behavior & MACH_EXCEPTION_CODES);
	behavior &= ~MACH_EXCEPTION_CODES;

	if (!code64) {
		small_code[0] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[0]);
		small_code[1] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[1]);
	}


	switch (behavior) {
	case EXCEPTION_STATE: {
		mach_msg_type_number_t state_cnt;
		thread_state_data_t state;

		c_thr_exc_raise_state++;
		state_cnt = _MachineStateCount[flavor];
		kr = thread_getstatus(thread, flavor, 
				      (thread_state_t)state,
				      &state_cnt);
		if (kr == KERN_SUCCESS) {
			if (code64) {
				kr = mach_exception_raise_state(exc_port, 
						exception,
						code, 
						codeCnt,
						&flavor,
						state, state_cnt,
						state, &state_cnt);
			} else {
				kr = exception_raise_state(exc_port, exception,
						small_code, 
						codeCnt,
						&flavor,
						state, state_cnt,
						state, &state_cnt);
			}
			if (kr == MACH_MSG_SUCCESS)
				kr = thread_setstatus(thread, flavor, 
						(thread_state_t)state,
						state_cnt);
		}

		return kr;
	}

	case EXCEPTION_DEFAULT:
		c_thr_exc_raise++;
		if (code64) {
			kr = mach_exception_raise(exc_port,
					retrieve_thread_self_fast(thread),
					retrieve_task_self_fast(thread->task),
					exception,
					code, 
					codeCnt);
		} else {
			kr = exception_raise(exc_port,
					retrieve_thread_self_fast(thread),
					retrieve_task_self_fast(thread->task),
					exception,
					small_code, 
					codeCnt);
		}

		return kr;

	case EXCEPTION_STATE_IDENTITY: {
		mach_msg_type_number_t state_cnt;
		thread_state_data_t state;

		c_thr_exc_raise_state_id++;
		state_cnt = _MachineStateCount[flavor];
		kr = thread_getstatus(thread, flavor,
				      (thread_state_t)state,
				      &state_cnt);
		if (kr == KERN_SUCCESS) {
			if (code64) {
				kr = mach_exception_raise_state_identity(
						exc_port,
						retrieve_thread_self_fast(thread),
						retrieve_task_self_fast(thread->task),
						exception,
						code, 
						codeCnt,
						&flavor,
						state, state_cnt,
						state, &state_cnt);
			} else {
				kr = exception_raise_state_identity(exc_port,
						retrieve_thread_self_fast(thread),
						retrieve_task_self_fast(thread->task),
						exception,
						small_code, 
						codeCnt,
						&flavor,
						state, state_cnt,
						state, &state_cnt);
			}
			if (kr == MACH_MSG_SUCCESS)
				kr = thread_setstatus(thread, flavor,
						(thread_state_t)state,
						state_cnt);
		}

		return kr;
	}

	default:
	       panic ("bad exception behavior!");
	       return KERN_FAILURE; 
	}/* switch */
}