1*061da546Spatrick #include <ctype.h>
2*061da546Spatrick #include <dispatch/dispatch.h>
3*061da546Spatrick #include <errno.h>
4*061da546Spatrick #include <libproc.h>
5*061da546Spatrick #include <mach/mach.h>
6*061da546Spatrick #include <mach/task_info.h>
7*061da546Spatrick #include <stdio.h>
8*061da546Spatrick #include <stdlib.h>
9*061da546Spatrick #include <string.h>
10*061da546Spatrick #include <sys/sysctl.h>
11*061da546Spatrick #include <time.h>
12*061da546Spatrick
13*061da546Spatrick // from System.framework/Versions/B/PrivateHeaders/sys/codesign.h
14*061da546Spatrick #define CS_OPS_STATUS 0 /* return status */
15*061da546Spatrick #define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */
16*061da546Spatrick int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize);
17*061da546Spatrick
18*061da546Spatrick /* Step through the process table, find a matching process name, return
19*061da546Spatrick the pid of that matched process.
20*061da546Spatrick If there are multiple processes with that name, issue a warning on stdout
21*061da546Spatrick and return the highest numbered process.
22*061da546Spatrick The proc_pidpath() call is used which gets the full process name including
23*061da546Spatrick directories to the executable and the full (longer than 16 character)
24*061da546Spatrick executable name. */
25*061da546Spatrick
get_pid_for_process_name(const char * procname)26*061da546Spatrick pid_t get_pid_for_process_name(const char *procname) {
27*061da546Spatrick int process_count = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0) / sizeof(pid_t);
28*061da546Spatrick if (process_count < 1) {
29*061da546Spatrick printf("Only found %d processes running!\n", process_count);
30*061da546Spatrick exit(1);
31*061da546Spatrick }
32*061da546Spatrick
33*061da546Spatrick // Allocate a few extra slots in case new processes are spawned
34*061da546Spatrick int all_pids_size = sizeof(pid_t) * (process_count + 3);
35*061da546Spatrick pid_t *all_pids = (pid_t *)malloc(all_pids_size);
36*061da546Spatrick
37*061da546Spatrick // re-set process_count in case the number of processes changed (got smaller;
38*061da546Spatrick // we won't do bigger)
39*061da546Spatrick process_count =
40*061da546Spatrick proc_listpids(PROC_ALL_PIDS, 0, all_pids, all_pids_size) / sizeof(pid_t);
41*061da546Spatrick
42*061da546Spatrick int i;
43*061da546Spatrick pid_t highest_pid = 0;
44*061da546Spatrick int match_count = 0;
45*061da546Spatrick for (i = 1; i < process_count; i++) {
46*061da546Spatrick char pidpath[PATH_MAX];
47*061da546Spatrick int pidpath_len = proc_pidpath(all_pids[i], pidpath, sizeof(pidpath));
48*061da546Spatrick if (pidpath_len == 0)
49*061da546Spatrick continue;
50*061da546Spatrick char *j = strrchr(pidpath, '/');
51*061da546Spatrick if ((j == NULL && strcmp(procname, pidpath) == 0) ||
52*061da546Spatrick (j != NULL && strcmp(j + 1, procname) == 0)) {
53*061da546Spatrick match_count++;
54*061da546Spatrick if (all_pids[i] > highest_pid)
55*061da546Spatrick highest_pid = all_pids[i];
56*061da546Spatrick }
57*061da546Spatrick }
58*061da546Spatrick free(all_pids);
59*061da546Spatrick
60*061da546Spatrick if (match_count == 0) {
61*061da546Spatrick printf("Did not find process '%s'.\n", procname);
62*061da546Spatrick exit(1);
63*061da546Spatrick }
64*061da546Spatrick if (match_count > 1) {
65*061da546Spatrick printf("Warning: More than one process '%s'!\n", procname);
66*061da546Spatrick printf(" defaulting to the highest-pid one, %d\n", highest_pid);
67*061da546Spatrick }
68*061da546Spatrick return highest_pid;
69*061da546Spatrick }
70*061da546Spatrick
71*061da546Spatrick /* Given a pid, get the full executable name (including directory
72*061da546Spatrick paths and the longer-than-16-chars executable name) and return
73*061da546Spatrick the basename of that (i.e. do not include the directory components).
74*061da546Spatrick This function mallocs the memory for the string it returns;
75*061da546Spatrick the caller must free this memory. */
76*061da546Spatrick
get_process_name_for_pid(pid_t pid)77*061da546Spatrick const char *get_process_name_for_pid(pid_t pid) {
78*061da546Spatrick char tmp_name[PATH_MAX];
79*061da546Spatrick if (proc_pidpath(pid, tmp_name, sizeof(tmp_name)) == 0) {
80*061da546Spatrick printf("Could not find process with pid of %d\n", (int)pid);
81*061da546Spatrick exit(1);
82*061da546Spatrick }
83*061da546Spatrick if (strrchr(tmp_name, '/'))
84*061da546Spatrick return strdup(strrchr(tmp_name, '/') + 1);
85*061da546Spatrick else
86*061da546Spatrick return strdup(tmp_name);
87*061da546Spatrick }
88*061da546Spatrick
89*061da546Spatrick /* Get a struct kinfo_proc structure for a given pid.
90*061da546Spatrick Process name is required for error printing.
91*061da546Spatrick Gives you the current state of the process and whether it is being debugged
92*061da546Spatrick by anyone.
93*061da546Spatrick memory is malloc()'ed for the returned struct kinfo_proc
94*061da546Spatrick and must be freed by the caller. */
95*061da546Spatrick
get_kinfo_proc_for_pid(pid_t pid,const char * process_name)96*061da546Spatrick struct kinfo_proc *get_kinfo_proc_for_pid(pid_t pid, const char *process_name) {
97*061da546Spatrick struct kinfo_proc *kinfo =
98*061da546Spatrick (struct kinfo_proc *)malloc(sizeof(struct kinfo_proc));
99*061da546Spatrick int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
100*061da546Spatrick size_t len = sizeof(struct kinfo_proc);
101*061da546Spatrick if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), kinfo, &len, NULL, 0) != 0) {
102*061da546Spatrick free((void *)kinfo);
103*061da546Spatrick printf("Could not get kinfo_proc for pid %d\n", (int)pid);
104*061da546Spatrick exit(1);
105*061da546Spatrick }
106*061da546Spatrick return kinfo;
107*061da546Spatrick }
108*061da546Spatrick
109*061da546Spatrick /* Get the basic information (thread_basic_info_t) about a given
110*061da546Spatrick thread.
111*061da546Spatrick Gives you the suspend count; thread state; user time; system time; sleep
112*061da546Spatrick time; etc.
113*061da546Spatrick The return value is a pointer to malloc'ed memory - it is the caller's
114*061da546Spatrick responsibility to free it. */
115*061da546Spatrick
get_thread_basic_info(thread_t thread)116*061da546Spatrick thread_basic_info_t get_thread_basic_info(thread_t thread) {
117*061da546Spatrick kern_return_t kr;
118*061da546Spatrick integer_t *thinfo = (integer_t *)malloc(sizeof(integer_t) * THREAD_INFO_MAX);
119*061da546Spatrick mach_msg_type_number_t thread_info_count = THREAD_INFO_MAX;
120*061da546Spatrick kr = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)thinfo,
121*061da546Spatrick &thread_info_count);
122*061da546Spatrick if (kr != KERN_SUCCESS) {
123*061da546Spatrick printf("Error - unable to get basic thread info for a thread\n");
124*061da546Spatrick exit(1);
125*061da546Spatrick }
126*061da546Spatrick return (thread_basic_info_t)thinfo;
127*061da546Spatrick }
128*061da546Spatrick
129*061da546Spatrick /* Get the thread identifier info (thread_identifier_info_data_t)
130*061da546Spatrick about a given thread.
131*061da546Spatrick Gives you the system-wide unique thread number; the pthread identifier number
132*061da546Spatrick */
133*061da546Spatrick
get_thread_identifier_info(thread_t thread)134*061da546Spatrick thread_identifier_info_data_t get_thread_identifier_info(thread_t thread) {
135*061da546Spatrick kern_return_t kr;
136*061da546Spatrick thread_identifier_info_data_t tident;
137*061da546Spatrick mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
138*061da546Spatrick kr = thread_info(thread, THREAD_IDENTIFIER_INFO, (thread_info_t)&tident,
139*061da546Spatrick &tident_count);
140*061da546Spatrick if (kr != KERN_SUCCESS) {
141*061da546Spatrick printf("Error - unable to get thread ident for a thread\n");
142*061da546Spatrick exit(1);
143*061da546Spatrick }
144*061da546Spatrick return tident;
145*061da546Spatrick }
146*061da546Spatrick
147*061da546Spatrick /* Given a mach port # (in the examine-threads mach port namespace) for a
148*061da546Spatrick thread,
149*061da546Spatrick find the mach port # in the inferior program's port namespace.
150*061da546Spatrick Sets inferior_port if successful.
151*061da546Spatrick Returns true if successful, false if unable to find the port number. */
152*061da546Spatrick
inferior_namespace_mach_port_num(task_t task,thread_t examine_threads_port,thread_t * inferior_port)153*061da546Spatrick bool inferior_namespace_mach_port_num(task_t task,
154*061da546Spatrick thread_t examine_threads_port,
155*061da546Spatrick thread_t *inferior_port) {
156*061da546Spatrick kern_return_t retval;
157*061da546Spatrick mach_port_name_array_t names;
158*061da546Spatrick mach_msg_type_number_t nameslen;
159*061da546Spatrick mach_port_type_array_t types;
160*061da546Spatrick mach_msg_type_number_t typeslen;
161*061da546Spatrick
162*061da546Spatrick if (inferior_port == NULL)
163*061da546Spatrick return false;
164*061da546Spatrick
165*061da546Spatrick retval = mach_port_names(task, &names, &nameslen, &types, &typeslen);
166*061da546Spatrick if (retval != KERN_SUCCESS) {
167*061da546Spatrick printf("Error - unable to get mach port names for inferior.\n");
168*061da546Spatrick return false;
169*061da546Spatrick }
170*061da546Spatrick int i = 0;
171*061da546Spatrick for (i = 0; i < nameslen; i++) {
172*061da546Spatrick mach_port_t local_name;
173*061da546Spatrick mach_msg_type_name_t local_type;
174*061da546Spatrick retval = mach_port_extract_right(task, names[i], MACH_MSG_TYPE_COPY_SEND,
175*061da546Spatrick &local_name, &local_type);
176*061da546Spatrick if (retval == KERN_SUCCESS) {
177*061da546Spatrick mach_port_deallocate(mach_task_self(), local_name);
178*061da546Spatrick if (local_name == examine_threads_port) {
179*061da546Spatrick *inferior_port = names[i];
180*061da546Spatrick vm_deallocate(mach_task_self(), (vm_address_t)names,
181*061da546Spatrick nameslen * sizeof(mach_port_t));
182*061da546Spatrick vm_deallocate(mach_task_self(), (vm_address_t)types,
183*061da546Spatrick typeslen * sizeof(mach_port_t));
184*061da546Spatrick return true;
185*061da546Spatrick }
186*061da546Spatrick }
187*061da546Spatrick }
188*061da546Spatrick vm_deallocate(mach_task_self(), (vm_address_t)names,
189*061da546Spatrick nameslen * sizeof(mach_port_t));
190*061da546Spatrick vm_deallocate(mach_task_self(), (vm_address_t)types,
191*061da546Spatrick typeslen * sizeof(mach_port_t));
192*061da546Spatrick return false;
193*061da546Spatrick }
194*061da546Spatrick
195*061da546Spatrick /* Get the current pc value for a given thread. */
196*061da546Spatrick
get_current_pc(thread_t thread,int * wordsize)197*061da546Spatrick uint64_t get_current_pc(thread_t thread, int *wordsize) {
198*061da546Spatrick kern_return_t kr;
199*061da546Spatrick
200*061da546Spatrick #if defined(__x86_64__) || defined(__i386__)
201*061da546Spatrick x86_thread_state_t gp_regs;
202*061da546Spatrick mach_msg_type_number_t gp_count = x86_THREAD_STATE_COUNT;
203*061da546Spatrick kr = thread_get_state(thread, x86_THREAD_STATE, (thread_state_t)&gp_regs,
204*061da546Spatrick &gp_count);
205*061da546Spatrick if (kr != KERN_SUCCESS) {
206*061da546Spatrick printf("Error - unable to get registers for a thread\n");
207*061da546Spatrick exit(1);
208*061da546Spatrick }
209*061da546Spatrick
210*061da546Spatrick if (gp_regs.tsh.flavor == x86_THREAD_STATE64) {
211*061da546Spatrick *wordsize = 8;
212*061da546Spatrick return gp_regs.uts.ts64.__rip;
213*061da546Spatrick } else {
214*061da546Spatrick *wordsize = 4;
215*061da546Spatrick return gp_regs.uts.ts32.__eip;
216*061da546Spatrick }
217*061da546Spatrick #endif
218*061da546Spatrick
219*061da546Spatrick #if defined(__arm__)
220*061da546Spatrick arm_thread_state_t gp_regs;
221*061da546Spatrick mach_msg_type_number_t gp_count = ARM_THREAD_STATE_COUNT;
222*061da546Spatrick kr = thread_get_state(thread, ARM_THREAD_STATE, (thread_state_t)&gp_regs,
223*061da546Spatrick &gp_count);
224*061da546Spatrick if (kr != KERN_SUCCESS) {
225*061da546Spatrick printf("Error - unable to get registers for a thread\n");
226*061da546Spatrick exit(1);
227*061da546Spatrick }
228*061da546Spatrick *wordsize = 4;
229*061da546Spatrick return gp_regs.__pc;
230*061da546Spatrick #endif
231*061da546Spatrick
232*061da546Spatrick #if defined(__arm64__)
233*061da546Spatrick arm_thread_state64_t gp_regs;
234*061da546Spatrick mach_msg_type_number_t gp_count = ARM_THREAD_STATE64_COUNT;
235*061da546Spatrick kr = thread_get_state(thread, ARM_THREAD_STATE64, (thread_state_t)&gp_regs,
236*061da546Spatrick &gp_count);
237*061da546Spatrick if (kr != KERN_SUCCESS) {
238*061da546Spatrick printf("Error - unable to get registers for a thread\n");
239*061da546Spatrick exit(1);
240*061da546Spatrick }
241*061da546Spatrick *wordsize = 8;
242*061da546Spatrick return gp_regs.__pc;
243*061da546Spatrick #endif
244*061da546Spatrick }
245*061da546Spatrick
246*061da546Spatrick /* Get the proc_threadinfo for a given thread.
247*061da546Spatrick Gives you the thread name, if set; current and max priorities.
248*061da546Spatrick Returns 1 if successful
249*061da546Spatrick Returns 0 if proc_pidinfo() failed
250*061da546Spatrick */
251*061da546Spatrick
get_proc_threadinfo(pid_t pid,uint64_t thread_handle,struct proc_threadinfo * pth)252*061da546Spatrick int get_proc_threadinfo(pid_t pid, uint64_t thread_handle,
253*061da546Spatrick struct proc_threadinfo *pth) {
254*061da546Spatrick pth->pth_name[0] = '\0';
255*061da546Spatrick int ret = proc_pidinfo(pid, PROC_PIDTHREADINFO, thread_handle, pth,
256*061da546Spatrick sizeof(struct proc_threadinfo));
257*061da546Spatrick if (ret != 0)
258*061da546Spatrick return 1;
259*061da546Spatrick else
260*061da546Spatrick return 0;
261*061da546Spatrick }
262*061da546Spatrick
main(int argc,char ** argv)263*061da546Spatrick int main(int argc, char **argv) {
264*061da546Spatrick kern_return_t kr;
265*061da546Spatrick task_t task;
266*061da546Spatrick pid_t pid = 0;
267*061da546Spatrick char *procname = NULL;
268*061da546Spatrick int arg_is_procname = 0;
269*061da546Spatrick int do_loop = 0;
270*061da546Spatrick int verbose = 0;
271*061da546Spatrick int resume_when_done = 0;
272*061da546Spatrick mach_port_t mytask = mach_task_self();
273*061da546Spatrick
274*061da546Spatrick if (argc != 2 && argc != 3 && argc != 4 && argc != 5) {
275*061da546Spatrick printf("Usage: tdump [-l] [-v] [-r] pid/procname\n");
276*061da546Spatrick exit(1);
277*061da546Spatrick }
278*061da546Spatrick
279*061da546Spatrick if (argc == 3 || argc == 4) {
280*061da546Spatrick int i = 1;
281*061da546Spatrick while (i < argc - 1) {
282*061da546Spatrick if (strcmp(argv[i], "-l") == 0)
283*061da546Spatrick do_loop = 1;
284*061da546Spatrick if (strcmp(argv[i], "-v") == 0)
285*061da546Spatrick verbose = 1;
286*061da546Spatrick if (strcmp(argv[i], "-r") == 0)
287*061da546Spatrick resume_when_done++;
288*061da546Spatrick i++;
289*061da546Spatrick }
290*061da546Spatrick }
291*061da546Spatrick
292*061da546Spatrick char *c = argv[argc - 1];
293*061da546Spatrick if (*c == '\0') {
294*061da546Spatrick printf("Usage: tdump [-l] [-v] pid/procname\n");
295*061da546Spatrick exit(1);
296*061da546Spatrick }
297*061da546Spatrick while (*c != '\0') {
298*061da546Spatrick if (!isdigit(*c)) {
299*061da546Spatrick arg_is_procname = 1;
300*061da546Spatrick procname = argv[argc - 1];
301*061da546Spatrick break;
302*061da546Spatrick }
303*061da546Spatrick c++;
304*061da546Spatrick }
305*061da546Spatrick
306*061da546Spatrick if (arg_is_procname && procname) {
307*061da546Spatrick pid = get_pid_for_process_name(procname);
308*061da546Spatrick } else {
309*061da546Spatrick errno = 0;
310*061da546Spatrick pid = (pid_t)strtol(argv[argc - 1], NULL, 10);
311*061da546Spatrick if (pid == 0 && errno == EINVAL) {
312*061da546Spatrick printf("Usage: tdump [-l] [-v] pid/procname\n");
313*061da546Spatrick exit(1);
314*061da546Spatrick }
315*061da546Spatrick }
316*061da546Spatrick
317*061da546Spatrick const char *process_name = get_process_name_for_pid(pid);
318*061da546Spatrick
319*061da546Spatrick // At this point "pid" is the process id and "process_name" is the process
320*061da546Spatrick // name
321*061da546Spatrick // Now we have to get the process list from the kernel (which only has the
322*061da546Spatrick // truncated
323*061da546Spatrick // 16 char names)
324*061da546Spatrick
325*061da546Spatrick struct kinfo_proc *kinfo = get_kinfo_proc_for_pid(pid, process_name);
326*061da546Spatrick
327*061da546Spatrick printf("pid %d (%s) is currently ", pid, process_name);
328*061da546Spatrick switch (kinfo->kp_proc.p_stat) {
329*061da546Spatrick case SIDL:
330*061da546Spatrick printf("being created by fork");
331*061da546Spatrick break;
332*061da546Spatrick case SRUN:
333*061da546Spatrick printf("runnable");
334*061da546Spatrick break;
335*061da546Spatrick case SSLEEP:
336*061da546Spatrick printf("sleeping on an address");
337*061da546Spatrick break;
338*061da546Spatrick case SSTOP:
339*061da546Spatrick printf("suspended");
340*061da546Spatrick break;
341*061da546Spatrick case SZOMB:
342*061da546Spatrick printf("zombie state - awaiting collection by parent");
343*061da546Spatrick break;
344*061da546Spatrick default:
345*061da546Spatrick printf("unknown");
346*061da546Spatrick }
347*061da546Spatrick if (kinfo->kp_proc.p_flag & P_TRACED)
348*061da546Spatrick printf(" and is being debugged.");
349*061da546Spatrick free((void *)kinfo);
350*061da546Spatrick
351*061da546Spatrick printf("\n");
352*061da546Spatrick
353*061da546Spatrick int csops_flags = 0;
354*061da546Spatrick if (csops(pid, CS_OPS_STATUS, &csops_flags, sizeof(csops_flags)) != -1 &&
355*061da546Spatrick (csops_flags & CS_RESTRICT)) {
356*061da546Spatrick printf("pid %d (%s) is restricted so nothing can attach to it.\n", pid,
357*061da546Spatrick process_name);
358*061da546Spatrick }
359*061da546Spatrick
360*061da546Spatrick kr = task_for_pid(mach_task_self(), pid, &task);
361*061da546Spatrick if (kr != KERN_SUCCESS) {
362*061da546Spatrick printf("Error - unable to task_for_pid()\n");
363*061da546Spatrick exit(1);
364*061da546Spatrick }
365*061da546Spatrick
366*061da546Spatrick struct task_basic_info info;
367*061da546Spatrick unsigned int info_count = TASK_BASIC_INFO_COUNT;
368*061da546Spatrick
369*061da546Spatrick kr = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &info_count);
370*061da546Spatrick if (kr != KERN_SUCCESS) {
371*061da546Spatrick printf("Error - unable to call task_info.\n");
372*061da546Spatrick exit(1);
373*061da546Spatrick }
374*061da546Spatrick printf("Task suspend count: %d.\n", info.suspend_count);
375*061da546Spatrick
376*061da546Spatrick struct timespec *rqtp = (struct timespec *)malloc(sizeof(struct timespec));
377*061da546Spatrick rqtp->tv_sec = 0;
378*061da546Spatrick rqtp->tv_nsec = 150000000;
379*061da546Spatrick
380*061da546Spatrick int loop_cnt = 1;
381*061da546Spatrick do {
382*061da546Spatrick int i;
383*061da546Spatrick if (do_loop)
384*061da546Spatrick printf("Iteration %d:\n", loop_cnt++);
385*061da546Spatrick thread_array_t thread_list;
386*061da546Spatrick mach_msg_type_number_t thread_count;
387*061da546Spatrick
388*061da546Spatrick kr = task_threads(task, &thread_list, &thread_count);
389*061da546Spatrick if (kr != KERN_SUCCESS) {
390*061da546Spatrick printf("Error - unable to get thread list\n");
391*061da546Spatrick exit(1);
392*061da546Spatrick }
393*061da546Spatrick printf("pid %d has %d threads\n", pid, thread_count);
394*061da546Spatrick if (verbose)
395*061da546Spatrick printf("\n");
396*061da546Spatrick
397*061da546Spatrick for (i = 0; i < thread_count; i++) {
398*061da546Spatrick thread_basic_info_t basic_info = get_thread_basic_info(thread_list[i]);
399*061da546Spatrick
400*061da546Spatrick thread_identifier_info_data_t identifier_info =
401*061da546Spatrick get_thread_identifier_info(thread_list[i]);
402*061da546Spatrick
403*061da546Spatrick int wordsize;
404*061da546Spatrick uint64_t pc = get_current_pc(thread_list[i], &wordsize);
405*061da546Spatrick
406*061da546Spatrick printf("thread #%d, system-wide-unique-tid 0x%llx, suspend count is %d, ",
407*061da546Spatrick i, identifier_info.thread_id, basic_info->suspend_count);
408*061da546Spatrick if (wordsize == 8)
409*061da546Spatrick printf("pc 0x%016llx, ", pc);
410*061da546Spatrick else
411*061da546Spatrick printf("pc 0x%08llx, ", pc);
412*061da546Spatrick printf("run state is ");
413*061da546Spatrick switch (basic_info->run_state) {
414*061da546Spatrick case TH_STATE_RUNNING:
415*061da546Spatrick puts("running");
416*061da546Spatrick break;
417*061da546Spatrick case TH_STATE_STOPPED:
418*061da546Spatrick puts("stopped");
419*061da546Spatrick break;
420*061da546Spatrick case TH_STATE_WAITING:
421*061da546Spatrick puts("waiting");
422*061da546Spatrick break;
423*061da546Spatrick case TH_STATE_UNINTERRUPTIBLE:
424*061da546Spatrick puts("uninterruptible");
425*061da546Spatrick break;
426*061da546Spatrick case TH_STATE_HALTED:
427*061da546Spatrick puts("halted");
428*061da546Spatrick break;
429*061da546Spatrick default:
430*061da546Spatrick puts("");
431*061da546Spatrick }
432*061da546Spatrick
433*061da546Spatrick printf(" pthread handle id 0x%llx (not the same value as "
434*061da546Spatrick "pthread_self() returns)\n",
435*061da546Spatrick (uint64_t)identifier_info.thread_handle);
436*061da546Spatrick
437*061da546Spatrick struct proc_threadinfo pth;
438*061da546Spatrick int proc_threadinfo_succeeded =
439*061da546Spatrick get_proc_threadinfo(pid, identifier_info.thread_handle, &pth);
440*061da546Spatrick
441*061da546Spatrick if (proc_threadinfo_succeeded && pth.pth_name[0] != '\0')
442*061da546Spatrick printf(" thread name '%s'\n", pth.pth_name);
443*061da546Spatrick
444*061da546Spatrick printf(" libdispatch qaddr 0x%llx (not the same as the "
445*061da546Spatrick "dispatch_queue_t token)\n",
446*061da546Spatrick (uint64_t)identifier_info.dispatch_qaddr);
447*061da546Spatrick
448*061da546Spatrick if (verbose) {
449*061da546Spatrick printf(
450*061da546Spatrick " (examine-threads port namespace) mach port # 0x%4.4x\n",
451*061da546Spatrick (int)thread_list[i]);
452*061da546Spatrick thread_t mach_port_inferior_namespace;
453*061da546Spatrick if (inferior_namespace_mach_port_num(task, thread_list[i],
454*061da546Spatrick &mach_port_inferior_namespace))
455*061da546Spatrick printf(" (inferior port namepsace) mach port # 0x%4.4x\n",
456*061da546Spatrick (int)mach_port_inferior_namespace);
457*061da546Spatrick printf(" user %d.%06ds, system %d.%06ds",
458*061da546Spatrick basic_info->user_time.seconds,
459*061da546Spatrick basic_info->user_time.microseconds,
460*061da546Spatrick basic_info->system_time.seconds,
461*061da546Spatrick basic_info->system_time.microseconds);
462*061da546Spatrick if (basic_info->cpu_usage > 0) {
463*061da546Spatrick float cpu_percentage = basic_info->cpu_usage / 10.0;
464*061da546Spatrick printf(", using %.1f%% cpu currently", cpu_percentage);
465*061da546Spatrick }
466*061da546Spatrick if (basic_info->sleep_time > 0)
467*061da546Spatrick printf(", this thread has slept for %d seconds",
468*061da546Spatrick basic_info->sleep_time);
469*061da546Spatrick
470*061da546Spatrick printf("\n ");
471*061da546Spatrick printf("scheduling policy %d", basic_info->policy);
472*061da546Spatrick
473*061da546Spatrick if (basic_info->flags != 0) {
474*061da546Spatrick printf(", flags %d", basic_info->flags);
475*061da546Spatrick if ((basic_info->flags | TH_FLAGS_SWAPPED) == TH_FLAGS_SWAPPED)
476*061da546Spatrick printf(" (thread is swapped out)");
477*061da546Spatrick if ((basic_info->flags | TH_FLAGS_IDLE) == TH_FLAGS_IDLE)
478*061da546Spatrick printf(" (thread is idle)");
479*061da546Spatrick }
480*061da546Spatrick if (proc_threadinfo_succeeded)
481*061da546Spatrick printf(", current pri %d, max pri %d", pth.pth_curpri,
482*061da546Spatrick pth.pth_maxpriority);
483*061da546Spatrick
484*061da546Spatrick printf("\n\n");
485*061da546Spatrick }
486*061da546Spatrick
487*061da546Spatrick free((void *)basic_info);
488*061da546Spatrick }
489*061da546Spatrick if (do_loop)
490*061da546Spatrick printf("\n");
491*061da546Spatrick vm_deallocate(mytask, (vm_address_t)thread_list,
492*061da546Spatrick thread_count * sizeof(thread_act_t));
493*061da546Spatrick nanosleep(rqtp, NULL);
494*061da546Spatrick } while (do_loop);
495*061da546Spatrick
496*061da546Spatrick while (resume_when_done > 0) {
497*061da546Spatrick kern_return_t err = task_resume(task);
498*061da546Spatrick if (err != KERN_SUCCESS)
499*061da546Spatrick printf("Error resuming task: %d.", err);
500*061da546Spatrick resume_when_done--;
501*061da546Spatrick }
502*061da546Spatrick
503*061da546Spatrick vm_deallocate(mytask, (vm_address_t)task, sizeof(task_t));
504*061da546Spatrick free((void *)process_name);
505*061da546Spatrick
506*061da546Spatrick return 0;
507*061da546Spatrick }
508