]> git.saurik.com Git - apple/system_cmds.git/blob - lsmp.tproj/task_details.c
system_cmds-643.30.1.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 };
45
46 char * get_task_name_by_pid(pid_t pid);
47
48 static void proc_pid_to_name(int pid, char *pname){
49 if (0 == proc_name(pid, pname, PROC_NAME_LEN)) {
50 strcpy(pname, "Unknown Process");
51 }
52 }
53
54 static my_per_task_info_t *global_taskinfo = NULL;
55 static uint32_t global_taskcount = 0;
56
57 my_per_task_info_t * allocate_taskinfo_memory(uint32_t taskCount)
58 {
59 my_per_task_info_t * retval = malloc(taskCount * sizeof(my_per_task_info_t));
60 if (retval) {
61 bzero((void *)retval, taskCount * sizeof(my_per_task_info_t));
62 }
63 global_taskcount = taskCount;
64 global_taskinfo = retval;
65 return retval;
66 }
67
68 void deallocate_taskinfo_memory(my_per_task_info_t *data){
69 if (data) {
70 free(data);
71 global_taskinfo = NULL;
72 global_taskcount = 0;
73 }
74 }
75
76 kern_return_t collect_per_task_info(my_per_task_info_t *taskinfo, task_t target_task)
77 {
78 kern_return_t ret = KERN_SUCCESS;
79 unsigned int kotype = 0;
80 vm_offset_t kobject = (vm_offset_t)0;
81
82 taskinfo->task = target_task;
83 pid_for_task(target_task, &taskinfo->pid);
84
85 ret = mach_port_space_info(target_task, &taskinfo->info,
86 &taskinfo->table, &taskinfo->tableCount,
87 &taskinfo->tree, &taskinfo->treeCount);
88
89 if (ret != KERN_SUCCESS) {
90 fprintf(stderr, "mach_port_space_info() failed: pid:%d error: %s\n",taskinfo->pid, mach_error_string(ret));
91 taskinfo->pid = 0;
92 return ret;
93 }
94
95 proc_pid_to_name(taskinfo->pid, taskinfo->processName);
96 ret = mach_port_kernel_object(mach_task_self(), taskinfo->task, &kotype, (unsigned *)&kobject);
97
98 if (ret == KERN_SUCCESS && kotype == IKOT_TASK) {
99 taskinfo->task_kobject = kobject;
100 taskinfo->valid = TRUE;
101 }
102
103 return ret;
104 }
105
106 struct exc_port_info {
107 mach_msg_type_number_t count;
108 mach_port_t ports[EXC_TYPES_COUNT];
109 exception_mask_t masks[EXC_TYPES_COUNT];
110 exception_behavior_t behaviors[EXC_TYPES_COUNT];
111 thread_state_flavor_t flavors[EXC_TYPES_COUNT];
112 };
113
114 void get_exc_behavior_string(exception_behavior_t b, char *out_string, size_t len)
115 {
116 out_string[0]='\0';
117
118 if (b & MACH_EXCEPTION_CODES)
119 strncat(out_string, "MACH +", len);
120 switch (b & ~MACH_EXCEPTION_CODES) {
121 case EXCEPTION_DEFAULT:
122 strncat(out_string, " DEFAULT", len);
123 break;
124 case EXCEPTION_STATE:
125 strncat(out_string, " STATE", len);
126 break;
127 case EXCEPTION_STATE_IDENTITY:
128 strncat(out_string, " IDENTITY", len);
129 break;
130 default:
131 strncat(out_string, " UNKNOWN", len);
132 }
133 }
134
135 void get_exc_mask_string(exception_mask_t m, char *out_string, size_t len)
136 {
137 out_string[0]='\0';
138
139 if (m & (1<<EXC_BAD_ACCESS))
140 strncat(out_string, " BAD_ACCESS", len);
141 if (m & (1<<EXC_BAD_INSTRUCTION))
142 strncat(out_string," BAD_INSTRUCTION", len);
143 if (m & (1<<EXC_ARITHMETIC))
144 strncat(out_string," ARITHMETIC", len);
145 if (m & (1<<EXC_EMULATION))
146 strncat(out_string," EMULATION", len);
147 if (m & (1<<EXC_SOFTWARE))
148 strncat(out_string," SOFTWARE", len);
149 if (m & (1<<EXC_BREAKPOINT))
150 strncat(out_string," BREAKPOINT", len);
151 if (m & (1<<EXC_SYSCALL))
152 strncat(out_string," SYSCALL", len);
153 if (m & (1<<EXC_MACH_SYSCALL))
154 strncat(out_string," MACH_SYSCALL", len);
155 if (m & (1<<EXC_RPC_ALERT))
156 strncat(out_string," RPC_ALERT", len);
157 if (m & (1<<EXC_CRASH))
158 strncat(out_string," CRASH", len);
159 if (m & (1<<EXC_RESOURCE))
160 strncat(out_string," RESOURCE", len);
161 if (m & (1<<EXC_GUARD))
162 strncat(out_string," GUARD", len);
163
164 }
165
166 kern_return_t print_task_exception_info(my_per_task_info_t *taskinfo)
167 {
168 kern_return_t kr = KERN_SUCCESS;
169 exception_mask_t mask = EXC_MASK_ALL;
170 struct exc_port_info excinfo;
171 char behavior_string[30];
172 char mask_string[200];
173
174 kr = task_get_exception_ports(taskinfo->task, mask, excinfo.masks, &excinfo.count, excinfo.ports, excinfo.behaviors, excinfo.flavors);
175
176 if (kr != KERN_SUCCESS) {
177 fprintf(stderr, "Failed task_get_exception_ports task: %d pid: %d\n", taskinfo->task, taskinfo->pid);
178 return kr;
179 }
180 boolean_t header_required = TRUE;
181 for (int i = 0; i < excinfo.count; i++) {
182 if (excinfo.ports[i] != MACH_PORT_NULL) {
183 if (header_required) {
184 printf("port flavor <behaviors> mask \n");
185 header_required = FALSE;
186 }
187 get_exc_behavior_string(excinfo.behaviors[i], behavior_string, sizeof(behavior_string));
188 get_exc_mask_string(excinfo.masks[i], mask_string, 200);
189 printf("0x%08x 0x%03x <%s> %s \n" , excinfo.ports[i], excinfo.flavors[i], behavior_string, mask_string);
190 mach_port_deallocate(mach_task_self(), excinfo.ports[i]);
191 }
192
193 }
194
195 return kr;
196 }
197
198
199 kern_return_t print_task_threads_special_ports(my_per_task_info_t *taskinfo)
200 {
201 kern_return_t kret = KERN_SUCCESS;
202 thread_act_array_t threadlist;
203 mach_msg_type_number_t threadcount=0;
204 kret = task_threads(taskinfo->task, &threadlist, &threadcount);
205 boolean_t header_required = TRUE;
206 boolean_t newline_required = TRUE;
207 unsigned th_kobject = 0;
208 unsigned th_kotype = 0;
209
210 for (int i = 0; i < threadcount; i++) {
211 if (header_required) {
212 printf("Threads Thread-ID DispatchQ Port Description.");
213 header_required = FALSE;
214 }
215
216 if (newline_required) {
217 printf("\n");
218 }
219 newline_required = TRUE;
220 if (KERN_SUCCESS == mach_port_kernel_object(mach_task_self(), threadlist[i], &th_kotype, &th_kobject)) {
221 /* TODO: Should print tid and stuff */
222 thread_identifier_info_data_t th_info;
223 mach_msg_type_number_t th_info_count = THREAD_IDENTIFIER_INFO_COUNT;
224 printf("0x%08x ", th_kobject);
225 if (KERN_SUCCESS == thread_info(threadlist[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&th_info, &th_info_count)) {
226 printf("%16llu 0x%016llx ", th_info.thread_id, th_info.dispatch_qaddr);
227 }
228 else
229 printf(" ");
230
231 }
232
233 ipc_voucher_t th_voucher = IPC_VOUCHER_NULL;
234 if (KERN_SUCCESS == thread_get_mach_voucher(threadlist[i], 0, &th_voucher) && th_voucher != IPC_VOUCHER_NULL) {
235 show_voucher_detail(mach_task_self(), th_voucher);
236 mach_port_deallocate(mach_task_self(), th_voucher);
237 newline_required = FALSE;
238 }
239 mach_port_deallocate(mach_task_self(), threadlist[i]);
240 }
241 return kret;
242 }
243
244 char * get_task_name_by_pid(pid_t pid) {
245 char * retval = "Unknown";
246 for (int i = 0; i < global_taskcount; i++) {
247 if (pid == global_taskinfo[i].pid) {
248 return global_taskinfo[i].processName;
249 }
250 }
251 return retval;
252 }
253
254 my_per_task_info_t * get_taskinfo_by_kobject(natural_t kobj) {
255 my_per_task_info_t *retval = &NOT_FOUND_TASK_INFO;
256 for (int j = 0; j < global_taskcount; j++) {
257 if (global_taskinfo[j].task_kobject == kobj) {
258 retval = &global_taskinfo[j];
259 break;
260 }
261 }
262 return retval;
263 }
264
265 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)
266 {
267 kern_return_t retval = KERN_FAILURE;
268 boolean_t found = FALSE;
269 *out_taskinfo = &NOT_FOUND_TASK_INFO;
270
271 for (int j = 0; j < global_taskcount && !found; j++) {
272 for (int k = 0; k < global_taskinfo[j].tableCount && !found; k++) {
273 if ((global_taskinfo[j].table[k].iin_type & MACH_PORT_TYPE_RECEIVE) &&
274 global_taskinfo[j].table[k].iin_object == sendright->iin_object ) {
275 *out_taskinfo = &global_taskinfo[j];
276 *out_recv_info = global_taskinfo[j].table[k].iin_name;
277 found = TRUE;
278 retval = KERN_SUCCESS;
279 }
280 }
281 }
282 return retval;
283 }
284
285