]> git.cameronkatri.com Git - apple_cmds.git/blob - system_cmds/lsmp.tproj/lsmp.c
Merge branch 'apple'
[apple_cmds.git] / system_cmds / lsmp.tproj / lsmp.c
1 /*
2 * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 typedef char *kobject_description_t[512];
23 #include <unistd.h>
24 #include <mach/mach.h>
25 #include <mach/mach_error.h>
26 #include <mach_debug/ipc_info.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <libproc.h>
30 #include <TargetConditionals.h>
31 #include <errno.h>
32 #include "common.h"
33 #include "json.h"
34
35 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
36 #define TASK_FOR_PID_USAGE_MESG "\nPlease check your boot-args to ensure you have access to task_for_pid()."
37 #else
38 #define TASK_FOR_PID_USAGE_MESG ""
39 #endif
40
41 struct prog_configs lsmp_config = {
42 .show_all_tasks = FALSE,
43 .show_voucher_details = FALSE,
44 .verbose = FALSE,
45 .pid = 0,
46 .json_output = NULL,
47 };
48
49 static void print_usage(char *progname) {
50 fprintf(stderr, "Usage: %s -p <pid> [-a|-v|-h] \n", "lsmp");
51 fprintf(stderr, "Lists information about mach ports. Please see man page for description of each column.\n");
52 fprintf(stderr, "\t-p <pid> : print all mach ports for process id <pid>. \n");
53 fprintf(stderr, "\t-a : print all mach ports for all processeses. \n");
54 fprintf(stderr, "\t-v : print verbose details for kernel objects.\n");
55 fprintf(stderr, "\t-j <path> : save output as JSON to <path>.\n");
56 fprintf(stderr, "\t-h : print this help.\n");
57 exit(1);
58 }
59
60 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) {
61 printf("Process (%d) : %s\n", taskinfo->pid, taskinfo->processName);
62 JSON_OBJECT_BEGIN(json);
63 JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
64 JSON_OBJECT_SET(json, name, "%s", taskinfo->processName);
65 show_task_mach_ports(taskinfo, taskCount, psettaskinfo, json);
66 print_task_exception_info(taskinfo, json);
67 if (verbose) {
68 printf("\n");
69 print_task_threads_special_ports(taskinfo, json);
70 }
71 JSON_OBJECT_END(json);
72 }
73
74 int main(int argc, char *argv[]) {
75 kern_return_t ret;
76 task_t aTask;
77 my_per_task_info_t *taskinfo = NULL;
78 task_array_t tasks;
79 char *progname = "lsmp";
80 int i, option = 0;
81 lsmp_config.voucher_detail_length = 128; /* default values for config */
82 my_per_task_info_t *psettaskinfo;
83 mach_msg_type_number_t taskCount;
84
85 while((option = getopt(argc, argv, "hvalp:j:")) != -1) {
86 switch(option) {
87 case 'a':
88 /* user asked for info on all processes */
89 lsmp_config.pid = 0;
90 lsmp_config.show_all_tasks = 1;
91 break;
92
93 case 'l':
94 /* for compatibility with sysdiagnose's usage of -all */
95 lsmp_config.voucher_detail_length = 1024;
96 /* Fall through to 'v' */
97
98 case 'v':
99 lsmp_config.show_voucher_details = TRUE;
100 lsmp_config.verbose = TRUE;
101 break;
102
103 case 'p':
104 lsmp_config.pid = atoi(optarg);
105 if (lsmp_config.pid == 0) {
106 fprintf(stderr, "Unknown pid: %s\n", optarg);
107 exit(1);
108 }
109 break;
110
111 case 'j':
112 lsmp_config.json_output = JSON_OPEN(optarg);
113 if (lsmp_config.json_output == NULL) {
114 fprintf(stderr, "Unable to open \"%s\": %s\n", optarg, strerror(errno));
115 exit(1);
116 }
117 break;
118
119 default:
120 fprintf(stderr, "Unknown argument. \n");
121 /* Fall through to 'h' */
122
123 case 'h':
124 print_usage(progname);
125 break;
126
127 }
128 }
129 argc -= optind;
130 argv += optind;
131
132 /* if privileged, get the info for all tasks so we can match ports up */
133 if (geteuid() == 0) {
134 processor_set_name_array_t psets;
135 mach_msg_type_number_t psetCount;
136 mach_port_t pset_priv;
137
138 ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
139 if (ret != KERN_SUCCESS) {
140 fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
141 exit(1);
142 }
143 if (psetCount != 1) {
144 fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
145 exit(1);
146 }
147
148 /* convert the processor-set-name port to a privileged port */
149 ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
150 if (ret != KERN_SUCCESS) {
151 fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret));
152 exit(1);
153 }
154 mach_port_deallocate(mach_task_self(), psets[0]);
155 vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
156
157 /* convert the processor-set-priv to a list of tasks for the processor set */
158 ret = processor_set_tasks(pset_priv, &tasks, &taskCount);
159 if (ret != KERN_SUCCESS) {
160 fprintf(stderr, "processor_set_tasks() failed: %s\n", mach_error_string(ret));
161 exit(1);
162 }
163 mach_port_deallocate(mach_task_self(), pset_priv);
164
165 /* swap my current instances port to be last to collect all threads and exception port info */
166 int myTaskPosition = -1;
167 for (int i = 0; i < taskCount; i++) {
168 if (tasks[i] == mach_task_self()){
169 myTaskPosition = i;
170 break;
171 }
172 }
173 if (myTaskPosition >= 0) {
174 mach_port_t swap_holder = MACH_PORT_NULL;
175 swap_holder = tasks[taskCount - 1];
176 tasks[taskCount - 1] = tasks[myTaskPosition];
177 tasks[myTaskPosition] = swap_holder;
178 }
179
180 }
181 else
182 {
183 fprintf(stderr, "warning: should run as root for best output (cross-ref to other tasks' ports).\n");
184 /* just the one process */
185 ret = task_for_pid(mach_task_self(), lsmp_config.pid, &aTask);
186 if (ret != KERN_SUCCESS) {
187 fprintf(stderr, "task_for_pid() failed: %s %s\n", mach_error_string(ret), TASK_FOR_PID_USAGE_MESG);
188 exit(1);
189 }
190 taskCount = 1;
191 tasks = &aTask;
192 }
193
194 /* convert each task to structure of pointer for the task info */
195 psettaskinfo = allocate_taskinfo_memory(taskCount);
196
197 for (i = 0; i < taskCount; i++) {
198 ret = collect_per_task_info(&psettaskinfo[i], tasks[i]);
199 if (ret != KERN_SUCCESS) {
200 printf("Ignoring failure of mach_port_space_info() for task %d for '-all'\n", tasks[i]);
201 continue;
202 }
203
204 if (psettaskinfo[i].pid == lsmp_config.pid)
205 taskinfo = &psettaskinfo[i];
206 }
207
208 JSON_OBJECT_BEGIN(lsmp_config.json_output);
209 JSON_OBJECT_SET(lsmp_config.json_output, version, "%.1f", 1.0);
210 JSON_KEY(lsmp_config.json_output, processes);
211 JSON_ARRAY_BEGIN(lsmp_config.json_output);
212
213 if (lsmp_config.show_all_tasks == FALSE) {
214 if (taskinfo == NULL) {
215 fprintf(stderr, "Failed to find task ipc information for pid %d\n", lsmp_config.pid);
216 exit(1);
217 }
218 print_task_info(taskinfo, taskCount, psettaskinfo, TRUE, lsmp_config.json_output);
219 } else {
220 for (i=0; i < taskCount; i++) {
221 if (psettaskinfo[i].valid != TRUE)
222 continue;
223 print_task_info(&psettaskinfo[i], taskCount, psettaskinfo, lsmp_config.verbose, lsmp_config.json_output);
224 printf("\n\n");
225 }
226 }
227
228 JSON_ARRAY_END(lsmp_config.json_output);
229 JSON_OBJECT_END(lsmp_config.json_output);
230
231 if (taskCount > 1) {
232 vm_deallocate(mach_task_self(), (vm_address_t)tasks, (vm_size_t)taskCount * sizeof(mach_port_t));
233 }
234
235 deallocate_taskinfo_memory(psettaskinfo);
236
237 JSON_CLOSE(lsmp_config.json_output);
238
239 return(0);
240 }