2 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* Collect kernel callstacks */
31 #include <mach/mach_types.h>
32 #include <kern/thread.h>
33 #include <kern/backtrace.h>
34 #include <vm/vm_map.h>
35 #include <kperf/buffer.h>
36 #include <kperf/context.h>
37 #include <kperf/callstack.h>
38 #include <kperf/ast.h>
39 #include <sys/errno.h>
41 #if defined(__arm__) || defined(__arm64__)
42 #include <arm/cpu_data.h>
43 #include <arm/cpu_data_internal.h>
47 callstack_fixup_user(struct callstack
*cs
, thread_t thread
)
49 uint64_t fixup_val
= 0;
50 assert(cs
->nframes
< MAX_CALLSTACK_FRAMES
);
52 #if defined(__x86_64__)
55 x86_saved_state_t
*state
;
57 state
= get_user_regs(thread
);
62 user_64
= is_saved_state64(state
);
64 sp_user
= saved_state64(state
)->isf
.rsp
;
66 sp_user
= saved_state32(state
)->uesp
;
69 if (thread
== current_thread()) {
70 (void)copyin(sp_user
, (char *)&fixup_val
,
71 user_64
? sizeof(uint64_t) : sizeof(uint32_t));
73 (void)vm_map_read_user(get_task_map(get_threadtask(thread
)), sp_user
,
74 &fixup_val
, user_64
? sizeof(uint64_t) : sizeof(uint32_t));
77 #elif defined(__arm64__) || defined(__arm__)
79 struct arm_saved_state
*state
= get_user_regs(thread
);
84 /* encode thumb mode into low bit of PC */
85 if (get_saved_state_cpsr(state
) & PSR_TF
) {
86 cs
->frames
[0] |= 1ULL;
89 fixup_val
= get_saved_state_lr(state
);
92 #error "callstack_fixup_user: unsupported architecture"
96 cs
->frames
[cs
->nframes
++] = fixup_val
;
99 #if defined(__x86_64__)
101 __attribute__((used
))
103 interrupted_kernel_sp_value(uintptr_t *sp_val
)
105 x86_saved_state_t
*state
;
109 uintptr_t top
, bottom
;
111 state
= current_cpu_datap()->cpu_int_state
;
116 state_64
= is_saved_state64(state
);
119 cs
= saved_state64(state
)->isf
.cs
;
121 cs
= saved_state32(state
)->cs
;
123 /* return early if interrupted a thread in user space */
124 if ((cs
& SEL_PL
) == SEL_PL_U
) {
129 sp
= saved_state64(state
)->isf
.rsp
;
131 sp
= saved_state32(state
)->uesp
;
134 /* make sure the stack pointer is pointing somewhere in this stack */
135 bottom
= current_thread()->kernel_stack
;
136 top
= bottom
+ kernel_stack_size
;
137 if (sp
>= bottom
&& sp
< top
) {
141 *sp_val
= *(uintptr_t *)sp
;
145 #elif defined(__arm64__)
147 __attribute__((used
))
149 interrupted_kernel_lr(uintptr_t *lr
)
151 struct arm_saved_state
*state
;
153 state
= getCpuDatap()->cpu_int_state
;
155 /* return early if interrupted a thread in user space */
156 if (PSR64_IS_USER(get_saved_state_cpsr(state
))) {
160 *lr
= get_saved_state_lr(state
);
164 #elif defined(__arm__)
166 __attribute__((used
))
168 interrupted_kernel_lr(uintptr_t *lr
)
170 struct arm_saved_state
*state
;
172 state
= getCpuDatap()->cpu_int_state
;
174 /* return early if interrupted a thread in user space */
175 if (PSR_IS_USER(get_saved_state_cpsr(state
))) {
179 *lr
= get_saved_state_lr(state
);
183 #else /* defined(__arm__) */
184 #error "interrupted_kernel_{sp,lr}: unsupported architecture"
185 #endif /* !defined(__arm__) */
189 callstack_fixup_interrupted(struct callstack
*cs
)
191 uintptr_t fixup_val
= 0;
192 assert(cs
->nframes
< MAX_CALLSTACK_FRAMES
);
195 * Only provide arbitrary data on development or debug kernels.
197 #if DEVELOPMENT || DEBUG
198 #if defined(__x86_64__)
199 (void)interrupted_kernel_sp_value(&fixup_val
);
200 #elif defined(__arm64__) || defined(__arm__)
201 (void)interrupted_kernel_lr(&fixup_val
);
202 #endif /* defined(__x86_64__) */
203 #endif /* DEVELOPMENT || DEBUG */
205 assert(cs
->flags
& CALLSTACK_KERNEL
);
206 cs
->frames
[cs
->nframes
++] = fixup_val
;
210 kperf_continuation_sample(struct callstack
*cs
, struct kperf_context
*context
)
215 assert(context
!= NULL
);
217 thread
= context
->cur_thread
;
218 assert(thread
!= NULL
);
219 assert(thread
->continuation
!= NULL
);
221 cs
->flags
= CALLSTACK_CONTINUATION
| CALLSTACK_VALID
| CALLSTACK_KERNEL
;
223 cs
->flags
|= CALLSTACK_64BIT
;
227 cs
->frames
[0] = VM_KERNEL_UNSLIDE(thread
->continuation
);
231 kperf_backtrace_sample(struct callstack
*cs
, struct kperf_context
*context
)
234 assert(context
!= NULL
);
235 assert(context
->cur_thread
== current_thread());
237 cs
->flags
= CALLSTACK_KERNEL
| CALLSTACK_KERNEL_WORDS
;
239 cs
->flags
|= CALLSTACK_64BIT
;
242 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_START
, 1);
244 cs
->nframes
= backtrace_frame((uintptr_t *)&(cs
->frames
), cs
->nframes
- 1,
245 context
->starting_fp
);
246 if (cs
->nframes
> 0) {
247 cs
->flags
|= CALLSTACK_VALID
;
249 * Fake the value pointed to by the stack pointer or the link
250 * register for symbolicators.
252 cs
->frames
[cs
->nframes
+ 1] = 0;
256 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_END
, cs
->nframes
);
259 kern_return_t
chudxnu_thread_get_callstack64_kperf(thread_t thread
,
260 uint64_t *callStack
, mach_msg_type_number_t
*count
,
261 boolean_t user_only
);
264 kperf_kcallstack_sample(struct callstack
*cs
, struct kperf_context
*context
)
269 assert(context
!= NULL
);
270 assert(cs
->nframes
<= MAX_CALLSTACK_FRAMES
);
272 thread
= context
->cur_thread
;
273 assert(thread
!= NULL
);
275 BUF_INFO(PERF_CS_KSAMPLE
| DBG_FUNC_START
, (uintptr_t)thread_tid(thread
),
278 cs
->flags
= CALLSTACK_KERNEL
;
281 cs
->flags
|= CALLSTACK_64BIT
;
284 if (ml_at_interrupt_context()) {
285 assert(thread
== current_thread());
286 cs
->flags
|= CALLSTACK_KERNEL_WORDS
;
287 cs
->nframes
= backtrace_interrupted((uintptr_t *)cs
->frames
,
289 if (cs
->nframes
!= 0) {
290 callstack_fixup_interrupted(cs
);
294 * Rely on legacy CHUD backtracer to backtrace kernel stacks on
298 kr
= chudxnu_thread_get_callstack64_kperf(thread
, cs
->frames
,
299 &cs
->nframes
, FALSE
);
300 if (kr
== KERN_SUCCESS
) {
301 cs
->flags
|= CALLSTACK_VALID
;
302 } else if (kr
== KERN_RESOURCE_SHORTAGE
) {
303 cs
->flags
|= CALLSTACK_VALID
;
304 cs
->flags
|= CALLSTACK_TRUNCATED
;
310 if (cs
->nframes
== 0) {
311 BUF_INFO(PERF_CS_ERROR
, ERR_GETSTACK
);
314 BUF_INFO(PERF_CS_KSAMPLE
| DBG_FUNC_END
, (uintptr_t)thread_tid(thread
), cs
->flags
, cs
->nframes
);
318 kperf_ucallstack_sample(struct callstack
*cs
, struct kperf_context
*context
)
321 bool user_64
= false;
325 assert(context
!= NULL
);
326 assert(cs
->nframes
<= MAX_CALLSTACK_FRAMES
);
327 assert(ml_get_interrupts_enabled() == TRUE
);
329 thread
= context
->cur_thread
;
330 assert(thread
!= NULL
);
332 BUF_INFO(PERF_CS_USAMPLE
| DBG_FUNC_START
, (uintptr_t)thread_tid(thread
),
337 err
= backtrace_thread_user(thread
, (uintptr_t *)cs
->frames
,
338 cs
->nframes
- 1, &cs
->nframes
, &user_64
);
339 cs
->flags
|= CALLSTACK_KERNEL_WORDS
;
341 cs
->flags
|= CALLSTACK_64BIT
;
344 if (!err
|| err
== EFAULT
) {
345 callstack_fixup_user(cs
, thread
);
346 cs
->flags
|= CALLSTACK_VALID
;
349 BUF_INFO(PERF_CS_ERROR
, ERR_GETSTACK
, err
);
352 BUF_INFO(PERF_CS_USAMPLE
| DBG_FUNC_END
, (uintptr_t)thread_tid(thread
),
353 cs
->flags
, cs
->nframes
);
356 static inline uintptr_t
357 scrub_word(uintptr_t *bt
, int n_frames
, int frame
, bool kern
)
359 if (frame
< n_frames
) {
361 return VM_KERNEL_UNSLIDE(bt
[frame
]);
370 static inline uintptr_t
371 scrub_frame(uint64_t *bt
, int n_frames
, int frame
)
373 if (frame
< n_frames
) {
374 return (uintptr_t)(bt
[frame
]);
381 callstack_log(struct callstack
*cs
, uint32_t hcode
, uint32_t dcode
)
383 BUF_VERB(PERF_CS_LOG
| DBG_FUNC_START
, cs
->flags
, cs
->nframes
);
385 /* framing information for the stack */
386 BUF_DATA(hcode
, cs
->flags
, cs
->nframes
);
388 /* how many batches of 4 */
389 unsigned int nframes
= cs
->nframes
;
390 unsigned int n
= nframes
/ 4;
391 unsigned int ovf
= nframes
% 4;
396 bool kern
= cs
->flags
& CALLSTACK_KERNEL
;
398 if (cs
->flags
& CALLSTACK_KERNEL_WORDS
) {
399 uintptr_t *frames
= (uintptr_t *)cs
->frames
;
400 for (unsigned int i
= 0; i
< n
; i
++) {
401 unsigned int j
= i
* 4;
403 scrub_word(frames
, nframes
, j
+ 0, kern
),
404 scrub_word(frames
, nframes
, j
+ 1, kern
),
405 scrub_word(frames
, nframes
, j
+ 2, kern
),
406 scrub_word(frames
, nframes
, j
+ 3, kern
));
409 for (unsigned int i
= 0; i
< n
; i
++) {
410 uint64_t *frames
= cs
->frames
;
411 unsigned int j
= i
* 4;
413 scrub_frame(frames
, nframes
, j
+ 0),
414 scrub_frame(frames
, nframes
, j
+ 1),
415 scrub_frame(frames
, nframes
, j
+ 2),
416 scrub_frame(frames
, nframes
, j
+ 3));
420 BUF_VERB(PERF_CS_LOG
| DBG_FUNC_END
, cs
->flags
, cs
->nframes
);
424 kperf_kcallstack_log( struct callstack
*cs
)
426 callstack_log(cs
, PERF_CS_KHDR
, PERF_CS_KDATA
);
430 kperf_ucallstack_log( struct callstack
*cs
)
432 callstack_log(cs
, PERF_CS_UHDR
, PERF_CS_UDATA
);
436 kperf_ucallstack_pend(struct kperf_context
* context
, uint32_t depth
)
438 int did_pend
= kperf_ast_pend(context
->cur_thread
, T_KPERF_AST_CALLSTACK
);
439 kperf_ast_set_callstack_depth(context
->cur_thread
, depth
);
445 chudxnu_kern_read(void *dstaddr
, vm_offset_t srcaddr
, vm_size_t size
)
447 return ((ml_nofault_copy(srcaddr
, (vm_offset_t
)dstaddr
, size
) == size
) ?
448 KERN_SUCCESS
: KERN_FAILURE
);
458 //ppc version ported to arm
459 kern_return_t ret
= KERN_SUCCESS
;
461 if (ml_at_interrupt_context()) {
462 return KERN_FAILURE
; // can't look at tasks on interrupt stack
465 if (current_task() == task
) {
466 thread_t cur_thr
= current_thread();
467 vm_offset_t recover_handler
= cur_thr
->recover
;
469 if (copyin(usraddr
, kernaddr
, size
)) {
472 cur_thr
->recover
= recover_handler
;
474 vm_map_t map
= get_task_map(task
);
475 ret
= vm_map_read_user(map
, usraddr
, kernaddr
, size
);
481 static inline uint64_t
482 chudxnu_vm_unslide( uint64_t ptr
, int kaddr
)
487 return VM_KERNEL_UNSLIDE(ptr
);
491 #define ARM_SUPERVISOR_MODE(cpsr) ((((cpsr) & PSR_MODE_MASK) != PSR_USER_MODE) ? TRUE : FALSE)
492 #define CS_FLAG_EXTRASP 1 // capture extra sp register
494 chudxnu_thread_get_callstack64_internal(
497 mach_msg_type_number_t
*count
,
503 uint64_t currPC
=0ULL, currLR
=0ULL, currSP
=0ULL;
504 uint64_t prevPC
= 0ULL;
505 uint32_t kernStackMin
= thread
->kernel_stack
;
506 uint32_t kernStackMax
= kernStackMin
+ kernel_stack_size
;
507 uint64_t *buffer
= callStack
;
510 int bufferMaxIndex
= 0;
511 boolean_t supervisor
= FALSE
;
512 struct arm_saved_state
*state
= NULL
;
513 uint32_t *fp
=NULL
, *nextFramePointer
=NULL
, *topfp
=NULL
;
516 task
= get_threadtask(thread
);
518 bufferMaxIndex
= *count
;
521 state
= find_user_regs(thread
);
523 state
= find_kern_regs(thread
);
530 /* make sure it is safe to dereference before you do it */
531 supervisor
= ARM_SUPERVISOR_MODE(state
->cpsr
);
533 /* can't take a kernel callstack if we've got a user frame */
534 if( !user_only
&& !supervisor
)
538 * Reserve space for saving LR (and sometimes SP) at the end of the
541 if (flags
& CS_FLAG_EXTRASP
) {
547 if (bufferMaxIndex
< 2) {
549 return KERN_RESOURCE_SHORTAGE
;
552 currPC
= (uint64_t)state
->pc
; /* r15 */
553 if (state
->cpsr
& PSR_TF
)
554 currPC
|= 1ULL; /* encode thumb mode into low bit of PC */
556 currLR
= (uint64_t)state
->lr
; /* r14 */
557 currSP
= (uint64_t)state
->sp
; /* r13 */
559 fp
= (uint32_t *)state
->r
[7]; /* frame pointer */
562 bufferIndex
= 0; // start with a stack of size zero
563 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currPC
, supervisor
); // save PC in position 0.
565 // Now, fill buffer with stack backtraces.
566 while (bufferIndex
< bufferMaxIndex
) {
569 * Below the frame pointer, the following values are saved:
574 * Note that we read the pc even for the first stack frame
575 * (which, in theory, is always empty because the callee fills
576 * it in just before it lowers the stack. However, if we
577 * catch the program in between filling in the return address
578 * and lowering the stack, we want to still have a valid
579 * backtrace. FixupStack correctly disregards this value if
583 if((uint32_t)fp
== 0 || ((uint32_t)fp
& 0x3) != 0) {
584 /* frame pointer is invalid - stop backtracing */
590 if (((uint32_t)fp
> kernStackMax
) ||
591 ((uint32_t)fp
< kernStackMin
)) {
594 kr
= chudxnu_kern_read(&frame
,
596 (vm_size_t
)sizeof(frame
));
597 if (kr
== KERN_SUCCESS
) {
598 pc
= (uint64_t)frame
[1];
599 nextFramePointer
= (uint32_t *) (frame
[0]);
602 nextFramePointer
= 0ULL;
607 kr
= chudxnu_task_read(task
,
609 (((uint64_t)(uint32_t)fp
) & 0x00000000FFFFFFFFULL
),
611 if (kr
== KERN_SUCCESS
) {
612 pc
= (uint64_t) frame
[1];
613 nextFramePointer
= (uint32_t *) (frame
[0]);
616 nextFramePointer
= 0ULL;
621 if (kr
!= KERN_SUCCESS
) {
626 if (nextFramePointer
) {
627 buffer
[bufferIndex
++] = chudxnu_vm_unslide(pc
, supervisor
);
631 if (nextFramePointer
< fp
)
634 fp
= nextFramePointer
;
637 if (bufferIndex
>= bufferMaxIndex
) {
638 bufferIndex
= bufferMaxIndex
;
639 kr
= KERN_RESOURCE_SHORTAGE
;
644 // Save link register and R13 (sp) at bottom of stack (used for later fixup).
645 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currLR
, supervisor
);
646 if( flags
& CS_FLAG_EXTRASP
)
647 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currSP
, supervisor
);
649 *count
= bufferIndex
;
656 chudxnu_thread_get_callstack64_kperf(
659 mach_msg_type_number_t
*count
,
662 return chudxnu_thread_get_callstack64_internal( thread
, callStack
, count
, user_only
, 0 );
667 // chudxnu_thread_get_callstack gathers a raw callstack along with any information needed to
668 // fix it up later (in case we stopped program as it was saving values into prev stack frame, etc.)
669 // after sampling has finished.
671 // For an N-entry callstack:
674 // [1..N-3] stack frames (including current one)
675 // [N-2] current LR (return value if we're in a leaf function)
676 // [N-1] current r0 (in case we've saved LR in r0) (optional)
679 #define ARM_SUPERVISOR_MODE(cpsr) ((((cpsr) & PSR_MODE_MASK) != PSR_USER_MODE) ? TRUE : FALSE)
681 #define CS_FLAG_EXTRASP 1 // capture extra sp register
684 chudxnu_thread_get_callstack64_internal(
687 mach_msg_type_number_t
*count
,
691 kern_return_t kr
= KERN_SUCCESS
;
693 uint64_t currPC
=0ULL, currLR
=0ULL, currSP
=0ULL;
694 uint64_t prevPC
= 0ULL;
695 uint64_t kernStackMin
= thread
->kernel_stack
;
696 uint64_t kernStackMax
= kernStackMin
+ kernel_stack_size
;
697 uint64_t *buffer
= callStack
;
699 int bufferMaxIndex
= 0;
700 boolean_t kernel
= FALSE
;
701 struct arm_saved_state
*sstate
= NULL
;
704 task
= get_threadtask(thread
);
705 bufferMaxIndex
= *count
;
708 sstate
= find_user_regs(thread
);
710 sstate
= find_kern_regs(thread
);
717 if (is_saved_state64(sstate
)) {
718 struct arm_saved_state64
*state
= NULL
;
719 uint64_t *fp
=NULL
, *nextFramePointer
=NULL
, *topfp
=NULL
;
722 state
= saved_state64(sstate
);
724 /* make sure it is safe to dereference before you do it */
725 kernel
= PSR64_IS_KERNEL(state
->cpsr
);
727 /* can't take a kernel callstack if we've got a user frame */
728 if( !user_only
&& !kernel
)
732 * Reserve space for saving LR (and sometimes SP) at the end of the
735 if (flags
& CS_FLAG_EXTRASP
) {
741 if (bufferMaxIndex
< 2) {
743 return KERN_RESOURCE_SHORTAGE
;
750 fp
= (uint64_t *)state
->fp
; /* frame pointer */
753 bufferIndex
= 0; // start with a stack of size zero
754 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currPC
, kernel
); // save PC in position 0.
756 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_START
, kernel
, 0);
758 // Now, fill buffer with stack backtraces.
759 while (bufferIndex
< bufferMaxIndex
) {
762 * Below the frame pointer, the following values are saved:
767 * Note that we read the pc even for the first stack frame
768 * (which, in theory, is always empty because the callee fills
769 * it in just before it lowers the stack. However, if we
770 * catch the program in between filling in the return address
771 * and lowering the stack, we want to still have a valid
772 * backtrace. FixupStack correctly disregards this value if
776 if((uint64_t)fp
== 0 || ((uint64_t)fp
& 0x3) != 0) {
777 /* frame pointer is invalid - stop backtracing */
783 if (((uint64_t)fp
> kernStackMax
) ||
784 ((uint64_t)fp
< kernStackMin
)) {
787 kr
= chudxnu_kern_read(&frame
,
789 (vm_size_t
)sizeof(frame
));
790 if (kr
== KERN_SUCCESS
) {
792 nextFramePointer
= (uint64_t *)frame
[0];
795 nextFramePointer
= 0ULL;
800 kr
= chudxnu_task_read(task
,
803 (vm_size_t
)sizeof(frame
));
804 if (kr
== KERN_SUCCESS
) {
806 nextFramePointer
= (uint64_t *)(frame
[0]);
809 nextFramePointer
= 0ULL;
814 if (kr
!= KERN_SUCCESS
) {
819 if (nextFramePointer
) {
820 buffer
[bufferIndex
++] = chudxnu_vm_unslide(pc
, kernel
);
824 if (nextFramePointer
< fp
)
827 fp
= nextFramePointer
;
830 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_END
, bufferIndex
);
832 if (bufferIndex
>= bufferMaxIndex
) {
833 bufferIndex
= bufferMaxIndex
;
834 kr
= KERN_RESOURCE_SHORTAGE
;
839 // Save link register and SP at bottom of stack (used for later fixup).
840 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currLR
, kernel
);
841 if( flags
& CS_FLAG_EXTRASP
)
842 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currSP
, kernel
);
844 struct arm_saved_state32
*state
= NULL
;
845 uint32_t *fp
=NULL
, *nextFramePointer
=NULL
, *topfp
=NULL
;
847 /* 64-bit kernel stacks, 32-bit user stacks */
851 state
= saved_state32(sstate
);
853 /* make sure it is safe to dereference before you do it */
854 kernel
= ARM_SUPERVISOR_MODE(state
->cpsr
);
856 /* can't take a kernel callstack if we've got a user frame */
857 if( !user_only
&& !kernel
)
861 * Reserve space for saving LR (and sometimes SP) at the end of the
864 if (flags
& CS_FLAG_EXTRASP
) {
870 if (bufferMaxIndex
< 2) {
872 return KERN_RESOURCE_SHORTAGE
;
875 currPC
= (uint64_t)state
->pc
; /* r15 */
876 if (state
->cpsr
& PSR_TF
)
877 currPC
|= 1ULL; /* encode thumb mode into low bit of PC */
879 currLR
= (uint64_t)state
->lr
; /* r14 */
880 currSP
= (uint64_t)state
->sp
; /* r13 */
882 fp
= (uint32_t *)(uintptr_t)state
->r
[7]; /* frame pointer */
885 bufferIndex
= 0; // start with a stack of size zero
886 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currPC
, kernel
); // save PC in position 0.
888 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_START
, kernel
, 1);
890 // Now, fill buffer with stack backtraces.
891 while (bufferIndex
< bufferMaxIndex
) {
894 * Below the frame pointer, the following values are saved:
899 * Note that we read the pc even for the first stack frame
900 * (which, in theory, is always empty because the callee fills
901 * it in just before it lowers the stack. However, if we
902 * catch the program in between filling in the return address
903 * and lowering the stack, we want to still have a valid
904 * backtrace. FixupStack correctly disregards this value if
908 if((uint32_t)fp
== 0 || ((uint32_t)fp
& 0x3) != 0) {
909 /* frame pointer is invalid - stop backtracing */
915 if (((uint32_t)fp
> kernStackMax
) ||
916 ((uint32_t)fp
< kernStackMin
)) {
919 kr
= chudxnu_kern_read(&frame
,
921 (vm_size_t
)sizeof(frame
));
922 if (kr
== KERN_SUCCESS
) {
923 pc
= (uint64_t)frame
[1];
924 nextFramePointer
= (uint32_t *) (frame
[0]);
927 nextFramePointer
= 0ULL;
932 kr
= chudxnu_task_read(task
,
934 (((uint64_t)(uint32_t)fp
) & 0x00000000FFFFFFFFULL
),
936 if (kr
== KERN_SUCCESS
) {
937 pc
= (uint64_t)frame32
[1];
938 nextFramePointer
= (uint32_t *)(uintptr_t)(frame32
[0]);
941 nextFramePointer
= 0ULL;
946 if (kr
!= KERN_SUCCESS
) {
951 if (nextFramePointer
) {
952 buffer
[bufferIndex
++] = chudxnu_vm_unslide(pc
, kernel
);
956 if (nextFramePointer
< fp
)
959 fp
= nextFramePointer
;
962 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_END
, bufferIndex
);
964 /* clamp callstack size to max */
965 if (bufferIndex
>= bufferMaxIndex
) {
966 bufferIndex
= bufferMaxIndex
;
967 kr
= KERN_RESOURCE_SHORTAGE
;
969 /* ignore all other failures */
973 // Save link register and R13 (sp) at bottom of stack (used for later fixup).
974 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currLR
, kernel
);
975 if( flags
& CS_FLAG_EXTRASP
)
976 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currSP
, kernel
);
979 *count
= bufferIndex
;
984 chudxnu_thread_get_callstack64_kperf(
987 mach_msg_type_number_t
*count
,
990 return chudxnu_thread_get_callstack64_internal( thread
, callStack
, count
, user_only
, 0 );
994 #define VALID_STACK_ADDRESS(supervisor, addr, minKernAddr, maxKernAddr) (supervisor ? (addr>=minKernAddr && addr<=maxKernAddr) : TRUE)
995 // don't try to read in the hole
996 #define VALID_STACK_ADDRESS64(supervisor, addr, minKernAddr, maxKernAddr) \
997 (supervisor ? ((uint64_t)addr >= minKernAddr && (uint64_t)addr <= maxKernAddr) : \
998 ((uint64_t)addr != 0ULL && ((uint64_t)addr <= 0x00007FFFFFFFFFFFULL || (uint64_t)addr >= 0xFFFF800000000000ULL)))
1000 typedef struct _cframe64_t
{
1001 uint64_t prevFP
; // can't use a real pointer here until we're a 64 bit kernel
1007 typedef struct _cframe_t
{
1008 uint32_t prev
; // this is really a user32-space pointer to the previous frame
1013 extern void * find_user_regs(thread_t
);
1014 extern x86_saved_state32_t
*find_kern_regs(thread_t
);
1016 static kern_return_t
do_kernel_backtrace(
1018 struct x86_kernel_state
*regs
,
1020 mach_msg_type_number_t
*start_idx
,
1021 mach_msg_type_number_t max_idx
)
1023 uint64_t kernStackMin
= (uint64_t)thread
->kernel_stack
;
1024 uint64_t kernStackMax
= (uint64_t)kernStackMin
+ kernel_stack_size
;
1025 mach_msg_type_number_t ct
= *start_idx
;
1026 kern_return_t kr
= KERN_FAILURE
;
1029 uint64_t currPC
= 0ULL;
1030 uint64_t currFP
= 0ULL;
1031 uint64_t prevPC
= 0ULL;
1032 uint64_t prevFP
= 0ULL;
1033 if(KERN_SUCCESS
!= chudxnu_kern_read(&currPC
, (vm_offset_t
)&(regs
->k_rip
), sizeof(uint64_t))) {
1034 return KERN_FAILURE
;
1036 if(KERN_SUCCESS
!= chudxnu_kern_read(&currFP
, (vm_offset_t
)&(regs
->k_rbp
), sizeof(uint64_t))) {
1037 return KERN_FAILURE
;
1040 uint32_t currPC
= 0U;
1041 uint32_t currFP
= 0U;
1042 uint32_t prevPC
= 0U;
1043 uint32_t prevFP
= 0U;
1044 if(KERN_SUCCESS
!= chudxnu_kern_read(&currPC
, (vm_offset_t
)&(regs
->k_eip
), sizeof(uint32_t))) {
1045 return KERN_FAILURE
;
1047 if(KERN_SUCCESS
!= chudxnu_kern_read(&currFP
, (vm_offset_t
)&(regs
->k_ebp
), sizeof(uint32_t))) {
1048 return KERN_FAILURE
;
1052 if(*start_idx
>= max_idx
)
1053 return KERN_RESOURCE_SHORTAGE
; // no frames traced
1056 return KERN_FAILURE
;
1059 frames
[ct
++] = chudxnu_vm_unslide((uint64_t)currPC
, 1);
1061 // build a backtrace of this kernel state
1063 while(VALID_STACK_ADDRESS64(TRUE
, currFP
, kernStackMin
, kernStackMax
)) {
1064 // this is the address where caller lives in the user thread
1065 uint64_t caller
= currFP
+ sizeof(uint64_t);
1067 while(VALID_STACK_ADDRESS(TRUE
, currFP
, kernStackMin
, kernStackMax
)) {
1068 uint32_t caller
= (uint32_t)currFP
+ sizeof(uint32_t);
1071 if(!currFP
|| !currPC
) {
1078 return KERN_RESOURCE_SHORTAGE
;
1081 /* read our caller */
1082 kr
= chudxnu_kern_read(&currPC
, (vm_offset_t
)caller
, sizeof(currPC
));
1084 if(kr
!= KERN_SUCCESS
|| !currPC
) {
1090 * retrive contents of the frame pointer and advance to the next stack
1091 * frame if it's valid
1094 kr
= chudxnu_kern_read(&prevFP
, (vm_offset_t
)currFP
, sizeof(currPC
));
1097 if(VALID_STACK_ADDRESS64(TRUE
, prevFP
, kernStackMin
, kernStackMax
)) {
1099 if(VALID_STACK_ADDRESS(TRUE
, prevFP
, kernStackMin
, kernStackMax
)) {
1101 frames
[ct
++] = chudxnu_vm_unslide((uint64_t)currPC
, 1);
1104 if(prevFP
<= currFP
) {
1112 return KERN_SUCCESS
;
1117 static kern_return_t
do_backtrace32(
1120 x86_saved_state32_t
*regs
,
1122 mach_msg_type_number_t
*start_idx
,
1123 mach_msg_type_number_t max_idx
,
1124 boolean_t supervisor
)
1126 uint32_t tmpWord
= 0UL;
1127 uint64_t currPC
= (uint64_t) regs
->eip
;
1128 uint64_t currFP
= (uint64_t) regs
->ebp
;
1129 uint64_t prevPC
= 0ULL;
1130 uint64_t prevFP
= 0ULL;
1131 uint64_t kernStackMin
= thread
->kernel_stack
;
1132 uint64_t kernStackMax
= kernStackMin
+ kernel_stack_size
;
1133 mach_msg_type_number_t ct
= *start_idx
;
1134 kern_return_t kr
= KERN_FAILURE
;
1137 return KERN_RESOURCE_SHORTAGE
; // no frames traced
1139 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1141 // build a backtrace of this 32 bit state.
1142 while(VALID_STACK_ADDRESS(supervisor
, currFP
, kernStackMin
, kernStackMax
)) {
1143 cframe_t
*fp
= (cframe_t
*) (uintptr_t) currFP
;
1152 return KERN_RESOURCE_SHORTAGE
;
1155 /* read our caller */
1157 kr
= chudxnu_kern_read(&tmpWord
, (vm_offset_t
) &fp
->caller
, sizeof(uint32_t));
1159 kr
= chudxnu_task_read(task
, &tmpWord
, (vm_offset_t
) &fp
->caller
, sizeof(uint32_t));
1162 if(kr
!= KERN_SUCCESS
) {
1167 currPC
= (uint64_t) tmpWord
; // promote 32 bit address
1170 * retrive contents of the frame pointer and advance to the next stack
1171 * frame if it's valid
1175 kr
= chudxnu_kern_read(&tmpWord
, (vm_offset_t
)&fp
->prev
, sizeof(uint32_t));
1177 kr
= chudxnu_task_read(task
, &tmpWord
, (vm_offset_t
)&fp
->prev
, sizeof(uint32_t));
1179 prevFP
= (uint64_t) tmpWord
; // promote 32 bit address
1182 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1185 if(prevFP
< currFP
) {
1193 return KERN_SUCCESS
;
1196 static kern_return_t
do_backtrace64(
1199 x86_saved_state64_t
*regs
,
1201 mach_msg_type_number_t
*start_idx
,
1202 mach_msg_type_number_t max_idx
,
1203 boolean_t supervisor
)
1205 uint64_t currPC
= regs
->isf
.rip
;
1206 uint64_t currFP
= regs
->rbp
;
1207 uint64_t prevPC
= 0ULL;
1208 uint64_t prevFP
= 0ULL;
1209 uint64_t kernStackMin
= (uint64_t)thread
->kernel_stack
;
1210 uint64_t kernStackMax
= (uint64_t)kernStackMin
+ kernel_stack_size
;
1211 mach_msg_type_number_t ct
= *start_idx
;
1212 kern_return_t kr
= KERN_FAILURE
;
1214 if(*start_idx
>= max_idx
)
1215 return KERN_RESOURCE_SHORTAGE
; // no frames traced
1217 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1219 // build a backtrace of this 32 bit state.
1220 while(VALID_STACK_ADDRESS64(supervisor
, currFP
, kernStackMin
, kernStackMax
)) {
1221 // this is the address where caller lives in the user thread
1222 uint64_t caller
= currFP
+ sizeof(uint64_t);
1231 return KERN_RESOURCE_SHORTAGE
;
1234 /* read our caller */
1236 kr
= chudxnu_kern_read(&currPC
, (vm_offset_t
)caller
, sizeof(uint64_t));
1238 kr
= chudxnu_task_read(task
, &currPC
, caller
, sizeof(uint64_t));
1241 if(kr
!= KERN_SUCCESS
) {
1247 * retrive contents of the frame pointer and advance to the next stack
1248 * frame if it's valid
1252 kr
= chudxnu_kern_read(&prevFP
, (vm_offset_t
)currFP
, sizeof(uint64_t));
1254 kr
= chudxnu_task_read(task
, &prevFP
, currFP
, sizeof(uint64_t));
1257 if(VALID_STACK_ADDRESS64(supervisor
, prevFP
, kernStackMin
, kernStackMax
)) {
1258 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1261 if(prevFP
< currFP
) {
1269 return KERN_SUCCESS
;
1272 static kern_return_t
1273 chudxnu_thread_get_callstack64_internal(
1275 uint64_t *callstack
,
1276 mach_msg_type_number_t
*count
,
1277 boolean_t user_only
,
1278 boolean_t kern_only
)
1280 kern_return_t kr
= KERN_FAILURE
;
1281 task_t task
= thread
->task
;
1282 uint64_t currPC
= 0ULL;
1283 boolean_t supervisor
= FALSE
;
1284 mach_msg_type_number_t bufferIndex
= 0;
1285 mach_msg_type_number_t bufferMaxIndex
= *count
;
1286 x86_saved_state_t
*tagged_regs
= NULL
; // kernel register state
1287 x86_saved_state64_t
*regs64
= NULL
;
1288 x86_saved_state32_t
*regs32
= NULL
;
1289 x86_saved_state32_t
*u_regs32
= NULL
;
1290 x86_saved_state64_t
*u_regs64
= NULL
;
1291 struct x86_kernel_state
*kregs
= NULL
;
1293 if(ml_at_interrupt_context()) {
1296 /* can't backtrace user state on interrupt stack. */
1297 return KERN_FAILURE
;
1300 /* backtracing at interrupt context? */
1301 if(thread
== current_thread() && current_cpu_datap()->cpu_int_state
) {
1303 * Locate the registers for the interrupted thread, assuming it is
1306 tagged_regs
= current_cpu_datap()->cpu_int_state
;
1308 if(is_saved_state64(tagged_regs
)) {
1309 /* 64 bit registers */
1310 regs64
= saved_state64(tagged_regs
);
1311 supervisor
= ((regs64
->isf
.cs
& SEL_PL
) != SEL_PL_U
);
1313 /* 32 bit registers */
1314 regs32
= saved_state32(tagged_regs
);
1315 supervisor
= ((regs32
->cs
& SEL_PL
) != SEL_PL_U
);
1320 if(!ml_at_interrupt_context() && kernel_task
== task
) {
1322 if(!thread
->kernel_stack
) {
1323 return KERN_FAILURE
;
1326 // Kernel thread not at interrupt context
1327 kregs
= (struct x86_kernel_state
*)NULL
;
1329 // nofault read of the thread->kernel_stack pointer
1330 if(KERN_SUCCESS
!= chudxnu_kern_read(&kregs
, (vm_offset_t
)&(thread
->kernel_stack
), sizeof(void *))) {
1331 return KERN_FAILURE
;
1334 // Adjust to find the saved kernel state
1335 kregs
= STACK_IKS((vm_offset_t
)(uintptr_t)kregs
);
1338 } else if(!tagged_regs
) {
1340 * not at interrupt context, or tracing a different thread than
1341 * current_thread() at interrupt context
1343 tagged_regs
= USER_STATE(thread
);
1344 if(is_saved_state64(tagged_regs
)) {
1345 /* 64 bit registers */
1346 regs64
= saved_state64(tagged_regs
);
1347 supervisor
= ((regs64
->isf
.cs
& SEL_PL
) != SEL_PL_U
);
1349 /* 32 bit registers */
1350 regs32
= saved_state32(tagged_regs
);
1351 supervisor
= ((regs32
->cs
& SEL_PL
) != SEL_PL_U
);
1358 // the caller only wants a user callstack.
1360 // bail - we've only got kernel state
1361 return KERN_FAILURE
;
1364 // regs32(64) is not in supervisor mode.
1372 /* we only want to backtrace the user mode */
1373 if(!(u_regs32
|| u_regs64
)) {
1374 /* no user state to look at */
1375 return KERN_FAILURE
;
1380 * Order of preference for top of stack:
1381 * 64 bit kernel state (not likely)
1382 * 32 bit kernel state
1383 * 64 bit user land state
1384 * 32 bit user land state
1389 * nofault read of the registers from the kernel stack (as they can
1390 * disappear on the fly).
1393 if(KERN_SUCCESS
!= chudxnu_kern_read(&currPC
, (vm_offset_t
)&(kregs
->k_rip
), sizeof(uint64_t))) {
1394 return KERN_FAILURE
;
1397 currPC
= regs64
->isf
.rip
;
1399 currPC
= (uint64_t) regs32
->eip
;
1400 } else if(u_regs64
) {
1401 currPC
= u_regs64
->isf
.rip
;
1402 } else if(u_regs32
) {
1403 currPC
= (uint64_t) u_regs32
->eip
;
1407 /* no top of the stack, bail out */
1408 return KERN_FAILURE
;
1413 if(bufferMaxIndex
< 1) {
1415 return KERN_RESOURCE_SHORTAGE
;
1418 /* backtrace kernel */
1420 addr64_t address
= 0ULL;
1424 kr
= do_kernel_backtrace(thread
, kregs
, callstack
, &bufferIndex
, bufferMaxIndex
);
1426 // and do a nofault read of (r|e)sp
1427 uint64_t rsp
= 0ULL;
1428 size
= sizeof(uint64_t);
1430 if(KERN_SUCCESS
!= chudxnu_kern_read(&address
, (vm_offset_t
)&(kregs
->k_rsp
), size
)) {
1434 if(address
&& KERN_SUCCESS
== chudxnu_kern_read(&rsp
, (vm_offset_t
)address
, size
) && bufferIndex
< bufferMaxIndex
) {
1435 callstack
[bufferIndex
++] = (uint64_t)rsp
;
1438 uint64_t rsp
= 0ULL;
1440 // backtrace the 64bit side.
1441 kr
= do_backtrace64(task
, thread
, regs64
, callstack
, &bufferIndex
,
1442 bufferMaxIndex
- 1, TRUE
);
1444 if(KERN_SUCCESS
== chudxnu_kern_read(&rsp
, (vm_offset_t
) regs64
->isf
.rsp
, sizeof(uint64_t)) &&
1445 bufferIndex
< bufferMaxIndex
) {
1446 callstack
[bufferIndex
++] = rsp
;
1452 // backtrace the 32bit side.
1453 kr
= do_backtrace32(task
, thread
, regs32
, callstack
, &bufferIndex
,
1454 bufferMaxIndex
- 1, TRUE
);
1456 if(KERN_SUCCESS
== chudxnu_kern_read(&esp
, (vm_offset_t
) regs32
->uesp
, sizeof(uint32_t)) &&
1457 bufferIndex
< bufferMaxIndex
) {
1458 callstack
[bufferIndex
++] = (uint64_t) esp
;
1460 } else if(u_regs64
&& !kern_only
) {
1461 /* backtrace user land */
1462 uint64_t rsp
= 0ULL;
1464 kr
= do_backtrace64(task
, thread
, u_regs64
, callstack
, &bufferIndex
,
1465 bufferMaxIndex
- 1, FALSE
);
1467 if(KERN_SUCCESS
== chudxnu_task_read(task
, &rsp
, (addr64_t
) u_regs64
->isf
.rsp
, sizeof(uint64_t)) &&
1468 bufferIndex
< bufferMaxIndex
) {
1469 callstack
[bufferIndex
++] = rsp
;
1472 } else if(u_regs32
&& !kern_only
) {
1475 kr
= do_backtrace32(task
, thread
, u_regs32
, callstack
, &bufferIndex
,
1476 bufferMaxIndex
- 1, FALSE
);
1478 if(KERN_SUCCESS
== chudxnu_task_read(task
, &esp
, (addr64_t
) u_regs32
->uesp
, sizeof(uint32_t)) &&
1479 bufferIndex
< bufferMaxIndex
) {
1480 callstack
[bufferIndex
++] = (uint64_t) esp
;
1484 *count
= bufferIndex
;
1489 kern_return_t
chudxnu_thread_get_callstack64_kperf(
1491 uint64_t *callstack
,
1492 mach_msg_type_number_t
*count
,
1495 return chudxnu_thread_get_callstack64_internal(thread
, callstack
, count
, is_user
, !is_user
);
1497 #else /* !__arm__ && !__arm64__ && !__x86_64__ */
1498 #error kperf: unsupported architecture
1499 #endif /* !__arm__ && !__arm64__ && !__x86_64__ */