[Lldb-commits] [lldb] r134135 - /lldb/trunk/tools/darwin-threads/examine-threads.c
Jason Molenda
jmolenda at apple.com
Thu Jun 30 00:25:17 PDT 2011
Author: jmolenda
Date: Thu Jun 30 02:25:17 2011
New Revision: 134135
URL: http://llvm.org/viewvc/llvm-project?rev=134135&view=rev
Log:
Restructure to be modular instead of a single big function;
should make it a little easier to use this as an example of
how to fetch all the different bits of information about
threads.
Modified:
lldb/trunk/tools/darwin-threads/examine-threads.c
Modified: lldb/trunk/tools/darwin-threads/examine-threads.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/darwin-threads/examine-threads.c?rev=134135&r1=134134&r2=134135&view=diff
==============================================================================
--- lldb/trunk/tools/darwin-threads/examine-threads.c (original)
+++ lldb/trunk/tools/darwin-threads/examine-threads.c Thu Jun 30 02:25:17 2011
@@ -6,6 +6,231 @@
#include <sys/sysctl.h>
#include <ctype.h>
#include <libproc.h>
+#include <errno.h>
+
+/* Step through the process table, find a matching process name, return
+ the pid of that matched process.
+ If there are multiple processes with that name, issue a warning on stdout
+ and return the highest numbered process.
+ The proc_pidpath() call is used which gets the full process name including
+ directories to the executable and the full (longer than 16 character)
+ executable name. */
+
+pid_t
+get_pid_for_process_name (const char *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 (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);
+ }
+ return highest_pid;
+}
+
+/* Given a pid, get the full executable name (including directory
+ paths and the longer-than-16-chars executable name) and return
+ the basename of that (i.e. do not include the directory components).
+ This function mallocs the memory for the string it returns;
+ the caller must free this memory. */
+
+const char *
+get_process_name_for_pid (pid_t pid)
+{
+ char tmp_name[PATH_MAX];
+ if (proc_pidpath (pid, tmp_name, sizeof (tmp_name)) == 0)
+ {
+ printf ("Could not find process with pid of %d\n", (int) pid);
+ exit (1);
+ }
+ if (strrchr (tmp_name, '/'))
+ return strdup (strrchr (tmp_name, '/') + 1);
+ else
+ return strdup (tmp_name);
+}
+
+/* Get a struct kinfo_proc structure for a given pid.
+ Process name is required for error printing.
+ Gives you the current state of the process and whether it is being debugged by anyone.
+ memory is malloc()'ed for the returned struct kinfo_proc
+ and must be freed by the caller. */
+
+struct kinfo_proc *
+get_kinfo_proc_for_pid (pid_t pid, const char *process_name)
+{
+ 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 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);
+ }
+
+ 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)
+ {
+ struct kinfo_proc *kinfo = (struct kinfo_proc *) malloc (sizeof (struct kinfo_proc));
+ memcpy (kinfo, &all_kinfos[i], sizeof (struct kinfo_proc));
+ free ((void *) all_kinfos);
+ return kinfo;
+ }
+ printf ("Did not find process '%s' when re-getting proc table.\n", process_name);
+ exit (1);
+}
+
+/* Get the basic information (thread_basic_info_t) about a given
+ thread.
+ Gives you the suspend count; thread state; user time; system time; sleep time; etc.
+ The return value is a pointer to malloc'ed memory - it is the caller's
+ responsibility to free it. */
+
+thread_basic_info_t
+get_thread_basic_info (thread_t thread)
+{
+ kern_return_t kr;
+ integer_t *thinfo = (integer_t *) malloc (sizeof (integer_t) * THREAD_INFO_MAX);
+ mach_msg_type_number_t thread_info_count = THREAD_INFO_MAX;
+ kr = thread_info (thread, 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);
+ }
+ return (thread_basic_info_t) thinfo;
+}
+
+/* Get the thread identifier info (thread_identifier_info_data_t)
+ about a given thread.
+ Gives you the system-wide unique thread number; the pthread identifier number
+*/
+
+thread_identifier_info_data_t
+get_thread_identifier_info (thread_t thread)
+{
+ kern_return_t kr;
+ thread_identifier_info_data_t tident;
+ mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
+ kr = thread_info (thread, 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);
+ }
+ return tident;
+}
+
+/* Get the current pc value for a given thread. */
+
+uint64_t
+get_current_pc (thread_t thread, int *wordsize)
+{
+ kern_return_t kr;
+
+#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, 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)
+ {
+ *wordsize = 8;
+ return gp_regs.uts.ts64.__rip;
+ }
+ else
+ {
+ *wordsize = 4;
+ return gp_regs.uts.ts32.__eip;
+ }
+#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, 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);
+ }
+ return gp_regs.__pc;
+ *wordsize = 4;
+#endif
+
+}
+
+/* Get the proc_threadinfo for a given thread.
+ Gives you the thread name, if set; current and max priorities.
+ Returns 1 if successful
+ Returns 0 if proc_pidinfo() failed
+*/
+
+int
+get_proc_threadinfo (pid_t pid, uint64_t thread_handle, struct proc_threadinfo *pth)
+{
+ pth->pth_name[0] = '\0';
+ int ret = proc_pidinfo (pid, PROC_PIDTHREADINFO, thread_handle,
+ pth, sizeof (struct proc_threadinfo));
+ if (ret != 0)
+ return 1;
+ else
+ return 0;
+}
int
main (int argc, char **argv)
@@ -56,113 +281,28 @@
c++;
}
- // the argument is a pid
- if (arg_is_procname == 0)
+ if (arg_is_procname && procname)
{
- pid = atoi (argv[argc - 1]);
- if (pid == 0)
- {
- printf ("Usage: tdump [-l] [-v] pid/procname\n");
- exit (1);
- }
+ pid = get_pid_for_process_name (procname);
}
-
- // Look up the pid for the provided process name
- if (arg_is_procname)
+ else
{
- 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++)
+ errno = 0;
+ pid = (pid_t) strtol (argv[argc - 1], NULL, 10);
+ if (pid == 0 && errno == EINVAL)
{
- 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 (match_count == 0)
- {
- printf ("Did not find process '%s'.\n", procname);
+ printf ("Usage: tdump [-l] [-v] pid/procname\n");
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 ("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);
+ const char *process_name = get_process_name_for_pid (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)
- 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 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 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 ("Did not find process '%s' when re-getting proc table.\n", process_name);
- exit (1);
- }
+ struct kinfo_proc *kinfo = get_kinfo_proc_for_pid (pid, process_name);
printf ("pid %d (%s) is currently ", pid, process_name);
switch (kinfo->kp_proc.p_stat) {
@@ -175,6 +315,7 @@
}
if (kinfo->kp_proc.p_flag & P_TRACED)
printf (" and is being debugged.");
+ free ((void *) kinfo);
printf ("\n");
@@ -205,78 +346,27 @@
exit (1);
}
printf ("pid %d has %d threads\n", pid, thread_count);
+ if (verbose)
+ printf ("\n");
for (i = 0; i < thread_count; i++)
{
- 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);
- }
+ thread_basic_info_t basic_info = get_thread_basic_info (thread_list[i]);
- 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);
- }
+ thread_identifier_info_data_t identifier_info = get_thread_identifier_info (thread_list[i]);
- 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
+ int wordsize;
+ uint64_t pc = get_current_pc (thread_list[i], &wordsize);
printf ("thread #%d, unique tid %lld, suspend count is %d, ", i,
- tident.thread_id,
- basic_info_th->suspend_count);
- if (width == 8)
+ identifier_info.thread_id,
+ basic_info->suspend_count);
+ if (wordsize == 8)
printf ("pc 0x%016llx, ", pc);
else
printf ("pc 0x%08llx, ", pc);
printf ("run state is ");
- switch (basic_info_th->run_state) {
+ switch (basic_info->run_state) {
case TH_STATE_RUNNING: puts ("running"); break;
case TH_STATE_STOPPED: puts ("stopped"); break;
case TH_STATE_WAITING: puts ("waiting"); break;
@@ -288,43 +378,44 @@
{
printf (" ");
printf ("mach thread #0x%4.4x ", (int) thread_list[i]);
- printf ("pthread handle id 0x%llx ", (uint64_t) tident.thread_handle);
+ printf ("pthread handle id 0x%llx ", (uint64_t) identifier_info.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')
+ int proc_threadinfo_succeeded = get_proc_threadinfo (pid, identifier_info.thread_handle, &pth);
+
+ if (proc_threadinfo_succeeded && 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)
+ basic_info->user_time.seconds, basic_info->user_time.microseconds,
+ basic_info->system_time.seconds, basic_info->system_time.microseconds);
+ if (basic_info->cpu_usage > 0)
{
- float cpu_percentage = basic_info_th->cpu_usage / 10.0;
+ float cpu_percentage = basic_info->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);
+ if (basic_info->sleep_time > 0)
+ printf (", this thread has slept for %d seconds", basic_info->sleep_time);
printf ("\n ");
- printf ("scheduling policy %d", basic_info_th->policy);
+ printf ("scheduling policy %d", basic_info->policy);
- if (basic_info_th->flags != 0)
+ if (basic_info->flags != 0)
{
- printf (", flags %d", basic_info_th->flags);
- if ((basic_info_th->flags | TH_FLAGS_SWAPPED) == TH_FLAGS_SWAPPED)
+ printf (", flags %d", basic_info->flags);
+ if ((basic_info->flags | TH_FLAGS_SWAPPED) == TH_FLAGS_SWAPPED)
printf (" (thread is swapped out)");
- if ((basic_info_th->flags | TH_FLAGS_IDLE) == TH_FLAGS_IDLE)
+ if ((basic_info->flags | TH_FLAGS_IDLE) == TH_FLAGS_IDLE)
printf (" (thread is idle)");
}
- if (ret != 0)
+ if (proc_threadinfo_succeeded)
printf (", current pri %d, max pri %d", pth.pth_curpri, pth.pth_maxpriority);
- puts ("");
+ printf ("\n\n");
}
+
+ free ((void *) basic_info);
}
if (do_loop)
printf ("\n");
@@ -334,6 +425,7 @@
} while (do_loop);
vm_deallocate (mytask, (vm_address_t) task, sizeof (task_t));
+ free ((void *) process_name);
return 0;
}
More information about the lldb-commits
mailing list