xref: /openbsd-src/gnu/llvm/lldb/tools/darwin-threads/examine-threads.c (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
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