/*
- * Copyright (c) 2002-20014 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <stdlib.h>
#include <libproc.h>
#include <TargetConditionals.h>
+#include <errno.h>
#include "common.h"
-
+#include "json.h"
#if TARGET_OS_EMBEDDED
#define TASK_FOR_PID_USAGE_MESG "\nPlease check your boot-args to ensure you have access to task_for_pid()."
#define TASK_FOR_PID_USAGE_MESG ""
#endif
-
struct prog_configs lsmp_config = {
.show_all_tasks = FALSE,
.show_voucher_details = FALSE,
.verbose = FALSE,
.pid = 0,
+ .json_output = NULL,
};
-my_per_task_info_t *psettaskinfo;
-mach_msg_type_number_t taskCount;
-
static void print_usage(char *progname) {
fprintf(stderr, "Usage: %s -p <pid> [-a|-v|-h] \n", "lsmp");
fprintf(stderr, "Lists information about mach ports. Please see man page for description of each column.\n");
fprintf(stderr, "\t-p <pid> : print all mach ports for process id <pid>. \n");
fprintf(stderr, "\t-a : print all mach ports for all processeses. \n");
fprintf(stderr, "\t-v : print verbose details for kernel objects.\n");
+ fprintf(stderr, "\t-j <path> : save output as JSON to <path>.\n");
fprintf(stderr, "\t-h : print this help.\n");
exit(1);
}
+static void print_task_info(my_per_task_info_t *taskinfo, mach_msg_type_number_t taskCount, my_per_task_info_t *psettaskinfo, boolean_t verbose, JSON_t json) {
+ printf("Process (%d) : %s\n", taskinfo->pid, taskinfo->processName);
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
+ JSON_OBJECT_SET(json, name, "%s", taskinfo->processName);
+ show_task_mach_ports(taskinfo, taskCount, psettaskinfo, json);
+ print_task_exception_info(taskinfo, json);
+ if (verbose) {
+ printf("\n");
+ print_task_threads_special_ports(taskinfo, json);
+ }
+ JSON_OBJECT_END(json);
+}
int main(int argc, char *argv[]) {
kern_return_t ret;
char *progname = "lsmp";
int i, option = 0;
lsmp_config.voucher_detail_length = 128; /* default values for config */
-
- while((option = getopt(argc, argv, "hvalp:")) != -1) {
+ my_per_task_info_t *psettaskinfo;
+ mach_msg_type_number_t taskCount;
+
+ while((option = getopt(argc, argv, "hvalp:j:")) != -1) {
switch(option) {
case 'a':
/* user asked for info on all processes */
lsmp_config.pid = 0;
lsmp_config.show_all_tasks = 1;
break;
-
+
case 'l':
/* for compatibility with sysdiagnose's usage of -all */
lsmp_config.voucher_detail_length = 1024;
/* Fall through to 'v' */
-
+
case 'v':
lsmp_config.show_voucher_details = TRUE;
lsmp_config.verbose = TRUE;
break;
-
+
case 'p':
lsmp_config.pid = atoi(optarg);
if (lsmp_config.pid == 0) {
exit(1);
}
break;
-
+
+ case 'j':
+ lsmp_config.json_output = JSON_OPEN(optarg);
+ if (lsmp_config.json_output == NULL) {
+ fprintf(stderr, "Unable to open \"%s\": %s\n", optarg, strerror(errno));
+ exit(1);
+ }
+ break;
+
default:
fprintf(stderr, "Unknown argument. \n");
/* Fall through to 'h' */
-
+
case 'h':
print_usage(progname);
break;
-
+
}
}
argc -= optind;
argv += optind;
-
-
+
/* if privileged, get the info for all tasks so we can match ports up */
if (geteuid() == 0) {
processor_set_name_array_t psets;
mach_msg_type_number_t psetCount;
mach_port_t pset_priv;
-
-
+
ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
if (ret != KERN_SUCCESS) {
fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
exit(1);
}
-
+
/* convert the processor-set-name port to a privileged port */
ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
if (ret != KERN_SUCCESS) {
}
mach_port_deallocate(mach_task_self(), psets[0]);
vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
-
+
/* convert the processor-set-priv to a list of tasks for the processor set */
ret = processor_set_tasks(pset_priv, &tasks, &taskCount);
if (ret != KERN_SUCCESS) {
exit(1);
}
mach_port_deallocate(mach_task_self(), pset_priv);
-
+
/* swap my current instances port to be last to collect all threads and exception port info */
int myTaskPosition = -1;
for (int i = 0; i < taskCount; i++) {
taskCount = 1;
tasks = &aTask;
}
-
+
/* convert each task to structure of pointer for the task info */
psettaskinfo = allocate_taskinfo_memory(taskCount);
-
+
for (i = 0; i < taskCount; i++) {
ret = collect_per_task_info(&psettaskinfo[i], tasks[i]);
if (ret != KERN_SUCCESS) {
printf("Ignoring failure of mach_port_space_info() for task %d for '-all'\n", tasks[i]);
continue;
}
-
+
if (psettaskinfo[i].pid == lsmp_config.pid)
taskinfo = &psettaskinfo[i];
-
+
ret = KERN_SUCCESS;
}
-
-
+
+ JSON_OBJECT_BEGIN(lsmp_config.json_output);
+ JSON_OBJECT_SET(lsmp_config.json_output, version, "%.1f", 1.0);
+ JSON_KEY(lsmp_config.json_output, processes);
+ JSON_ARRAY_BEGIN(lsmp_config.json_output);
+
if (lsmp_config.show_all_tasks == FALSE) {
if (taskinfo == NULL) {
fprintf(stderr, "Failed to find task ipc information for pid %d\n", lsmp_config.pid);
exit(1);
}
- printf("Process (%d) : %s\n", taskinfo->pid, taskinfo->processName);
- show_task_mach_ports(taskinfo, taskCount, psettaskinfo);
- print_task_exception_info(taskinfo);
- printf("\n");
- print_task_threads_special_ports(taskinfo);
-
-
+ print_task_info(taskinfo, taskCount, psettaskinfo, TRUE, lsmp_config.json_output);
} else {
for (i=0; i < taskCount; i++) {
if (psettaskinfo[i].valid != TRUE)
continue;
- printf("Process (%d) : %s\n", psettaskinfo[i].pid, psettaskinfo[i].processName);
- show_task_mach_ports(&psettaskinfo[i], taskCount, psettaskinfo);
- print_task_exception_info(&psettaskinfo[i]);
-
- if (lsmp_config.verbose) {
- printf("\n");
- print_task_threads_special_ports(&psettaskinfo[i]);
- }
-
+ print_task_info(&psettaskinfo[i], taskCount, psettaskinfo, lsmp_config.verbose, lsmp_config.json_output);
printf("\n\n");
}
}
-
+
+ JSON_ARRAY_END(lsmp_config.json_output);
+ JSON_OBJECT_END(lsmp_config.json_output);
+
if (taskCount > 1) {
vm_deallocate(mach_task_self(), (vm_address_t)tasks, (vm_size_t)taskCount * sizeof(mach_port_t));
}
-
+
deallocate_taskinfo_memory(psettaskinfo);
-
+
+ JSON_CLOSE(lsmp_config.json_output);
+
return(0);
}