static bool xnu_save_exception_ports (int pid) { kern_return_t kr; task_t task = pid_to_task (pid); ex.count = (sizeof (ex.ports) / sizeof (ex.ports[0])); kr = task_get_exception_ports (task, EXC_MASK_ALL, ex.masks, &ex.count, ex.ports, ex.behaviors, ex.flavors); return (kr == KERN_SUCCESS); }
void next_save_exception_ports (task_t task, struct next_exception_info *info) { kern_return_t kret; info->count = (sizeof (info->ports) / sizeof (info->ports[0])); kret = task_get_exception_ports (task, EXC_MASK_ALL, info->masks, &info->count, info->ports, info->behaviors, info->flavors); MACH_CHECK_ERROR (kret); }
//FIXME this will not compile static bool xnu_save_exception_ports (RDebug *dbg) { kern_return_t kr; task_t task = pid_to_task (dbg->pid); dbg->ex->count = (sizeof (dbg->ex->ports) / sizeof (dbg->ex->ports[0])); if (task == -1) { perror ("xnu_save_exception_ports: pid_to_task:"); return false; } kr = task_get_exception_ports (task, EXC_MASK_ALL, dbg->ex->masks, &dbg->ex->count, dbg->ex->ports, dbg->ex->behaviors, dbg->ex->flavors); return (kr == KERN_SUCCESS); }
static void info_mach_exceptions_command (const char *args, int from_tty) { int i; task_t task; kern_return_t kret; darwin_exception_info info; info.count = sizeof (info.ports) / sizeof (info.ports[0]); if (args != NULL) { if (strcmp (args, "saved") == 0) { if (ptid_equal (inferior_ptid, null_ptid)) printf_unfiltered (_("No inferior running\n")); darwin_inferior *priv = get_darwin_inferior (current_inferior ()); disp_exception (&priv->exception_info); return; } else if (strcmp (args, "host") == 0) { /* FIXME: This need a privilegied host port! */ kret = host_get_exception_ports (darwin_host_self, EXC_MASK_ALL, info.masks, &info.count, info.ports, info.behaviors, info.flavors); MACH_CHECK_ERROR (kret); disp_exception (&info); } else error (_("Parameter is saved, host or none")); } else { struct inferior *inf; if (ptid_equal (inferior_ptid, null_ptid)) printf_unfiltered (_("No inferior running\n")); inf = current_inferior (); darwin_inferior *priv = get_darwin_inferior (inf); kret = task_get_exception_ports (priv->task, EXC_MASK_ALL, info.masks, &info.count, info.ports, info.behaviors, info.flavors); MACH_CHECK_ERROR (kret); disp_exception (&info); } }
void mach_exn_init() { kern_return_t r; mach_port_t me; pthread_t thread; pthread_attr_t attr; exception_mask_t mask; me = mach_task_self(); r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&exception_port); if(r != MACH_MSG_SUCCESS) DIE("mach_port_allocate"); r = mach_port_insert_right(me,exception_port,exception_port, MACH_MSG_TYPE_MAKE_SEND); if(r != MACH_MSG_SUCCESS) DIE("mach_port_insert_right"); /* for others see mach/exception_types.h */ mask = EXC_MASK_BAD_ACCESS; /* get the old exception ports */ r = task_get_exception_ports( me, mask, old_exc_ports.masks, &old_exc_ports.count, old_exc_ports.ports, old_exc_ports.behaviors, old_exc_ports.flavors ); if(r != MACH_MSG_SUCCESS) DIE("task_get_exception_ports"); /* set the new exception ports */ r = task_set_exception_ports( me, mask, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE ); if(r != MACH_MSG_SUCCESS) DIE("task_set_exception_ports"); if(pthread_attr_init(&attr) != 0) DIE("pthread_attr_init"); if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0) DIE("pthread_attr_setdetachedstate"); if(pthread_create(&thread,&attr,exc_thread,NULL) != 0) DIE("pthread_create"); pthread_attr_destroy(&attr); }
int main() { kern_return_t kr = 0; mach_port_t exc_port; mach_port_t task = mach_task_self(); pthread_t exception_thread; int err; mach_msg_type_number_t maskCount = 1; exception_mask_t mask; exception_handler_t handler; exception_behavior_t behavior; thread_state_flavor_t flavor; if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) { fprintf(stderr, "mach_port_allocate: %#x\n", kr); exit(1); } if ((kr = mach_port_insert_right(task, exc_port, exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) { fprintf(stderr, "mach_port_allocate: %#x\n", kr); exit(1); } if ((kr = task_get_exception_ports(task, EXC_MASK_ALL, &mask, &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) { fprintf(stderr,"task_get_exception_ports: %#x\n", kr); exit(1); } if ((err = pthread_create(&exception_thread, NULL, server_thread, &exc_port)) != 0) { fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err)); exit(1); } pthread_detach(exception_thread); if ((kr = task_set_exception_ports(task, EXC_MASK_ALL, exc_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) { fprintf(stderr, "task_set_exception_ports: %#x\n", kr); exit(1); } puts("Starting exception stuff"); int a = 1; int b = 0; float c = a / b; int cat = *(int *)(0x13371337); printf("Have c %f and cat %d\n", c, cat); puts("End."); }
bool TargetException::setExceptionCallback(ExceptionCallback callback) { m_callback = std::move(callback); auto kr = mach_port_allocate(mach_task_self(),MACH_PORT_RIGHT_RECEIVE,&m_exceptionPort); if (kr != KERN_SUCCESS) { log(QString("mach_port_allocate failde: %1").arg(mach_error_string(kr)), LogType::Error); return false; } kr = mach_port_insert_right(mach_task_self(), m_exceptionPort, m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND); if (kr != KERN_SUCCESS) { log(QString("mach_port_insert_right failde: %1").arg(mach_error_string(kr)), LogType::Error); return false; } kr = task_get_exception_ports( g_task, EXC_MASK_ALL, m_oldExcPorts.masks, &m_oldExcPorts.count, m_oldExcPorts.ports, m_oldExcPorts.behaviors, m_oldExcPorts.flavors ); if (kr != KERN_SUCCESS) { log(QString("task_get_exception_ports failde: %1").arg(mach_error_string(kr)), LogType::Error); return false; } kr = task_set_exception_ports( g_task, EXC_MASK_ALL, m_exceptionPort, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE ); if (kr != KERN_SUCCESS) { log(QString("task_set_exception_ports failde: %1").arg(mach_error_string(kr)), LogType::Error); return false; } return true; }
mach_port_t machExceptionPort() { exception_mask_t exceptionMasks[EXC_TYPES_COUNT]; exception_port_t exceptionHandlers[EXC_TYPES_COUNT]; exception_behavior_t exceptionBehaviors[EXC_TYPES_COUNT]; thread_state_flavor_t exceptionFlavors[EXC_TYPES_COUNT]; mach_msg_type_number_t numExceptionMasks; kern_return_t kr = task_get_exception_ports(mach_task_self(), EXC_MASK_CRASH, exceptionMasks, &numExceptionMasks, exceptionHandlers, exceptionBehaviors, exceptionFlavors); if (kr != KERN_SUCCESS) { ASSERT_NOT_REACHED(); return MACH_PORT_NULL; } // We're just interested in the first exception handler. return exceptionHandlers[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)); } } }
void osfmach3_trap_init( exception_behavior_t behavior, thread_state_flavor_t flavor) { kern_return_t kr; mach_port_t trap_port_name, trap_port; exception_mask_t mask; thread_exception_behavior = behavior; thread_exception_flavor = flavor; init_task.osfmach3.task->mach_task_port = mach_task_self(); trap_port_name = ((mach_port_t) &init_task) + 1; kr = serv_port_allocate_name(&trap_port, (void *) trap_port_name); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("osfmach3_trap_init: " "serv_port_allocate_name(%x)", trap_port_name)); panic("osfmach3_trap_init: " "can't allocate exception port"); } init_task.osfmach3.thread->mach_trap_port = trap_port; kr = mach_port_insert_right(mach_task_self(), trap_port, trap_port, MACH_MSG_TYPE_MAKE_SEND); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("osfmach3_trap_init: " "mach_port_insert_right")); panic("osfmach3_trap_init: can't insert send right"); } mask = EXC_MASK_ALL & ~EXC_MASK_RPC_ALERT; if (parent_server) { exception_mask_t syscall_exc_mask; exception_mask_t old_exc_mask; mach_msg_type_number_t old_exc_count; mach_port_t old_exc_port; exception_behavior_t old_exc_behavior; thread_state_flavor_t old_exc_flavor; /* * Don't catch syscall exceptions that are directed to * the parent server. But save the port, behavior and flavor * to be able to restore them later. */ syscall_exc_mask = parent_server_syscall_exc_mask(); old_exc_count = 1; kr = task_get_exception_ports(mach_task_self(), syscall_exc_mask, &old_exc_mask, &old_exc_count, &old_exc_port, &old_exc_behavior, &old_exc_flavor); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("osfmach3_trap_init(FIRST_TASK): " "task_get_exception_ports(mask=0x%x)", syscall_exc_mask)); panic("can't get syscall exc port (parent server)"); } if (old_exc_count == 1) { parent_server_syscall_port = old_exc_port; parent_server_syscall_behavior = old_exc_behavior; parent_server_syscall_flavor = old_exc_flavor; } else { printk("osfmach3_trap_init: " "couldn't get our syscall exc port"); } mask &= ~syscall_exc_mask; /* let breakpoints go to the debugger (if any) */ mask &= ~EXC_MASK_BREAKPOINT; /* let Mach syscalls go to Mach */ mask &= ~EXC_MASK_MACH_SYSCALL; } kr = task_set_exception_ports(mach_task_self(), mask, trap_port, behavior, flavor); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("osfmach3_trap_init: " "task_set_exception_ports")); panic("osfmach3_trap_init: " "can't set server's task exception ports"); } #if 0 /* obsolete */ if (parent_server) { /* * Hide the EXC_BAD_INSTRUCTION exceptions to avoid * interferences from the parent_server when we do * syscalls to ourselves (see start_kernel() and init()). */ kr = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_INSTRUCTION, MACH_PORT_NULL, behavior, flavor); if (kr != KERN_SUCCESS) { MACH3_DEBUG(1, kr, ("osfmach3_trap_init: " "thread_set_exception_ports")); panic("can't unset thread exception port"); } } #endif ASSERT(server_exception_port == MACH_PORT_NULL); server_exception_port = trap_port; server_thread_start(server_exception_catcher, (void *) 0); /* * Create a global exception port for user tasks to detect * new user threads. */ kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &user_trap_port); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("osfmach3_trap_init: " "mach_port_allocate()")); panic("osfmach3_trap_init: " "can't allocate user trap port"); } kr = mach_port_insert_right(mach_task_self(), user_trap_port, user_trap_port, MACH_MSG_TYPE_MAKE_SEND); if (kr != KERN_SUCCESS) { MACH3_DEBUG(0, kr, ("osfmach3_trap_init: " "mach_port_insert_right")); panic("osfmach3_trap_init: can't insert send right " "for user trap port"); } server_thread_start(task_exception_catcher, (void *) 0); }
int main(int argc, char *argv[]) { posix_spawnattr_t attrs; uint64_t percent, interval; int i, err, ret = 0; kern_return_t kr; mach_port_t task = mach_task_self(); mach_port_t child_task; char **child_args; pthread_t exception_thread; pthread_t timer_thread; pthread_t wait_thread; mach_msg_type_number_t maskCount = 1; exception_mask_t mask; exception_handler_t handler; exception_behavior_t behavior; thread_state_flavor_t flavor; pid_t child_pid; int test_case_id = -1; if (argc > 1) test_case_id = atoi(argv[1]); /* Initialize mutex and condition variable */ if ((err = pthread_mutex_init(&lock, NULL)) != 0) { fprintf(stderr,"pthread_mutex_init: %s\n", strerror(err)); exit(1); } if ((err = pthread_cond_init(&cv, NULL)) != 0) { fprintf(stderr, "pthread_cond_init: %s\n", strerror(err)); exit(1); } /* Allocate and initialize new exception port */ if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) { fprintf(stderr, "mach_port_allocate: %s\n", mach_error_string(kr)); exit(1); } if ((kr = mach_port_insert_right(task, exc_port, exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) { fprintf(stderr, "mach_port_allocate: %s\n", mach_error_string(kr)); exit(1); } /* Get Current exception ports */ if ((kr = task_get_exception_ports(task, EXC_MASK_RESOURCE, &mask, &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) { fprintf(stderr,"task_get_exception_ports: %s\n", mach_error_string(kr)); exit(1); } /* Create exception serving thread */ if ((err = pthread_create(&exception_thread, NULL, server_thread, 0)) != 0) { fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err)); exit(1); } fprintf(stderr, "---------------System Configuration------------------------------------------\n"); fprintf(stderr, "System Kernel Version: "); system("uname -a"); fprintf(stderr, "System SDK Version: "); system("sw_vers"); for (i = 0; i < NUMTESTS; i++) { indiv_results[i] = -1; } /* Run Tests */ for(i=0; i<NUMTESTS; i++) { int j; if (test_case_id != -1 && test_case_id != i) continue; fprintf(stderr, "---------------Test [%d] Configuration------------------------------------------\n", i); fprintf(stderr, "Test Case ID: %d\n", i); fprintf(stderr, "Description: %s\n", test_description[i]); switch(i) { case 0: child_args = test_argv_0; break; case 1: child_args = test_argv_1; break; case 2: child_args = test_argv_2; break; case 3: child_args = test_argv_3; break; case 4: child_args = test_argv_4; break; case 5: child_args = test_argv_5; break; case 6: child_args = test_argv_6; break; default: fprintf(stderr, "no test argv found\n"); exit(1); } /* Test cases which do not need to run for certain platforms */ if (child_args == NULL) { fprintf(stderr, "Test case unimplemented for current platform.\n"); fprintf(stderr, "[PASSED]\n"); fprintf(stderr, "-------------------------------------------------------------------------------\n"); continue; } fprintf(stderr, "Helper args: "); for (j = 0; child_args[j] != NULL; j++) { fprintf(stderr, "%s ", child_args[j]); } fprintf(stderr, "\n"); /* Print Test Case Configuration */ fprintf(stderr, "Test Case expects EXC_RESOURCE?: %s\n", test_exception_code[i] ? "Yes":"No"); if (test_exception_code[i]) fprintf(stderr, "Expected EXC_RESOURCE code: 0x%llx\n", test_exception_code[i]); if (timeout_secs[i]) fprintf(stderr, "Timeout for Test Program: %d secs\n", timeout_secs[i]); if (exc_expected_at[i]) fprintf(stderr, "Exception Expected After: %d secs\n", exc_expected_at[i]); /* Initialize posix_spawn attributes */ posix_spawnattr_init(&attrs); if ((err = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC)) != 0) { fprintf(stderr, "posix_spawnattr_setflags: %s\n", strerror(err)); exit(1); } /* Use high values so the system defaults take effect (spawn attrs are capped) */ percent = 100; interval = 10000; /* Enable CPU Monitor */ if ((err = posix_spawnattr_setcpumonitor(&attrs, percent, interval)) != 0) { fprintf(stderr, "posix_spawnattr_setcpumonitor: %s\n", strerror(err)); exit(1); } exception_code = 0; time_for_exc = -1; /* Set Exception Ports for Current Task */ if ((kr = task_set_exception_ports(task, EXC_MASK_RESOURCE, exc_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) { fprintf(stderr, "task_set_exception_ports: %#x\n", kr); exit(1); } /* * Note the time at start of test. */ start_time = time(NULL); fprintf(stderr, "---------------Test [%d] Runtime------------------------------------------------\n", i); /* Fork and exec child */ if ((child_pid = fork()) == 0) { if ((err = posix_spawn(NULL, child_args[0], NULL, &attrs, &child_args[0], environ)) != 0) { fprintf(stderr, "posix_spawn: %s\n", strerror(err)); exit(1); } } /* Restore exception ports for parent */ if ((kr = task_set_exception_ports(task, EXC_MASK_RESOURCE, handler, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) { fprintf(stderr, "task_set_exception_ports: %#x\n", kr); exit(1); } /* Create Timer Thread if timeout specified */ if (timeout_secs[i]) { if ((err = pthread_create(&timer_thread, NULL, timeout_thread, (void *)timeout_secs[i])) != 0) { fprintf(stderr, "pthread_create timeout_thread: %s\n", strerror(err)); test_status = 1; goto cleanup; } } /* Create waiting for child thread */ if ((err = pthread_create(&wait_thread, NULL, wait4_child_thread, NULL)) != 0) { fprintf(stderr, "pthread_create wait4_child_thread: %s\n", strerror(err)); test_status = 1; goto cleanup; } pthread_mutex_lock(&lock); pthread_cond_wait(&cv, &lock); pthread_mutex_unlock(&lock); kill(child_pid, SIGKILL); pthread_join(timer_thread, NULL); pthread_join(wait_thread, NULL); int test_case_status = 0; indiv_results[i] = 0; fprintf(stderr, "---------------Test [%d] Results------------------------------------------------\n", i); if (exception_code) fprintf(stderr, "EXC_RESOURCE Received with Code: 0x%llx\n", exception_code); else fprintf(stderr, "No EXC_RESOURCE Received!\n"); if (time_for_exc > 0) fprintf(stderr, "EXC_RESOURCE Received after %d secs\n", time_for_exc); if (!!exception_code != !!test_exception_code[i]) { test_status = 1; test_case_status = 1; indiv_results[i] = 1; } if (exception_code) { /* Validate test success by checking code and expected time */ if ((exception_code & test_exception_code[i]) != test_exception_code[i]) { fprintf(stderr, "Test Failure Reason: EXC_RESOURCE code did not match expected exception code!\n"); fprintf(stderr, "Expected: 0x%llx Found: 0x%llx\n", test_exception_code[i], exception_code); test_status = 1; test_case_status = 1; indiv_results[i] = 1; } if(exc_expected_at[i] && (time_for_exc < (exc_expected_at[i] - 10) || time_for_exc > (exc_expected_at[i] + 10))) { fprintf(stderr, "Test Failure Reason: Test case did not receive EXC_RESOURCE within expected time!\n"); test_status = 1; test_case_status = 1; indiv_results[i] = 1; } } if(test_case_status) fprintf(stderr, "[FAILED]\n"); else fprintf(stderr, "[PASSED]\n"); fprintf(stderr, "-------------------------------------------------------------------------------\n"); } if (test_case_id == -1) { fprintf(stderr, "--------------- Results Summary -----------------------------------------------\n"); for (i = 0; i < NUMTESTS; i++) { fprintf(stderr, "%2d: %s\n", i, (indiv_results[i] < 0) ? "N/A" : (indiv_results[i] == 0) ? "PASSED" : "FAILED"); } } cleanup: kill(child_pid, SIGKILL); exit(test_status); }
bool kscrashsentry_installMachHandler(KSCrash_SentryContext* const context) { KSLOG_DEBUG("Installing mach exception handler."); bool attributes_created = false; pthread_attr_t attr; kern_return_t kr; int error; const task_t thisTask = mach_task_self(); exception_mask_t mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT; if(g_installed) { KSLOG_DEBUG("Exception handler already installed."); return true; } g_installed = 1; if(ksmach_isBeingTraced()) { // Different debuggers hook into different exception types. // For example, GDB uses EXC_BAD_ACCESS for single stepping, // and LLDB uses EXC_SOFTWARE to stop a debug session. // Because of this, it's safer to not hook into the mach exception // system at all while being debugged. KSLOG_WARN("Process is being debugged. Not installing handler."); goto failed; } g_context = context; KSLOG_DEBUG("Backing up original exception ports."); kr = task_get_exception_ports(thisTask, mask, g_previousExceptionPorts.masks, &g_previousExceptionPorts.count, g_previousExceptionPorts.ports, g_previousExceptionPorts.behaviors, g_previousExceptionPorts.flavors); if(kr != KERN_SUCCESS) { KSLOG_ERROR("task_get_exception_ports: %s", mach_error_string(kr)); goto failed; } if(g_exceptionPort == MACH_PORT_NULL) { KSLOG_DEBUG("Allocating new port with receive rights."); kr = mach_port_allocate(thisTask, MACH_PORT_RIGHT_RECEIVE, &g_exceptionPort); if(kr != KERN_SUCCESS) { KSLOG_ERROR("mach_port_allocate: %s", mach_error_string(kr)); goto failed; } KSLOG_DEBUG("Adding send rights to port."); kr = mach_port_insert_right(thisTask, g_exceptionPort, g_exceptionPort, MACH_MSG_TYPE_MAKE_SEND); if(kr != KERN_SUCCESS) { KSLOG_ERROR("mach_port_insert_right: %s", mach_error_string(kr)); goto failed; } } KSLOG_DEBUG("Installing port as exception handler."); kr = task_set_exception_ports(thisTask, mask, g_exceptionPort, EXCEPTION_DEFAULT, THREAD_STATE_NONE); if(kr != KERN_SUCCESS) { KSLOG_ERROR("task_set_exception_ports: %s", mach_error_string(kr)); goto failed; } KSLOG_DEBUG("Creating secondary exception thread (suspended)."); pthread_attr_init(&attr); attributes_created = true; pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); error = pthread_create(&g_secondaryThread, &attr, &ksmachexc_i_handleExceptions, kThreadSecondary); if(error != 0) { KSLOG_ERROR("pthread_create_suspended_np: %s", strerror(error)); goto failed; } context->reservedThreads[KSCrashReservedThreadTypeMachSecondary] = pthread_mach_thread_np(g_secondaryThread); KSLOG_DEBUG("Creating primary exception thread."); error = pthread_create(&g_primaryThread, &attr, &ksmachexc_i_handleExceptions, kThreadPrimary); if(error != 0) { KSLOG_ERROR("pthread_create: %s", strerror(error)); goto failed; } pthread_attr_destroy(&attr); context->reservedThreads[KSCrashReservedThreadTypeMachPrimary] = pthread_mach_thread_np(g_primaryThread); KSLOG_DEBUG("Mach exception handler installed."); return true; failed: KSLOG_DEBUG("Failed to install mach exception handler."); if(attributes_created) { pthread_attr_destroy(&attr); } kscrashsentry_uninstallMachHandler(); return false; }
int main(int argc, char *argv[]) { posix_spawnattr_t attrs; kern_return_t kr; mach_port_t task = mach_task_self(); mach_msg_type_number_t maskCount = 1; exception_mask_t mask; exception_handler_t handler; exception_behavior_t behavior; thread_state_flavor_t flavor; pthread_t exception_thread; uint64_t exc_id; unsigned int exc_fd; char *test_prog_name = "./guarded_test"; char *child_args[MAX_ARGV]; char test_id[MAX_TEST_ID_LEN]; int i, err; int child_status; int test_status = 0; /* Allocate and initialize new exception port */ if ((kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &exc_port)) != KERN_SUCCESS) { fprintf(stderr, "mach_port_allocate: %#x\n", kr); exit(1); } if ((kr = mach_port_insert_right(task, exc_port, exc_port, MACH_MSG_TYPE_MAKE_SEND)) != KERN_SUCCESS) { fprintf(stderr, "mach_port_allocate: %#x\n", kr); exit(1); } /* Get Current exception ports */ if ((kr = task_get_exception_ports(task, EXC_MASK_GUARD, &mask, &maskCount, &handler, &behavior, &flavor)) != KERN_SUCCESS) { fprintf(stderr,"task_get_exception_ports: %#x\n", kr); exit(1); } /* Create exception serving thread */ if ((err = pthread_create(&exception_thread, NULL, server_thread, 0)) != 0) { fprintf(stderr, "pthread_create server_thread: %s\n", strerror(err)); exit(1); } pthread_detach(exception_thread); /* Initialize posix_spawn attributes */ posix_spawnattr_init(&attrs); if ((err = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC)) != 0) { fprintf(stderr, "posix_spawnattr_setflags: %s\n", strerror(err)); exit(1); } /* Run Tests */ for(i=0; i<NUMTESTS; i++) { exception_code = 0; /* Set Exception Ports for Current Task */ if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, exc_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) { fprintf(stderr, "task_set_exception_ports: %#x\n", kr); exit(1); } child_args[0] = test_prog_name; sprintf(&test_id[0], "%d", i); child_args[1] = &test_id[0]; child_args[2] = NULL; /* Fork and exec child */ if (fork() == 0) { if ((err = posix_spawn(NULL, child_args[0], NULL, &attrs, &child_args[0], environ)) != 0) { fprintf(stderr, "posix_spawn: %s\n", strerror(err)); exit(1); } } /* Restore exception ports for parent */ if ((kr = task_set_exception_ports(task, EXC_MASK_GUARD, handler, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, flavor)) != KERN_SUCCESS) { fprintf(stderr, "task_set_exception_ports: %#x\n", kr); exit(1); } /* Wait for child and check for exception */ if (-1 == wait4(-1, &child_status, 0, NULL)) { exit(1); } exc_fd = (unsigned int) (exception_code & (uint64_t)EXC_GUARD_FD_MASK); exc_id = exception_code & ~((uint64_t)EXC_GUARD_FD_MASK); printf("EXC_GUARD Received: "); (exception_code != 0)?printf("Yes (Code 0x%llx)\n", exception_code):printf("No\n"); printf("Test Result: "); if((WIFEXITED(child_status) && WEXITSTATUS(child_status)) || (exc_id != test_exception_code[i]) || (test_fd[i] && exc_fd != (unsigned int)TEST_FD)) { test_status = 1; printf("FAILED\n"); } else { printf("PASSED\n"); } printf("-------------------\n"); } exit(test_status); }