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