2 * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 #include <System/sys/proc.h>
24 #include <mach/mach.h>
25 #include <mach/mach_error.h>
26 #include <mach_debug/ipc_info.h>
30 #include <TargetConditionals.h>
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_read_for_pid()."
38 #define TASK_FOR_PID_USAGE_MESG ""
41 struct prog_configs lsmp_config
= {
42 .show_all_tasks
= FALSE
,
43 .show_voucher_details
= FALSE
,
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");
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
);
69 print_task_threads_special_ports(taskinfo
, json
);
71 JSON_OBJECT_END(json
);
74 int main(int argc
, char *argv
[]) {
77 my_per_task_info_t
*taskinfo
= NULL
;
79 char *progname
= "lsmp";
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
;
85 while((option
= getopt(argc
, argv
, "hvalp:j:")) != -1) {
88 /* user asked for info on all processes */
90 lsmp_config
.show_all_tasks
= 1;
94 /* for compatibility with sysdiagnose's usage of -all */
95 lsmp_config
.voucher_detail_length
= 1024;
96 /* Fall through to 'v' */
99 lsmp_config
.show_voucher_details
= TRUE
;
100 lsmp_config
.verbose
= TRUE
;
104 lsmp_config
.pid
= atoi(optarg
);
105 if (lsmp_config
.pid
== 0) {
106 fprintf(stderr
, "Unknown pid: %s\n", optarg
);
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
));
120 fprintf(stderr
, "Unknown argument. \n");
121 /* Fall through to 'h' */
124 print_usage(progname
);
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
;
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
));
143 if (psetCount
!= 1) {
144 fprintf(stderr
, "Assertion Failure: pset count greater than one (%d)\n", psetCount
);
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
));
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
));
157 /* convert the processor-set-priv to a list of task read ports for the processor set */
158 ret
= processor_set_tasks_with_flavor(pset_priv
, TASK_FLAVOR_READ
, &tasks
, &taskCount
);
159 if (ret
!= KERN_SUCCESS
) {
160 fprintf(stderr
, "processor_set_tasks_with_flavor() failed: %s\n", mach_error_string(ret
));
163 mach_port_deallocate(mach_task_self(), pset_priv
);
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 (mach_task_is_self(tasks
[i
])){
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
;
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_read_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
);
194 /* convert each task to structure of pointer for the task info */
195 psettaskinfo
= allocate_taskinfo_memory(taskCount
);
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
]);
204 if (psettaskinfo
[i
].pid
== lsmp_config
.pid
) {
205 taskinfo
= &psettaskinfo
[i
];
209 JSON_OBJECT_BEGIN(lsmp_config
.json_output
);
210 JSON_OBJECT_SET(lsmp_config
.json_output
, version
, "%.1f", 1.0);
211 JSON_KEY(lsmp_config
.json_output
, processes
);
212 JSON_ARRAY_BEGIN(lsmp_config
.json_output
);
214 if (lsmp_config
.show_all_tasks
== FALSE
) {
215 if (taskinfo
== NULL
) {
216 fprintf(stderr
, "Failed to find task ipc information for pid %d\n", lsmp_config
.pid
);
219 print_task_info(taskinfo
, taskCount
, psettaskinfo
, TRUE
, lsmp_config
.json_output
);
221 for (i
=0; i
< taskCount
; i
++) {
222 if (psettaskinfo
[i
].valid
!= TRUE
)
224 print_task_info(&psettaskinfo
[i
], taskCount
, psettaskinfo
, lsmp_config
.verbose
, lsmp_config
.json_output
);
229 JSON_ARRAY_END(lsmp_config
.json_output
);
230 JSON_OBJECT_END(lsmp_config
.json_output
);
233 vm_deallocate(mach_task_self(), (vm_address_t
)tasks
, (vm_size_t
)taskCount
* sizeof(mach_port_t
));
236 deallocate_taskinfo_memory(psettaskinfo
);
238 JSON_CLOSE(lsmp_config
.json_output
);