void *arena_alloc(arena_t arena, long size, const char *file, int line){ assert(arena); assert(size>0); size = ((size + sizeof(union align)-1)/(sizeof(union align)))*(sizeof(union align)); while(size > arena->limit - arena->avail){ arena_t ptr; char *limit; if((ptr = freechunks)!=NULL){ freechunks=freechunks->prev; nfree--; limit = ptr->limit; }else{ long m = sizeof(union header) + size + 10*1024; ptr = malloc(m); if(ptr == NULL){ if(file==NULL) RAISE(Arena_Failed); else exception_raise(&Arena_Failed, file, line); } limit = (char *)ptr+m; } *ptr=*arena; arena->avail = (char *)((union header *)ptr +1); arena->limit = limit; arena->prev = ptr; } arena->avail += size; return arena->avail - size; }
/* 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; }
void exception( integer_t _exception, integer_t code, integer_t subcode) { ipc_thread_t self = current_thread(); ipc_port_t exc_port; if (_exception == KERN_SUCCESS) panic("exception"); /* * Optimized version of retrieve_thread_exception. */ ith_lock(self); assert(self->ith_self != IP_NULL); exc_port = self->ith_exception; if (!IP_VALID(exc_port)) { ith_unlock(self); exception_try_task(_exception, code, subcode); /*NOTREACHED*/ } ip_lock(exc_port); ith_unlock(self); if (!ip_active(exc_port)) { ip_unlock(exc_port); exception_try_task(_exception, code, subcode); /*NOTREACHED*/ } /* * Make a naked send right for the exception port. */ ip_reference(exc_port); exc_port->ip_srights++; ip_unlock(exc_port); /* * If this exception port doesn't work, * we will want to try the task's exception port. * Indicate this by saving the exception state. */ self->ith_exc = _exception; self->ith_exc_code = code; self->ith_exc_subcode = subcode; exception_raise(exc_port, retrieve_thread_self_fast(self), retrieve_task_self_fast(self->task), _exception, code, subcode); /*NOTREACHED*/ }
/* * Send a signal to the process. */ static int send_sig(struct proc *p, int sig) { if (p->p_pid == 0 || p->p_pid == 1) return EPERM; DPRINTF(("proc: send_sig task=%x\n", p->p_task)); return exception_raise(p->p_task, sig); }
void exception_try_task( integer_t _exception, integer_t code, integer_t subcode) { ipc_thread_t self = current_thread(); task_t task = self->task; ipc_port_t exc_port; /* * Optimized version of retrieve_task_exception. */ itk_lock(task); assert(task->itk_self != IP_NULL); exc_port = task->itk_exception; if (!IP_VALID(exc_port)) { itk_unlock(task); exception_no_server(); /*NOTREACHED*/ } ip_lock(exc_port); itk_unlock(task); if (!ip_active(exc_port)) { ip_unlock(exc_port); exception_no_server(); /*NOTREACHED*/ } /* * Make a naked send right for the exception port. */ ip_reference(exc_port); exc_port->ip_srights++; ip_unlock(exc_port); /* * This is the thread's last chance. * Clear the saved exception state. */ self->ith_exc = KERN_SUCCESS; exception_raise(exc_port, retrieve_thread_self_fast(self), retrieve_task_self_fast(task), _exception, code, subcode); /*NOTREACHED*/ }
/* * Send a signal to the process. */ static int sendsig(struct proc *p, int sig) { /* * We never allow to send signal to the * process server in any case. */ if (p->p_pid == 0) return EPERM; /* * Filter signals for init process. * This is for fail safe... */ if (p->p_pid == 1 && sig != SIGCHLD) return EPERM; DPRINTF(("proc: sendsig task=%x\n", p->p_task)); return exception_raise(p->p_task, sig); }
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)); } } }
/* * 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 */ }