diff options
author | Jason Molenda <jmolenda@apple.com> | 2011-06-21 02:57:15 +0000 |
---|---|---|
committer | Jason Molenda <jmolenda@apple.com> | 2011-06-21 02:57:15 +0000 |
commit | 98322e64c3ae6fa964cb21f9aab068f0984c3231 (patch) | |
tree | 1bc52f2c4d92d4b1e4adb3bd22e1870668e1e4c4 | |
parent | 184f3b37e2a6812c647c2614613a9eebfe33247b (diff) | |
download | bcm5719-llvm-98322e64c3ae6fa964cb21f9aab068f0984c3231.tar.gz bcm5719-llvm-98322e64c3ae6fa964cb21f9aab068f0984c3231.zip |
Replace examine-threads.c with a similar little utility I wrote a
while back. By default its output will be less verbose than the
old examine-threads.c but adding the '-v' command line flag will
give all the information that examine-threads.c provided plus some.
Of note, this implementation can take a process name -- and it will
use the libproc API so it can match program names longer than 16
characters.
llvm-svn: 133500
-rw-r--r-- | lldb/tools/darwin-threads/examine-threads.c | 379 |
1 files changed, 307 insertions, 72 deletions
diff --git a/lldb/tools/darwin-threads/examine-threads.c b/lldb/tools/darwin-threads/examine-threads.c index 4ced99010cd..b8e05c228e7 100644 --- a/lldb/tools/darwin-threads/examine-threads.c +++ b/lldb/tools/darwin-threads/examine-threads.c @@ -1,104 +1,339 @@ -#include <mach/mach.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <mach/mach.h> +#include <time.h> +#include <sys/sysctl.h> +#include <ctype.h> +#include <libproc.h> -void -dump_thread_basic_info (uint32_t index, uint32_t tid, struct thread_basic_info *i) +int +main (int argc, char **argv) { - const char * thread_run_state = NULL; + kern_return_t kr; + task_t task; + thread_t thread; + pid_t pid = 0; + char *procname = NULL; + int arg_is_procname = 0; + int do_loop = 0; + int verbose = 0; + mach_port_t mytask = mach_task_self (); - switch (i->run_state) + if (argc != 2 && argc != 3 && argc != 4) { - case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally - case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped - case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally - case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait - case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a - default: thread_run_state = "???"; break; + printf ("Usage: tdump [-l] [-v] pid/procname\n"); + exit (1); + } + + if (argc == 3 || argc == 4) + { + int i = 1; + while (i < argc - 1) + { + if (strcmp (argv[i], "-l") == 0) + do_loop = 1; + if (strcmp (argv[i], "-v") == 0) + verbose = 1; + i++; + } } -// printf("[%3u] tid: 0x%4.4x, pc: 0x%16.16llx, sp: 0x%16.16llx, user: %d.%06.6d, system: %d.%06.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", - printf("[%3u] tid: 0x%4.4x user: %d.%06d, system: %d.%06d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d, sleep_time: %d\n", - index, - tid, - i->user_time.seconds, i->user_time.microseconds, - i->system_time.seconds, i->system_time.microseconds, - i->cpu_usage, - i->policy, - i->run_state, - thread_run_state, - i->flags, - i->suspend_count, - i->sleep_time); - //DumpRegisterState(0); -} + char *c = argv[argc - 1]; + if (*c == '\0') + { + printf ("Usage: tdump [-l] [-v] pid/procname\n"); + exit (1); + } + while (*c != '\0') + { + if (!isdigit (*c)) + { + arg_is_procname = 1; + procname = argv[argc - 1]; + break; + } + c++; + } + // the argument is a pid + if (arg_is_procname == 0) + { + pid = atoi (argv[argc - 1]); + if (pid == 0) + { + printf ("Usage: tdump [-l] [-v] pid/procname\n"); + exit (1); + } + } -int main (int argc, char ** argv) -{ - kern_return_t kret; - task_t itask; - thread_array_t thread_list; - unsigned int nthreads; - pid_t pid; + // Look up the pid for the provided process name + if (arg_is_procname) + { + int process_count = proc_listpids (PROC_ALL_PIDS, 0, NULL, 0) / sizeof (pid_t); + if (process_count < 1) + { + printf ("Only found %d processes running!\n", process_count); + exit (1); + } + + // Allocate a few extra slots in case new processes are spawned + int all_pids_size = sizeof (pid_t) * (process_count + 3); + pid_t *all_pids = (pid_t *) malloc (all_pids_size); + + // re-set process_count in case the number of processes changed (got smaller; we won't do bigger) + process_count = proc_listpids (PROC_ALL_PIDS, 0, all_pids, all_pids_size) / sizeof (pid_t); + + int i; + pid_t highest_pid = 0; + int match_count = 0; + for (i = 1; i < process_count; i++) + { + char pidpath[PATH_MAX]; + int pidpath_len = proc_pidpath (all_pids[i], pidpath, sizeof (pidpath)); + if (pidpath_len == 0) + continue; + char *j = strrchr (pidpath, '/'); + if ((j == NULL && strcmp (procname, pidpath) == 0) + || (j != NULL && strcmp (j + 1, procname) == 0)) + { + match_count++; + if (all_pids[i] > highest_pid) + highest_pid = all_pids[i]; + } + } + free (all_pids); - if (argc < 2) + if (match_count == 0) + { + printf ("Did not find process '%s'.\n", procname); + exit (1); + } + if (match_count > 1) + { + printf ("Warning: More than one process '%s'!\n", procname); + printf (" defaulting to the highest-pid one, %d\n", highest_pid); + } + pid = highest_pid; + } + + char process_name[PATH_MAX]; + char tmp_name[PATH_MAX]; + if (proc_pidpath (pid, tmp_name, sizeof (tmp_name)) == 0) { - printf ("Usage: %s <PID>.\n", argv[0]); - return -1; + printf ("Could not find process with pid of %d\n", (int) pid); + exit (1); } + if (strrchr (tmp_name, '/')) + strcpy (process_name, strrchr (tmp_name, '/') + 1); + else + strcpy (process_name, tmp_name); + - pid = atoi (argv[1]); - printf ("Examining process: %d.\n", pid); + // At this point "pid" is the process id and "process_name" is the process name + // Now we have to get the process list from the kernel (which only has the truncated + // 16 char names) - kret = task_for_pid (mach_task_self (), pid, &itask); - if (kret != KERN_SUCCESS) + struct kinfo_proc *all_kinfos; + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; + size_t len; + if (sysctl (mib, 3, NULL, &len, NULL, 0) != 0) { - printf ("Could not get task for pid %d.\n", pid); - return -1; + printf ("Could not number of processes\n"); + exit (1); + } + all_kinfos = (struct kinfo_proc *) malloc (len); + if (sysctl (mib, 3, all_kinfos, &len, NULL, 0) != 0) + { + printf ("Could not get process infos\n"); + exit (1); } - struct task_basic_info info_for_task; - unsigned int task_info_count = TASK_BASIC_INFO_COUNT; - - kret = - task_info (itask, TASK_BASIC_INFO, (task_info_t) &info_for_task, &task_info_count); - if (kret != KERN_SUCCESS) + struct kinfo_proc *kinfo = NULL; + int proc_count, i; + proc_count = len / sizeof (struct kinfo_proc); + for (i = 0 ; i < proc_count; i++) + if (all_kinfos[i].kp_proc.p_pid == pid) + { + kinfo = &all_kinfos[i]; + break; + } + if (kinfo == NULL) { - printf ("Could not get task info for task: 0x%4.4x.\n", itask); + printf ("Did not find process '%s' when re-getting proc table.\n", process_name); + exit (1); } - - printf ("Task suspend: %d.\n", info_for_task.suspend_count); - kret = task_threads (itask, &thread_list, &nthreads); - if (kret != KERN_SUCCESS) + printf ("pid %d (%s) is currently ", pid, process_name); + switch (kinfo->kp_proc.p_stat) { + case SIDL: printf ("being created by fork"); break; + case SRUN: printf ("runnable"); break; + case SSLEEP: printf ("sleeping on an address"); break; + case SSTOP: printf ("suspended"); break; + case SZOMB: printf ("zombie state - awaiting collection by parent"); break; + default: printf ("unknown"); + } + if (kinfo->kp_proc.p_flag & P_TRACED) + printf (" and is being debugged."); + + printf ("\n"); + + kr = task_for_pid (mach_task_self (), pid, &task); + if (kr != KERN_SUCCESS) { - printf ("Could not get task threads for task 0x%4.4x.\n", itask); - return -1; + printf ("Error - unable to task_for_pid()\n"); + exit (1); } - int i; - for (i = 0; i < nthreads; i++) + struct timespec *rqtp = (struct timespec *) malloc (sizeof (struct timespec)); + rqtp->tv_sec = 0; + rqtp->tv_nsec = 150000000; + + int loop_cnt = 1; + do { - struct thread_basic_info info; - unsigned int thread_info_count = THREAD_BASIC_INFO_COUNT; - kern_return_t kret; - - kret = thread_info (thread_list[i], THREAD_BASIC_INFO, - (thread_info_t) & info, &thread_info_count); - - if (kret != KERN_SUCCESS) + int i; + if (do_loop) + printf ("Iteration %d:\n", loop_cnt++); + thread_array_t thread_list; + mach_msg_type_number_t thread_count; + + kr = task_threads (task, &thread_list, &thread_count); + if (kr != KERN_SUCCESS) { - printf ("Error getting thread basic info for thread 0x%4.4x.\n", thread_list[i]); + printf ("Error - unable to get thread list\n"); + exit (1); } - else + printf ("pid %d has %d threads\n", pid, thread_count); + + for (i = 0; i < thread_count; i++) { - dump_thread_basic_info (i + 1, thread_list[i], &info); + thread_info_data_t thinfo; + mach_msg_type_number_t thread_info_count = THREAD_INFO_MAX; + kr = thread_info (thread_list[i], THREAD_BASIC_INFO, + (thread_info_t) thinfo, &thread_info_count); + if (kr != KERN_SUCCESS) + { + printf ("Error - unable to get basic thread info for a thread\n"); + exit (1); + } + thread_basic_info_t basic_info_th = (thread_basic_info_t) thinfo; + + thread_identifier_info_data_t tident; + mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; + kr = thread_info (thread_list[i], THREAD_IDENTIFIER_INFO, + (thread_info_t) &tident, &tident_count); + if (kr != KERN_SUCCESS) + { + printf ("Error - unable to get thread ident for a thread\n"); + exit (1); + } + + uint64_t pc; + int width; +#if defined (__x86_64__) || defined (__i386__) + x86_thread_state_t gp_regs; + mach_msg_type_number_t gp_count = x86_THREAD_STATE_COUNT; + kr = thread_get_state (thread_list[i], x86_THREAD_STATE, + (thread_state_t) &gp_regs, &gp_count); + if (kr != KERN_SUCCESS) + { + printf ("Error - unable to get registers for a thread\n"); + exit (1); + } + + if (gp_regs.tsh.flavor == x86_THREAD_STATE64) + { + pc = gp_regs.uts.ts64.__rip; + width = 8; + } + else + { + pc = gp_regs.uts.ts32.__eip; + width = 4; + } +#endif + +#if defined (__arm__) + arm_thread_state_t gp_regs; + mach_msg_type_number_t gp_count = ARM_THREAD_STATE_COUNT; + kr = thread_get_state (thread_list[i], ARM_THREAD_STATE, + (thread_state_t) &gp_regs, &gp_count); + if (kr != KERN_SUCCESS) + { + printf ("Error - unable to get registers for a thread\n"); + exit (1); + } + pc = gp_regs.__pc; + width = 4; +#endif + + printf ("thread #%d, unique tid %lld, suspend count is %d, ", i, + tident.thread_id, + basic_info_th->suspend_count); + if (width == 8) + printf ("pc 0x%016llx, ", pc); + else + printf ("pc 0x%08llx, ", pc); + printf ("run state is "); + switch (basic_info_th->run_state) { + case TH_STATE_RUNNING: puts ("running"); break; + case TH_STATE_STOPPED: puts ("stopped"); break; + case TH_STATE_WAITING: puts ("waiting"); break; + case TH_STATE_UNINTERRUPTIBLE: puts ("uninterruptible"); break; + case TH_STATE_HALTED: puts ("halted"); break; + default: puts (""); + } + if (verbose) + { + printf (" "); + printf ("mach thread #0x%4.4x ", (int) thread_list[i]); + printf ("pthread handle id 0x%llx ", (uint64_t) tident.thread_handle); + + struct proc_threadinfo pth; + pth.pth_name[0] = '\0'; + int ret = proc_pidinfo (pid, PROC_PIDTHREADINFO, tident.thread_handle, + &pth, sizeof (pth)); + if (ret != 0 && pth.pth_name[0] != '\0') + printf ("thread name '%s' ", pth.pth_name); + + printf ("\n "); + printf ("user %d.%06ds, system %d.%06ds", + basic_info_th->user_time.seconds, basic_info_th->user_time.microseconds, + basic_info_th->system_time.seconds, basic_info_th->system_time.microseconds); + if (basic_info_th->cpu_usage > 0) + { + float cpu_percentage = basic_info_th->cpu_usage / 10.0; + printf (", using %.1f%% cpu currently", cpu_percentage); + } + if (basic_info_th->sleep_time > 0) + printf (", this thread has slept for %d seconds", basic_info_th->sleep_time); + + printf ("\n "); + printf ("scheduling policy %d", basic_info_th->policy); + + if (basic_info_th->flags != 0) + { + printf (", flags %d", basic_info_th->flags); + if ((basic_info_th->flags | TH_FLAGS_SWAPPED) == TH_FLAGS_SWAPPED) + printf (" (thread is swapped out)"); + if ((basic_info_th->flags | TH_FLAGS_IDLE) == TH_FLAGS_IDLE) + printf (" (thread is idle)"); + } + if (ret != 0) + printf (", current pri %d, max pri %d", pth.pth_curpri, pth.pth_maxpriority); + + puts (""); + } } - if (argc > 2) printf("thread_resume (tid = 0x%4.4x) => %i\n", thread_list[i], thread_resume (thread_list[i])); - } + if (do_loop) + printf ("\n"); + vm_deallocate (mytask, (vm_address_t) thread_list, + thread_count * sizeof (thread_act_t)); + nanosleep (rqtp, NULL); + } while (do_loop); - if (argc > 2) printf("task_resume (task = 0x%4.4x) => %i\n", itask, task_resume (itask)); - return 1; + vm_deallocate (mytask, (vm_address_t) task, sizeof (task_t)); + return 0; } |