2 * Copyright (c) 2002-20014 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@
24 #include <mach/mach.h>
25 #include <mach/mach_error.h>
26 #include <mach_debug/ipc_info.h>
33 static my_per_task_info_t NOT_FOUND_TASK_INFO
= {
37 .info
= {0,0,0,0,0,0},
43 .processName
= "Unknown",
46 char * get_task_name_by_pid(pid_t pid
);
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");
54 static my_per_task_info_t
*global_taskinfo
= NULL
;
55 static uint32_t global_taskcount
= 0;
57 my_per_task_info_t
* allocate_taskinfo_memory(uint32_t taskCount
)
59 my_per_task_info_t
* retval
= malloc(taskCount
* sizeof(my_per_task_info_t
));
61 bzero((void *)retval
, taskCount
* sizeof(my_per_task_info_t
));
63 global_taskcount
= taskCount
;
64 global_taskinfo
= retval
;
68 void deallocate_taskinfo_memory(my_per_task_info_t
*data
){
71 global_taskinfo
= NULL
;
76 kern_return_t
collect_per_task_info(my_per_task_info_t
*taskinfo
, task_t target_task
)
78 kern_return_t ret
= KERN_SUCCESS
;
79 unsigned int kotype
= 0;
80 vm_offset_t kobject
= (vm_offset_t
)0;
82 taskinfo
->task
= target_task
;
83 pid_for_task(target_task
, &taskinfo
->pid
);
85 ret
= mach_port_space_info(target_task
, &taskinfo
->info
,
86 &taskinfo
->table
, &taskinfo
->tableCount
,
87 &taskinfo
->tree
, &taskinfo
->treeCount
);
89 if (ret
!= KERN_SUCCESS
) {
90 fprintf(stderr
, "mach_port_space_info() failed: pid:%d error: %s\n",taskinfo
->pid
, mach_error_string(ret
));
95 proc_pid_to_name(taskinfo
->pid
, taskinfo
->processName
);
96 ret
= mach_port_kernel_object(mach_task_self(), taskinfo
->task
, &kotype
, (unsigned *)&kobject
);
98 if (ret
== KERN_SUCCESS
&& kotype
== IKOT_TASK
) {
99 taskinfo
->task_kobject
= kobject
;
100 taskinfo
->valid
= TRUE
;
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
];
114 void get_exc_behavior_string(exception_behavior_t b
, char *out_string
, size_t len
)
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
);
124 case EXCEPTION_STATE
:
125 strncat(out_string
, " STATE", len
);
127 case EXCEPTION_STATE_IDENTITY
:
128 strncat(out_string
, " IDENTITY", len
);
131 strncat(out_string
, " UNKNOWN", len
);
135 void get_exc_mask_string(exception_mask_t m
, char *out_string
, size_t len
)
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
);
166 kern_return_t
print_task_exception_info(my_per_task_info_t
*taskinfo
)
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];
174 kr
= task_get_exception_ports(taskinfo
->task
, mask
, excinfo
.masks
, &excinfo
.count
, excinfo
.ports
, excinfo
.behaviors
, excinfo
.flavors
);
176 if (kr
!= KERN_SUCCESS
) {
177 fprintf(stderr
, "Failed task_get_exception_ports task: %d pid: %d\n", taskinfo
->task
, taskinfo
->pid
);
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
;
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
]);
199 kern_return_t
print_task_threads_special_ports(my_per_task_info_t
*taskinfo
)
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;
210 for (int i
= 0; i
< threadcount
; i
++) {
211 if (header_required
) {
212 printf("Threads Thread-ID DispatchQ Port Description.");
213 header_required
= FALSE
;
216 if (newline_required
) {
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
);
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
;
239 mach_port_deallocate(mach_task_self(), threadlist
[i
]);
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
;
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
];
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
)
267 kern_return_t retval
= KERN_FAILURE
;
268 boolean_t found
= FALSE
;
269 *out_taskinfo
= &NOT_FOUND_TASK_INFO
;
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
;
278 retval
= KERN_SUCCESS
;