/* given a task (preferably stopped), sample all the threads in it */ static void pet_sample_task( task_t task ) { mach_msg_type_number_t threadc; thread_array_t threadv; kern_return_t kr; kr = chudxnu_task_threads(task, &threadv, &threadc); if( kr != KERN_SUCCESS ) { BUF_INFO2(PERF_PET_ERROR, ERR_THREAD, kr); return; } pet_sample_thread_list( threadc, threadv ); chudxnu_free_thread_list(&threadv, &threadc); }
static void pet_sample_all_tasks(void) { task_array_t taskv = NULL; mach_msg_type_number_t taskc = 0; kern_return_t kr; kr = chudxnu_all_tasks(&taskv, &taskc); if( kr != KERN_SUCCESS ) { BUF_INFO2(PERF_PET_ERROR, ERR_TASK, kr); return; } pet_sample_task_list( taskc, taskv ); chudxnu_free_task_list(&taskv, &taskc); }
static void pet_sample_pid_filter(void) { task_t *taskv = NULL; int *pidv, pidc, i; vm_size_t asize; kperf_filter_pid_list( &pidc, &pidv ); if( pidc == 0 ) { BUF_INFO2(PERF_PET_ERROR, ERR_PID, 0); return; } asize = pidc * sizeof(task_t); taskv = kalloc( asize ); if( taskv == NULL ) goto out; /* convert the pid list into a task list */ for( i = 0; i < pidc; i++ ) { int pid = pidv[i]; if( pid == -1 ) taskv[i] = NULL; else taskv[i] = chudxnu_task_for_pid(pid); } /* now sample the task list */ pet_sample_task_list( pidc, taskv ); kfree(taskv, asize); out: kperf_filter_free_pid_list( &pidc, &pidv ); }
static void callstack_sample( struct callstack *cs, struct kperf_context *context, uint32_t is_user ) { kern_return_t kr; mach_msg_type_number_t nframes; /* WTF with the type? */ uint32_t code; if( is_user ) code = PERF_CS_USAMPLE; else code = PERF_CS_KSAMPLE; BUF_INFO1( code, (uintptr_t)thread_tid(context->cur_thread) ); /* fill out known flags */ cs->flags = 0; if( !is_user ) { cs->flags |= CALLSTACK_KERNEL; #ifdef __LP64__ cs->flags |= CALLSTACK_64BIT; #endif } else { /* FIXME: detect 32 vs 64-bit? */ } /* collect the callstack */ nframes = MAX_CALLSTACK_FRAMES; kr = chudxnu_thread_get_callstack64_kperf( context->cur_thread, cs->frames, &nframes, is_user ); /* check for overflow */ if( kr == KERN_SUCCESS ) { cs->flags |= CALLSTACK_VALID; cs->nframes = nframes; } else if( kr == KERN_RESOURCE_SHORTAGE ) { /* FIXME: more here */ cs->flags |= CALLSTACK_TRUNCATED; cs->flags |= CALLSTACK_VALID; cs->nframes = nframes; } else { BUF_INFO2(PERF_CS_ERROR, ERR_GETSTACK, kr); cs->nframes = 0; } if( cs->nframes > MAX_CALLSTACK_FRAMES ) { /* necessary? */ BUF_INFO1(PERF_CS_ERROR, ERR_FRAMES); cs->nframes = 0; } }