]> git.saurik.com Git - apple/system_cmds.git/blob - lsmp.tproj/task_details.c
system_cmds-671.10.3.tar.gz
[apple/system_cmds.git] / lsmp.tproj / task_details.c
1 /*
2 * Copyright (c) 2002-20014 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
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
31 #include "common.h"
32
33 static my_per_task_info_t NOT_FOUND_TASK_INFO = {
34 .task = NULL,
35 .task_kobject = NULL,
36 .pid = -1,
37 .info = {0,0,0,0,0,0},
38 .table = NULL,
39 .tableCount = 0,
40 .tree = NULL,
41 .treeCount = 0,
42 .valid = FALSE,
43 .processName = "Unknown",
44 .exceptionInfo = {0},
45 .threadInfos = NULL,
46 .threadCount = 0,
47 .threadExceptionInfos = NULL
48 };
49
50 char * get_task_name_by_pid(pid_t pid);
51
52 static void proc_pid_to_name(int pid, char *pname){
53 if (0 == proc_name(pid, pname, PROC_NAME_LEN)) {
54 strcpy(pname, "Unknown Process");
55 }
56 }
57
58 static my_per_task_info_t *global_taskinfo = NULL;
59 static uint32_t global_taskcount = 0;
60
61 my_per_task_info_t * allocate_taskinfo_memory(uint32_t taskCount)
62 {
63 my_per_task_info_t * retval = malloc(taskCount * sizeof(my_per_task_info_t));
64 if (retval) {
65 bzero((void *)retval, taskCount * sizeof(my_per_task_info_t));
66 }
67 global_taskcount = taskCount;
68 global_taskinfo = retval;
69 return retval;
70 }
71
72 void deallocate_taskinfo_memory(my_per_task_info_t *data){
73 if (data) {
74 free(data);
75 global_taskinfo = NULL;
76 global_taskcount = 0;
77 }
78 }
79
80 kern_return_t collect_per_task_info(my_per_task_info_t *taskinfo, task_t target_task)
81 {
82 kern_return_t ret = KERN_SUCCESS;
83 unsigned int kotype = 0;
84 vm_offset_t kobject = (vm_offset_t)0;
85
86 taskinfo->task = target_task;
87 pid_for_task(target_task, &taskinfo->pid);
88
89 ret = task_get_exception_ports(taskinfo->task, EXC_MASK_ALL, taskinfo->exceptionInfo.masks, &taskinfo->exceptionInfo.count, taskinfo->exceptionInfo.ports, taskinfo->exceptionInfo.behaviors, taskinfo->exceptionInfo.flavors);
90
91 if (ret != KERN_SUCCESS) {
92 fprintf(stderr, "task_get_exception_ports() failed: pid:%d error: %s\n",taskinfo->pid, mach_error_string(ret));
93 taskinfo->pid = 0;
94 }
95
96 /* collect threads port as well */
97 taskinfo->threadCount = 0;
98 thread_act_array_t threadPorts;
99 ret = task_threads(taskinfo->task, &threadPorts, &taskinfo->threadCount);
100
101 if (ret != KERN_SUCCESS) {
102 fprintf(stderr, "task_threads() failed: pid:%d error: %s\n",taskinfo->pid, mach_error_string(ret));
103 taskinfo->threadCount = 0;
104 } else {
105 /* collect the thread information */
106 taskinfo->threadInfos = (struct my_per_thread_info *)malloc(sizeof(struct my_per_thread_info) * taskinfo->threadCount);
107 bzero(taskinfo->threadInfos, sizeof(struct my_per_thread_info) * taskinfo->threadCount);
108
109 /* now collect exception ports for each of those threads as well */
110 taskinfo->threadExceptionInfos = (struct exc_port_info *) malloc(sizeof(struct exc_port_info) * taskinfo->threadCount);
111 boolean_t found_exception = false;
112 for (int i = 0; i < taskinfo->threadCount; i++) {
113 unsigned th_kobject = 0;
114 unsigned th_kotype = 0;
115 ipc_voucher_t th_voucher = IPC_VOUCHER_NULL;
116 thread_identifier_info_data_t th_info;
117 mach_msg_type_number_t th_info_count = THREAD_IDENTIFIER_INFO_COUNT;
118 struct exc_port_info *excinfo = &(taskinfo->threadExceptionInfos[i]);
119
120 ret = thread_get_exception_ports(threadPorts[i], EXC_MASK_ALL, excinfo->masks, &excinfo->count, excinfo->ports, excinfo->behaviors, excinfo->flavors);
121 if (ret != KERN_SUCCESS){
122 fprintf(stderr, "thread_get_exception_ports() failed: pid: %d thread: %d error %s\n", taskinfo->pid, threadPorts[i], mach_error_string(ret));
123 }
124
125 if (excinfo->count != 0) {
126 found_exception = true;
127 }
128
129 taskinfo->threadInfos[i].thread = threadPorts[i];
130
131 if (KERN_SUCCESS == mach_port_kernel_object(mach_task_self(), threadPorts[i], &th_kotype, &th_kobject)) {
132 taskinfo->threadInfos[i].th_kobject = th_kobject;
133 if (KERN_SUCCESS == thread_info(threadPorts[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&th_info, &th_info_count)) {
134 taskinfo->threadInfos[i].th_id = th_info.thread_id;
135 }
136 }
137
138 if (KERN_SUCCESS == thread_get_mach_voucher(threadPorts[i], 0, &th_voucher) && th_voucher != IPC_VOUCHER_NULL) {
139 char *detail = copy_voucher_detail(mach_task_self(), th_voucher);
140 taskinfo->threadInfos[i].voucher_detail = strndup(detail, VOUCHER_DETAIL_MAXLEN);
141 free(detail);
142
143 mach_port_deallocate(mach_task_self(), th_voucher);
144 }
145
146 mach_port_deallocate(mach_task_self(), threadPorts[i]);
147 threadPorts[i] = MACH_PORT_NULL;
148 }
149
150 if (found_exception == false) {
151 free(taskinfo->threadExceptionInfos);
152 taskinfo->threadExceptionInfos = NULL;
153 }
154
155 }
156
157 vm_deallocate(mach_task_self(), threadPorts, taskinfo->threadCount * sizeof(thread_act_t));
158 threadPorts = NULL;
159
160 ret = mach_port_space_info(target_task, &taskinfo->info, &taskinfo->table, &taskinfo->tableCount, &taskinfo->tree, &taskinfo->treeCount);
161
162 if (ret != KERN_SUCCESS) {
163 fprintf(stderr, "mach_port_space_info() failed: pid:%d error: %s\n",taskinfo->pid, mach_error_string(ret));
164 taskinfo->pid = 0;
165 return ret;
166 }
167
168 proc_pid_to_name(taskinfo->pid, taskinfo->processName);
169
170 ret = mach_port_kernel_object(mach_task_self(), taskinfo->task, &kotype, (unsigned *)&kobject);
171
172 if (ret == KERN_SUCCESS && kotype == IKOT_TASK) {
173 taskinfo->task_kobject = kobject;
174 taskinfo->valid = TRUE;
175 }
176
177 return ret;
178 }
179
180
181
182 void get_exc_behavior_string(exception_behavior_t b, char *out_string, size_t len)
183 {
184 out_string[0]='\0';
185
186 if (b & MACH_EXCEPTION_CODES)
187 strncat(out_string, "MACH +", len);
188 switch (b & ~MACH_EXCEPTION_CODES) {
189 case EXCEPTION_DEFAULT:
190 strncat(out_string, " DEFAULT", len);
191 break;
192 case EXCEPTION_STATE:
193 strncat(out_string, " STATE", len);
194 break;
195 case EXCEPTION_STATE_IDENTITY:
196 strncat(out_string, " IDENTITY", len);
197 break;
198 default:
199 strncat(out_string, " UNKNOWN", len);
200 }
201 }
202
203 void get_exc_mask_string(exception_mask_t m, char *out_string, size_t len)
204 {
205 out_string[0]='\0';
206
207 if (m & (1<<EXC_BAD_ACCESS))
208 strncat(out_string, " BAD_ACCESS", len);
209 if (m & (1<<EXC_BAD_INSTRUCTION))
210 strncat(out_string," BAD_INSTRUCTION", len);
211 if (m & (1<<EXC_ARITHMETIC))
212 strncat(out_string," ARITHMETIC", len);
213 if (m & (1<<EXC_EMULATION))
214 strncat(out_string," EMULATION", len);
215 if (m & (1<<EXC_SOFTWARE))
216 strncat(out_string," SOFTWARE", len);
217 if (m & (1<<EXC_BREAKPOINT))
218 strncat(out_string," BREAKPOINT", len);
219 if (m & (1<<EXC_SYSCALL))
220 strncat(out_string," SYSCALL", len);
221 if (m & (1<<EXC_MACH_SYSCALL))
222 strncat(out_string," MACH_SYSCALL", len);
223 if (m & (1<<EXC_RPC_ALERT))
224 strncat(out_string," RPC_ALERT", len);
225 if (m & (1<<EXC_CRASH))
226 strncat(out_string," CRASH", len);
227 if (m & (1<<EXC_RESOURCE))
228 strncat(out_string," RESOURCE", len);
229 if (m & (1<<EXC_GUARD))
230 strncat(out_string," GUARD", len);
231
232 }
233
234 kern_return_t print_task_exception_info(my_per_task_info_t *taskinfo)
235 {
236
237 char behavior_string[30];
238 char mask_string[200];
239
240 boolean_t header_required = TRUE;
241 for (int i = 0; i < taskinfo->exceptionInfo.count; i++) {
242 if (taskinfo->exceptionInfo.ports[i] != MACH_PORT_NULL) {
243 if (header_required) {
244
245 printf(" exc_port flavor <behaviors> mask \n");
246 header_required = FALSE;
247 }
248 get_exc_behavior_string(taskinfo->exceptionInfo.behaviors[i], behavior_string, sizeof(behavior_string));
249 get_exc_mask_string(taskinfo->exceptionInfo.masks[i], mask_string, 200);
250 printf(" 0x%08x 0x%03x <%s> %s \n" , taskinfo->exceptionInfo.ports[i], taskinfo->exceptionInfo.flavors[i], behavior_string, mask_string);
251 }
252
253 }
254
255 return KERN_SUCCESS;
256 }
257
258
259 kern_return_t print_task_threads_special_ports(my_per_task_info_t *taskinfo)
260 {
261 kern_return_t kret = KERN_SUCCESS;
262 mach_msg_type_number_t threadcount = taskinfo->threadCount;
263 boolean_t header_required = TRUE;
264 boolean_t newline_required = TRUE;
265 struct my_per_thread_info * info = NULL;
266
267 for (int i = 0; i < threadcount; i++) {
268 info = &taskinfo->threadInfos[i];
269 if (header_required) {
270 printf("Thread_KObject Thread-ID Port Description.");
271 header_required = FALSE;
272 }
273
274 if (newline_required) {
275 printf("\n");
276 }
277 newline_required = TRUE;
278
279 if (info->th_kobject != 0) {
280 /* TODO: Should print tid and stuff */
281 printf("0x%08x ", info->th_kobject);
282 printf("0x%llx ", info->th_id);
283 }
284
285 if (info->voucher_detail != NULL) {
286 printf("%s\n", info->voucher_detail);
287 }
288
289 /* print the thread exception ports also */
290 if (taskinfo->threadExceptionInfos != NULL)
291 {
292
293 struct exc_port_info *excinfo = &taskinfo->threadExceptionInfos[i];
294 char behavior_string[30];
295 char mask_string[200];
296
297 if (excinfo->count > 0) {
298 boolean_t header_required = TRUE;
299 for (int i = 0; i < excinfo->count; i++) {
300 if (excinfo->ports[i] != MACH_PORT_NULL) {
301 if (header_required) {
302 printf("\n exc_port flavor <behaviors> mask -> name owner\n");
303 header_required = FALSE;
304 }
305 get_exc_behavior_string(excinfo->behaviors[i], behavior_string, sizeof(behavior_string));
306 get_exc_mask_string(excinfo->masks[i], mask_string, sizeof(mask_string));
307 printf(" 0x%08x 0x%03x <%s> %s " , excinfo->ports[i], excinfo->flavors[i], behavior_string, mask_string);
308
309 ipc_info_name_t actual_sendinfo;
310 if (KERN_SUCCESS == get_ipc_info_from_lsmp_spaceinfo(excinfo->ports[i], &actual_sendinfo)) {
311 my_per_task_info_t *recv_holder_taskinfo;
312 mach_port_name_t recv_name = MACH_PORT_NULL;
313 if (KERN_SUCCESS == get_taskinfo_of_receiver_by_send_right(&actual_sendinfo, &recv_holder_taskinfo, &recv_name)) {
314 printf(" -> 0x%08x 0x%08x (%d) %s\n",
315 recv_name,
316 actual_sendinfo.iin_object,
317 recv_holder_taskinfo->pid,
318 recv_holder_taskinfo->processName);
319 }
320
321 } else {
322 fprintf(stderr, "failed to find");
323 }
324
325 printf("\n");
326
327 }
328
329 }
330 }
331
332 }
333
334 }
335 printf("\n");
336 return kret;
337 }
338
339 char * get_task_name_by_pid(pid_t pid) {
340 char * retval = "Unknown";
341 for (int i = 0; i < global_taskcount; i++) {
342 if (pid == global_taskinfo[i].pid) {
343 return global_taskinfo[i].processName;
344 }
345 }
346 return retval;
347 }
348
349 my_per_task_info_t * get_taskinfo_by_kobject(natural_t kobj) {
350 my_per_task_info_t *retval = &NOT_FOUND_TASK_INFO;
351 for (int j = 0; j < global_taskcount; j++) {
352 if (global_taskinfo[j].task_kobject == kobj) {
353 retval = &global_taskinfo[j];
354 break;
355 }
356 }
357 return retval;
358 }
359
360 kern_return_t get_taskinfo_of_receiver_by_send_right(ipc_info_name_t *sendright, my_per_task_info_t **out_taskinfo, mach_port_name_t *out_recv_info)
361 {
362 kern_return_t retval = KERN_FAILURE;
363 boolean_t found = FALSE;
364 *out_taskinfo = &NOT_FOUND_TASK_INFO;
365
366 for (int j = 0; j < global_taskcount && !found; j++) {
367 for (int k = 0; k < global_taskinfo[j].tableCount && !found; k++) {
368 if ((global_taskinfo[j].table[k].iin_type & MACH_PORT_TYPE_RECEIVE) &&
369 global_taskinfo[j].table[k].iin_object == sendright->iin_object ) {
370 *out_taskinfo = &global_taskinfo[j];
371 *out_recv_info = global_taskinfo[j].table[k].iin_name;
372 found = TRUE;
373 retval = KERN_SUCCESS;
374 }
375 }
376 }
377 return retval;
378 }
379
380 kern_return_t get_ipc_info_from_lsmp_spaceinfo(mach_port_t port_name, ipc_info_name_t *out_sendright){
381 kern_return_t retval = KERN_FAILURE;
382 bzero(out_sendright, sizeof(ipc_info_name_t));
383 my_per_task_info_t *mytaskinfo = NULL;
384 for (int i = global_taskcount - 1; i >= 0; i--){
385 if (global_taskinfo[i].task == mach_task_self()){
386 mytaskinfo = &global_taskinfo[i];
387 break;
388 }
389 }
390 if (mytaskinfo) {
391 for (int k = 0; k < mytaskinfo->tableCount; k++) {
392 if (port_name == mytaskinfo->table[k].iin_name){
393 bcopy(&mytaskinfo->table[k], out_sendright, sizeof(ipc_info_name_t));
394 retval = KERN_SUCCESS;
395 break;
396 }
397 }
398 }
399 return retval;
400
401 }
402
403