]> git.saurik.com Git - apple/xnu.git/blame - osfmk/chud/i386/chud_thread_i386.c
xnu-3247.1.106.tar.gz
[apple/xnu.git] / osfmk / chud / i386 / chud_thread_i386.c
CommitLineData
0c530ab8 1/*
2d21ac55 2 * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
0c530ab8 3 *
2d21ac55
A
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
0c530ab8
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
0c530ab8
A
27 */
28
29#include <mach/mach_types.h>
30#include <mach/task.h>
31#include <mach/thread_act.h>
b0d623f7 32#include <machine/thread.h>
0c530ab8
A
33
34#include <kern/kern_types.h>
35#include <kern/processor.h>
36#include <kern/thread.h>
37
38#include <vm/vm_map.h>
39#include <vm/pmap.h>
40
41#include <chud/chud_xnu.h>
42#include <chud/chud_xnu_private.h>
43
0c530ab8
A
44#include <i386/proc_reg.h>
45#include <i386/mp_desc.h>
b0d623f7 46#include <i386/misc_protos.h>
0c530ab8 47
b0d623f7 48#if 0
0c530ab8 49#pragma mark **** thread state ****
b0d623f7 50#endif
0c530ab8
A
51
52__private_extern__ kern_return_t
0c530ab8 53chudxnu_thread_get_state(
2d21ac55
A
54 thread_t thread,
55 thread_flavor_t flavor,
56 thread_state_t tstate,
57 mach_msg_type_number_t *count,
58 boolean_t user_only)
0c530ab8
A
59{
60 if (user_only) {
61 /* We can't get user state for kernel threads */
62 if (thread->task == kernel_task)
63 return KERN_FAILURE;
64 /* this properly handles deciding whether or not the thread is 64 bit or not */
65 return machine_thread_get_state(thread, flavor, tstate, count);
66 } else {
67 // i386 machine_thread_get_kern_state() is different from the PPC version which returns
68 // the previous save area - user or kernel - rather than kernel or NULL if no kernel
69 // interrupt state available
2d21ac55 70
0c530ab8
A
71 // the real purpose of this branch is the following:
72 // the user doesn't care if the thread states are user or kernel, he
73 // just wants the thread state, so we need to determine the proper one
74 // to return, kernel or user, for the given thread.
75 if(thread == current_thread() && current_cpu_datap()->cpu_int_state) {
76 // the above are conditions where we possibly can read the kernel
77 // state. we still need to determine if this interrupt happened in
78 // kernel or user context
79 if(USER_STATE(thread) == current_cpu_datap()->cpu_int_state &&
2d21ac55 80 current_cpu_datap()->cpu_interrupt_level == 1) {
0c530ab8
A
81 // interrupt happened in user land
82 return machine_thread_get_state(thread, flavor, tstate, count);
83 } else {
84 // kernel interrupt.
85 return machine_thread_get_kern_state(thread, flavor, tstate, count);
86 }
87 } else {
88 // get the user-mode thread state
89 return machine_thread_get_state(thread, flavor, tstate, count);
90 }
91 }
92}
93
94__private_extern__ kern_return_t
95chudxnu_thread_set_state(
2d21ac55
A
96 thread_t thread,
97 thread_flavor_t flavor,
98 thread_state_t tstate,
99 mach_msg_type_number_t count,
100 boolean_t user_only)
0c530ab8
A
101{
102#pragma unused (user_only)
103 return machine_thread_set_state(thread, flavor, tstate, count);
104}
105
b0d623f7 106#if 0
0c530ab8 107#pragma mark **** task memory read/write ****
b0d623f7 108#endif
2d21ac55 109
0c530ab8
A
110__private_extern__ kern_return_t
111chudxnu_task_read(
2d21ac55
A
112 task_t task,
113 void *kernaddr,
114 uint64_t usraddr,
115 vm_size_t size)
0c530ab8
A
116{
117 kern_return_t ret = KERN_SUCCESS;
2d21ac55 118 boolean_t old_level;
0c530ab8 119
2d21ac55
A
120 if(ml_at_interrupt_context()) {
121 return KERN_FAILURE; // Can't look at tasks on interrupt stack
122 }
123
124 /*
125 * pmap layer requires interrupts to be on
126 */
127 old_level = ml_set_interrupts_enabled(TRUE);
128
129 if(current_task()==task) {
130
0c530ab8
A
131 if(copyin(usraddr, kernaddr, size)) {
132 ret = KERN_FAILURE;
133 }
134 } else {
135 vm_map_t map = get_task_map(task);
136 ret = vm_map_read_user(map, usraddr, kernaddr, size);
137 }
138
2d21ac55
A
139 ml_set_interrupts_enabled(old_level);
140
0c530ab8
A
141 return ret;
142}
2d21ac55 143
0c530ab8
A
144__private_extern__ kern_return_t
145chudxnu_task_write(
2d21ac55
A
146 task_t task,
147 uint64_t useraddr,
148 void *kernaddr,
149 vm_size_t size)
0c530ab8
A
150{
151 kern_return_t ret = KERN_SUCCESS;
2d21ac55
A
152 boolean_t old_level;
153
154 if(ml_at_interrupt_context()) {
155 return KERN_FAILURE; // can't poke into tasks on interrupt stack
156 }
157
158 /*
159 * pmap layer requires interrupts to be on
160 */
161 old_level = ml_set_interrupts_enabled(TRUE);
0c530ab8 162
2d21ac55
A
163 if(current_task()==task) {
164
0c530ab8
A
165 if(copyout(kernaddr, useraddr, size)) {
166 ret = KERN_FAILURE;
167 }
168 } else {
169 vm_map_t map = get_task_map(task);
170 ret = vm_map_write_user(map, kernaddr, useraddr, size);
171 }
2d21ac55
A
172
173 ml_set_interrupts_enabled(old_level);
174
0c530ab8
A
175 return ret;
176}
177
178__private_extern__ kern_return_t
179chudxnu_kern_read(void *dstaddr, vm_offset_t srcaddr, vm_size_t size)
180{
2d21ac55
A
181 return (ml_nofault_copy(srcaddr, (vm_offset_t) dstaddr, size) == size ?
182 KERN_SUCCESS: KERN_FAILURE);
0c530ab8
A
183}
184
185__private_extern__ kern_return_t
186chudxnu_kern_write(
2d21ac55
A
187 vm_offset_t dstaddr,
188 void *srcaddr,
189 vm_size_t size)
0c530ab8 190{
2d21ac55
A
191 return (ml_nofault_copy((vm_offset_t) srcaddr, dstaddr, size) == size ?
192 KERN_SUCCESS: KERN_FAILURE);
0c530ab8
A
193}
194
195#define VALID_STACK_ADDRESS(supervisor, addr, minKernAddr, maxKernAddr) (supervisor ? (addr>=minKernAddr && addr<=maxKernAddr) : TRUE)
196// don't try to read in the hole
197#define VALID_STACK_ADDRESS64(supervisor, addr, minKernAddr, maxKernAddr) \
b0d623f7
A
198(supervisor ? ((uint64_t)addr >= minKernAddr && (uint64_t)addr <= maxKernAddr) : \
199((uint64_t)addr != 0ULL && ((uint64_t)addr <= 0x00007FFFFFFFFFFFULL || (uint64_t)addr >= 0xFFFF800000000000ULL)))
0c530ab8
A
200
201typedef struct _cframe64_t {
202 uint64_t prevFP; // can't use a real pointer here until we're a 64 bit kernel
203 uint64_t caller;
204 uint64_t args[0];
205}cframe64_t;
206
207
208typedef struct _cframe_t {
b0d623f7 209 uint32_t prev; // this is really a user32-space pointer to the previous frame
0c530ab8
A
210 uint32_t caller;
211 uint32_t args[0];
212} cframe_t;
213
2d21ac55
A
214extern void * find_user_regs(thread_t);
215extern x86_saved_state32_t *find_kern_regs(thread_t);
216
217static kern_return_t do_backtrace32(
218 task_t task,
219 thread_t thread,
220 x86_saved_state32_t *regs,
221 uint64_t *frames,
222 mach_msg_type_number_t *start_idx,
223 mach_msg_type_number_t max_idx,
224 boolean_t supervisor)
225{
226 uint32_t tmpWord = 0UL;
227 uint64_t currPC = (uint64_t) regs->eip;
228 uint64_t currFP = (uint64_t) regs->ebp;
229 uint64_t prevPC = 0ULL;
230 uint64_t prevFP = 0ULL;
231 uint64_t kernStackMin = thread->kernel_stack;
b0d623f7 232 uint64_t kernStackMax = kernStackMin + kernel_stack_size;
2d21ac55
A
233 mach_msg_type_number_t ct = *start_idx;
234 kern_return_t kr = KERN_FAILURE;
235
236 if(ct >= max_idx)
237 return KERN_RESOURCE_SHORTAGE; // no frames traced
238
316670eb 239 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
2d21ac55
A
240
241 // build a backtrace of this 32 bit state.
242 while(VALID_STACK_ADDRESS(supervisor, currFP, kernStackMin, kernStackMax)) {
b0d623f7 243 cframe_t *fp = (cframe_t *) (uintptr_t) currFP;
2d21ac55
A
244
245 if(!currFP) {
246 currPC = 0;
247 break;
248 }
249
250 if(ct >= max_idx) {
251 *start_idx = ct;
252 return KERN_RESOURCE_SHORTAGE;
253 }
254
255 /* read our caller */
256 if(supervisor) {
257 kr = chudxnu_kern_read(&tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t));
258 } else {
259 kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t));
260 }
261
262 if(kr != KERN_SUCCESS) {
263 currPC = 0ULL;
264 break;
265 }
266
267 currPC = (uint64_t) tmpWord; // promote 32 bit address
268
269 /*
270 * retrive contents of the frame pointer and advance to the next stack
271 * frame if it's valid
272 */
273 prevFP = 0;
274 if(supervisor) {
275 kr = chudxnu_kern_read(&tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t));
276 } else {
277 kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t));
278 }
279 prevFP = (uint64_t) tmpWord; // promote 32 bit address
280
281 if(prevFP) {
316670eb 282 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
2d21ac55
A
283 prevPC = currPC;
284 }
285 if(prevFP < currFP) {
286 break;
287 } else {
288 currFP = prevFP;
289 }
290 }
291
292 *start_idx = ct;
293 return KERN_SUCCESS;
294}
295
296static kern_return_t do_backtrace64(
297 task_t task,
298 thread_t thread,
299 x86_saved_state64_t *regs,
300 uint64_t *frames,
301 mach_msg_type_number_t *start_idx,
302 mach_msg_type_number_t max_idx,
303 boolean_t supervisor)
304{
305 uint64_t currPC = regs->isf.rip;
306 uint64_t currFP = regs->rbp;
307 uint64_t prevPC = 0ULL;
308 uint64_t prevFP = 0ULL;
309 uint64_t kernStackMin = (uint64_t)thread->kernel_stack;
b0d623f7 310 uint64_t kernStackMax = (uint64_t)kernStackMin + kernel_stack_size;
2d21ac55
A
311 mach_msg_type_number_t ct = *start_idx;
312 kern_return_t kr = KERN_FAILURE;
313
314 if(*start_idx >= max_idx)
315 return KERN_RESOURCE_SHORTAGE; // no frames traced
316
316670eb 317 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
2d21ac55
A
318
319 // build a backtrace of this 32 bit state.
320 while(VALID_STACK_ADDRESS64(supervisor, currFP, kernStackMin, kernStackMax)) {
321 // this is the address where caller lives in the user thread
322 uint64_t caller = currFP + sizeof(uint64_t);
323
324 if(!currFP) {
325 currPC = 0;
326 break;
327 }
328
329 if(ct >= max_idx) {
330 *start_idx = ct;
331 return KERN_RESOURCE_SHORTAGE;
332 }
333
334 /* read our caller */
335 if(supervisor) {
b0d623f7 336 kr = chudxnu_kern_read(&currPC, (vm_offset_t)caller, sizeof(uint64_t));
2d21ac55
A
337 } else {
338 kr = chudxnu_task_read(task, &currPC, caller, sizeof(uint64_t));
339 }
340
341 if(kr != KERN_SUCCESS) {
342 currPC = 0ULL;
343 break;
344 }
345
346 /*
347 * retrive contents of the frame pointer and advance to the next stack
348 * frame if it's valid
349 */
350 prevFP = 0;
351 if(supervisor) {
b0d623f7 352 kr = chudxnu_kern_read(&prevFP, (vm_offset_t)currFP, sizeof(uint64_t));
2d21ac55
A
353 } else {
354 kr = chudxnu_task_read(task, &prevFP, currFP, sizeof(uint64_t));
355 }
356
357 if(VALID_STACK_ADDRESS64(supervisor, prevFP, kernStackMin, kernStackMax)) {
316670eb 358 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
2d21ac55
A
359 prevPC = currPC;
360 }
361 if(prevFP < currFP) {
362 break;
363 } else {
364 currFP = prevFP;
365 }
366 }
367
368 *start_idx = ct;
369 return KERN_SUCCESS;
370}
371
b0d623f7
A
372static kern_return_t do_kernel_backtrace(
373 thread_t thread,
374 struct x86_kernel_state *regs,
375 uint64_t *frames,
376 mach_msg_type_number_t *start_idx,
377 mach_msg_type_number_t max_idx)
378{
379 uint64_t kernStackMin = (uint64_t)thread->kernel_stack;
380 uint64_t kernStackMax = (uint64_t)kernStackMin + kernel_stack_size;
381 mach_msg_type_number_t ct = *start_idx;
382 kern_return_t kr = KERN_FAILURE;
383
384#if __LP64__
385 uint64_t currPC = 0ULL;
386 uint64_t currFP = 0ULL;
387 uint64_t prevPC = 0ULL;
388 uint64_t prevFP = 0ULL;
389 if(KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(regs->k_rip), sizeof(uint64_t))) {
390 return KERN_FAILURE;
391 }
392 if(KERN_SUCCESS != chudxnu_kern_read(&currFP, (vm_offset_t)&(regs->k_rbp), sizeof(uint64_t))) {
393 return KERN_FAILURE;
394 }
395#else
396 uint32_t currPC = 0U;
397 uint32_t currFP = 0U;
398 uint32_t prevPC = 0U;
399 uint32_t prevFP = 0U;
400 if(KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(regs->k_eip), sizeof(uint32_t))) {
401 return KERN_FAILURE;
402 }
403 if(KERN_SUCCESS != chudxnu_kern_read(&currFP, (vm_offset_t)&(regs->k_ebp), sizeof(uint32_t))) {
404 return KERN_FAILURE;
405 }
406#endif
407
408 if(*start_idx >= max_idx)
409 return KERN_RESOURCE_SHORTAGE; // no frames traced
410
411 if(!currPC) {
412 return KERN_FAILURE;
413 }
414
316670eb 415 frames[ct++] = chudxnu_vm_unslide((uint64_t)currPC, 1);
b0d623f7
A
416
417 // build a backtrace of this kernel state
418#if __LP64__
419 while(VALID_STACK_ADDRESS64(TRUE, currFP, kernStackMin, kernStackMax)) {
420 // this is the address where caller lives in the user thread
421 uint64_t caller = currFP + sizeof(uint64_t);
422#else
423 while(VALID_STACK_ADDRESS(TRUE, currFP, kernStackMin, kernStackMax)) {
424 uint32_t caller = (uint32_t)currFP + sizeof(uint32_t);
425#endif
426
427 if(!currFP || !currPC) {
428 currPC = 0;
429 break;
430 }
431
432 if(ct >= max_idx) {
433 *start_idx = ct;
434 return KERN_RESOURCE_SHORTAGE;
435 }
436
437 /* read our caller */
438 kr = chudxnu_kern_read(&currPC, (vm_offset_t)caller, sizeof(currPC));
439
440 if(kr != KERN_SUCCESS || !currPC) {
441 currPC = 0UL;
442 break;
443 }
444
445 /*
446 * retrive contents of the frame pointer and advance to the next stack
447 * frame if it's valid
448 */
449 prevFP = 0;
450 kr = chudxnu_kern_read(&prevFP, (vm_offset_t)currFP, sizeof(currPC));
451
452#if __LP64__
453 if(VALID_STACK_ADDRESS64(TRUE, prevFP, kernStackMin, kernStackMax)) {
454#else
455 if(VALID_STACK_ADDRESS(TRUE, prevFP, kernStackMin, kernStackMax)) {
456#endif
316670eb 457 frames[ct++] = chudxnu_vm_unslide((uint64_t)currPC, 1);
b0d623f7
A
458 prevPC = currPC;
459 }
460 if(prevFP <= currFP) {
461 break;
462 } else {
463 currFP = prevFP;
464 }
465 }
466
467 *start_idx = ct;
468 return KERN_SUCCESS;
469}
470
39236c6e
A
471static
472kern_return_t chudxnu_thread_get_callstack64_internal(
0c530ab8
A
473 thread_t thread,
474 uint64_t *callstack,
475 mach_msg_type_number_t *count,
39236c6e
A
476 boolean_t user_only,
477 boolean_t kern_only)
0c530ab8 478{
2d21ac55 479 kern_return_t kr = KERN_FAILURE;
0c530ab8 480 task_t task = thread->task;
b0d623f7 481 uint64_t currPC = 0ULL;
2d21ac55
A
482 boolean_t supervisor = FALSE;
483 mach_msg_type_number_t bufferIndex = 0;
484 mach_msg_type_number_t bufferMaxIndex = *count;
485 x86_saved_state_t *tagged_regs = NULL; // kernel register state
486 x86_saved_state64_t *regs64 = NULL;
487 x86_saved_state32_t *regs32 = NULL;
488 x86_saved_state32_t *u_regs32 = NULL;
489 x86_saved_state64_t *u_regs64 = NULL;
b0d623f7 490 struct x86_kernel_state *kregs = NULL;
2d21ac55
A
491
492 if(ml_at_interrupt_context()) {
493
494 if(user_only) {
495 /* can't backtrace user state on interrupt stack. */
0c530ab8
A
496 return KERN_FAILURE;
497 }
2d21ac55
A
498
499 /* backtracing at interrupt context? */
500 if(thread == current_thread() && current_cpu_datap()->cpu_int_state) {
501 /*
502 * Locate the registers for the interrupted thread, assuming it is
503 * current_thread().
504 */
505 tagged_regs = current_cpu_datap()->cpu_int_state;
0c530ab8 506
2d21ac55
A
507 if(is_saved_state64(tagged_regs)) {
508 /* 64 bit registers */
509 regs64 = saved_state64(tagged_regs);
510 supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U);
0c530ab8 511 } else {
2d21ac55
A
512 /* 32 bit registers */
513 regs32 = saved_state32(tagged_regs);
514 supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U);
0c530ab8 515 }
2d21ac55
A
516 }
517 }
0c530ab8 518
b0d623f7
A
519 if(!ml_at_interrupt_context() && kernel_task == task) {
520
521 if(!thread->kernel_stack) {
522 return KERN_FAILURE;
523 }
524
525 // Kernel thread not at interrupt context
526 kregs = (struct x86_kernel_state *)NULL;
527
528 // nofault read of the thread->kernel_stack pointer
529 if(KERN_SUCCESS != chudxnu_kern_read(&kregs, (vm_offset_t)&(thread->kernel_stack), sizeof(void *))) {
530 return KERN_FAILURE;
531 }
532
533 // Adjust to find the saved kernel state
534 kregs = STACK_IKS((vm_offset_t)(uintptr_t)kregs);
535
536 supervisor = TRUE;
537 } else if(!tagged_regs) {
2d21ac55
A
538 /*
539 * not at interrupt context, or tracing a different thread than
540 * current_thread() at interrupt context
541 */
542 tagged_regs = USER_STATE(thread);
543 if(is_saved_state64(tagged_regs)) {
544 /* 64 bit registers */
545 regs64 = saved_state64(tagged_regs);
b0d623f7 546 supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U);
2d21ac55
A
547 } else {
548 /* 32 bit registers */
549 regs32 = saved_state32(tagged_regs);
550 supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U);
0c530ab8 551 }
2d21ac55 552 }
0c530ab8 553
2d21ac55
A
554 *count = 0;
555
556 if(supervisor) {
557 // the caller only wants a user callstack.
0c530ab8 558 if(user_only) {
2d21ac55 559 // bail - we've only got kernel state
0c530ab8
A
560 return KERN_FAILURE;
561 }
2d21ac55
A
562 } else {
563 // regs32(64) is not in supervisor mode.
564 u_regs32 = regs32;
565 u_regs64 = regs64;
566 regs32 = NULL;
567 regs64 = NULL;
568 }
569
570 if (user_only) {
571 /* we only want to backtrace the user mode */
572 if(!(u_regs32 || u_regs64)) {
573 /* no user state to look at */
574 return KERN_FAILURE;
0c530ab8 575 }
2d21ac55 576 }
0c530ab8 577
2d21ac55
A
578 /*
579 * Order of preference for top of stack:
580 * 64 bit kernel state (not likely)
581 * 32 bit kernel state
582 * 64 bit user land state
583 * 32 bit user land state
584 */
585
b0d623f7
A
586 if(kregs) {
587 /*
588 * nofault read of the registers from the kernel stack (as they can
589 * disappear on the fly).
590 */
591
592#if __LP64__
593 if(KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(kregs->k_rip), sizeof(uint64_t))) {
594 return KERN_FAILURE;
595 }
596#else
597 uint32_t tmp;
598 if(KERN_SUCCESS != chudxnu_kern_read(&tmp, (vm_offset_t)&(kregs->k_eip), sizeof(uint32_t))) {
599 return KERN_FAILURE;
600 }
601 currPC = (uint64_t)tmp;
602#endif
603 } else if(regs64) {
2d21ac55
A
604 currPC = regs64->isf.rip;
605 } else if(regs32) {
606 currPC = (uint64_t) regs32->eip;
607 } else if(u_regs64) {
608 currPC = u_regs64->isf.rip;
609 } else if(u_regs32) {
610 currPC = (uint64_t) u_regs32->eip;
611 }
0c530ab8 612
2d21ac55
A
613 if(!currPC) {
614 /* no top of the stack, bail out */
615 return KERN_FAILURE;
616 }
0c530ab8 617
2d21ac55 618 bufferIndex = 0;
0c530ab8 619
2d21ac55
A
620 if(bufferMaxIndex < 1) {
621 *count = 0;
622 return KERN_RESOURCE_SHORTAGE;
623 }
624
625 /* backtrace kernel */
b0d623f7
A
626 if(kregs) {
627 addr64_t address = 0ULL;
628 size_t size = 0UL;
629
630 // do the backtrace
631 kr = do_kernel_backtrace(thread, kregs, callstack, &bufferIndex, bufferMaxIndex);
632
633 // and do a nofault read of (r|e)sp
634#if __LP64__
635 uint64_t rsp = 0ULL;
636 size = sizeof(uint64_t);
637
638 if(KERN_SUCCESS != chudxnu_kern_read(&address, (vm_offset_t)&(kregs->k_rsp), size)) {
639 address = 0ULL;
640 }
641#else
642 uint32_t rsp = 0ULL, tmp = 0ULL;
643 size = sizeof(uint32_t);
644
645 if(KERN_SUCCESS != chudxnu_kern_read(&tmp, (vm_offset_t)&(kregs->k_esp), size)) {
646 address = 0ULL;
647 } else {
648 address = (addr64_t)tmp;
649 }
650#endif
651
652 if(address && KERN_SUCCESS == chudxnu_kern_read(&rsp, (vm_offset_t)address, size) && bufferIndex < bufferMaxIndex) {
653 callstack[bufferIndex++] = (uint64_t)rsp;
654 }
655 } else if(regs64) {
2d21ac55
A
656 uint64_t rsp = 0ULL;
657
658 // backtrace the 64bit side.
3e170ce0
A
659 kr = do_backtrace64(task, thread, regs64, callstack, &bufferIndex,
660 bufferMaxIndex - 1, TRUE);
2d21ac55 661
b0d623f7 662 if(KERN_SUCCESS == chudxnu_kern_read(&rsp, (vm_offset_t) regs64->isf.rsp, sizeof(uint64_t)) &&
2d21ac55
A
663 bufferIndex < bufferMaxIndex) {
664 callstack[bufferIndex++] = rsp;
0c530ab8
A
665 }
666
2d21ac55
A
667 } else if(regs32) {
668 uint32_t esp = 0UL;
669
670 // backtrace the 32bit side.
3e170ce0
A
671 kr = do_backtrace32(task, thread, regs32, callstack, &bufferIndex,
672 bufferMaxIndex - 1, TRUE);
0c530ab8 673
b0d623f7 674 if(KERN_SUCCESS == chudxnu_kern_read(&esp, (vm_offset_t) regs32->uesp, sizeof(uint32_t)) &&
2d21ac55
A
675 bufferIndex < bufferMaxIndex) {
676 callstack[bufferIndex++] = (uint64_t) esp;
0c530ab8 677 }
39236c6e 678 } else if(u_regs64 && !kern_only) {
2d21ac55
A
679 /* backtrace user land */
680 uint64_t rsp = 0ULL;
681
3e170ce0
A
682 kr = do_backtrace64(task, thread, u_regs64, callstack, &bufferIndex,
683 bufferMaxIndex - 1, FALSE);
0c530ab8 684
2d21ac55
A
685 if(KERN_SUCCESS == chudxnu_task_read(task, &rsp, (addr64_t) u_regs64->isf.rsp, sizeof(uint64_t)) &&
686 bufferIndex < bufferMaxIndex) {
687 callstack[bufferIndex++] = rsp;
688 }
0c530ab8 689
39236c6e 690 } else if(u_regs32 && !kern_only) {
2d21ac55
A
691 uint32_t esp = 0UL;
692
3e170ce0
A
693 kr = do_backtrace32(task, thread, u_regs32, callstack, &bufferIndex,
694 bufferMaxIndex - 1, FALSE);
0c530ab8 695
2d21ac55
A
696 if(KERN_SUCCESS == chudxnu_task_read(task, &esp, (addr64_t) u_regs32->uesp, sizeof(uint32_t)) &&
697 bufferIndex < bufferMaxIndex) {
698 callstack[bufferIndex++] = (uint64_t) esp;
0c530ab8 699 }
2d21ac55 700 }
0c530ab8 701
0c530ab8 702 *count = bufferIndex;
2d21ac55 703 return kr;
0c530ab8
A
704}
705
39236c6e
A
706__private_extern__
707kern_return_t chudxnu_thread_get_callstack64_kperf(
708 thread_t thread,
709 uint64_t *callstack,
710 mach_msg_type_number_t *count,
711 boolean_t is_user)
712{
713 return chudxnu_thread_get_callstack64_internal(thread, callstack, count, is_user, !is_user);
714}
715
716__private_extern__
717kern_return_t chudxnu_thread_get_callstack64(
718 thread_t thread,
719 uint64_t *callstack,
720 mach_msg_type_number_t *count,
721 boolean_t user_only)
722{
723 return chudxnu_thread_get_callstack64_internal(thread, callstack, count, user_only, 0);
724}
725