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 <kern/cambria_layout.h>
35 #include <vm/vm_map.h>
36 #include <kperf/buffer.h>
37 #include <kperf/context.h>
38 #include <kperf/callstack.h>
39 #include <kperf/ast.h>
40 #include <sys/errno.h>
42 #if defined(__arm__) || defined(__arm64__)
43 #include <arm/cpu_data.h>
44 #include <arm/cpu_data_internal.h>
48 callstack_fixup_user(struct kp_ucallstack
*cs
, thread_t thread
)
50 uint64_t fixup_val
= 0;
51 assert(cs
->kpuc_nframes
< MAX_UCALLSTACK_FRAMES
);
53 #if defined(__x86_64__)
56 x86_saved_state_t
*state
;
58 state
= get_user_regs(thread
);
63 user_64
= is_saved_state64(state
);
65 sp_user
= saved_state64(state
)->isf
.rsp
;
67 sp_user
= saved_state32(state
)->uesp
;
70 if (thread
== current_thread()) {
71 (void)copyin(sp_user
, (char *)&fixup_val
,
72 user_64
? sizeof(uint64_t) : sizeof(uint32_t));
74 (void)vm_map_read_user(get_task_map(get_threadtask(thread
)), sp_user
,
75 &fixup_val
, user_64
? sizeof(uint64_t) : sizeof(uint32_t));
78 #elif defined(__arm64__) || defined(__arm__)
80 struct arm_saved_state
*state
= get_user_regs(thread
);
85 /* encode thumb mode into low bit of PC */
86 if (get_saved_state_cpsr(state
) & PSR_TF
) {
87 cs
->kpuc_frames
[0] |= 1ULL;
91 fixup_val
= get_saved_state_lr(state
);
94 #error "callstack_fixup_user: unsupported architecture"
98 cs
->kpuc_frames
[cs
->kpuc_nframes
++] = fixup_val
;
101 #if defined(__x86_64__)
103 __attribute__((used
))
105 interrupted_kernel_sp_value(uintptr_t *sp_val
)
107 x86_saved_state_t
*state
;
111 uintptr_t top
, bottom
;
113 state
= current_cpu_datap()->cpu_int_state
;
118 state_64
= is_saved_state64(state
);
121 cs
= saved_state64(state
)->isf
.cs
;
123 cs
= saved_state32(state
)->cs
;
125 /* return early if interrupted a thread in user space */
126 if ((cs
& SEL_PL
) == SEL_PL_U
) {
131 sp
= saved_state64(state
)->isf
.rsp
;
133 sp
= saved_state32(state
)->uesp
;
136 /* make sure the stack pointer is pointing somewhere in this stack */
137 bottom
= current_thread()->kernel_stack
;
138 top
= bottom
+ kernel_stack_size
;
139 if (sp
>= bottom
&& sp
< top
) {
143 *sp_val
= *(uintptr_t *)sp
;
147 #elif defined(__arm64__)
149 __attribute__((used
))
151 interrupted_kernel_lr(uintptr_t *lr
)
153 struct arm_saved_state
*state
;
155 state
= getCpuDatap()->cpu_int_state
;
157 /* return early if interrupted a thread in user space */
158 if (PSR64_IS_USER(get_saved_state_cpsr(state
))) {
162 *lr
= get_saved_state_lr(state
);
166 #elif defined(__arm__)
168 __attribute__((used
))
170 interrupted_kernel_lr(uintptr_t *lr
)
172 struct arm_saved_state
*state
;
174 state
= getCpuDatap()->cpu_int_state
;
176 /* return early if interrupted a thread in user space */
177 if (PSR_IS_USER(get_saved_state_cpsr(state
))) {
181 *lr
= get_saved_state_lr(state
);
185 #else /* defined(__arm__) */
186 #error "interrupted_kernel_{sp,lr}: unsupported architecture"
187 #endif /* !defined(__arm__) */
191 callstack_fixup_interrupted(struct kp_kcallstack
*cs
)
193 uintptr_t fixup_val
= 0;
194 assert(cs
->kpkc_nframes
< MAX_KCALLSTACK_FRAMES
);
197 * Only provide arbitrary data on development or debug kernels.
199 #if DEVELOPMENT || DEBUG
200 #if defined(__x86_64__)
201 (void)interrupted_kernel_sp_value(&fixup_val
);
202 #elif defined(__arm64__) || defined(__arm__)
203 (void)interrupted_kernel_lr(&fixup_val
);
204 #endif /* defined(__x86_64__) */
205 #endif /* DEVELOPMENT || DEBUG */
207 assert(cs
->kpkc_flags
& CALLSTACK_KERNEL
);
208 cs
->kpkc_frames
[cs
->kpkc_nframes
++] = fixup_val
;
212 kperf_continuation_sample(struct kp_kcallstack
*cs
, struct kperf_context
*context
)
217 assert(context
!= NULL
);
219 thread
= context
->cur_thread
;
220 assert(thread
!= NULL
);
221 assert(thread
->continuation
!= NULL
);
223 cs
->kpkc_flags
= CALLSTACK_CONTINUATION
| CALLSTACK_VALID
| CALLSTACK_KERNEL
;
225 cs
->kpkc_flags
|= CALLSTACK_64BIT
;
228 cs
->kpkc_nframes
= 1;
229 cs
->kpkc_frames
[0] = VM_KERNEL_UNSLIDE(thread
->continuation
);
233 kperf_backtrace_sample(struct kp_kcallstack
*cs
, struct kperf_context
*context
)
236 assert(context
!= NULL
);
237 assert(context
->cur_thread
== current_thread());
239 cs
->kpkc_flags
= CALLSTACK_KERNEL
| CALLSTACK_KERNEL_WORDS
;
241 cs
->kpkc_flags
|= CALLSTACK_64BIT
;
244 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_START
, 1);
247 cs
->kpkc_nframes
= backtrace_frame(cs
->kpkc_word_frames
,
248 cs
->kpkc_nframes
- 1, context
->starting_fp
, &trunc
);
249 if (cs
->kpkc_nframes
> 0) {
250 cs
->kpkc_flags
|= CALLSTACK_VALID
;
252 * Fake the value pointed to by the stack pointer or the link
253 * register for symbolicators.
255 cs
->kpkc_word_frames
[cs
->kpkc_nframes
+ 1] = 0;
256 cs
->kpkc_nframes
+= 1;
259 cs
->kpkc_flags
|= CALLSTACK_TRUNCATED
;
262 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_END
, cs
->kpkc_nframes
);
265 kern_return_t
chudxnu_thread_get_callstack64_kperf(thread_t thread
,
266 uint64_t *callStack
, mach_msg_type_number_t
*count
,
267 boolean_t user_only
);
270 kperf_kcallstack_sample(struct kp_kcallstack
*cs
, struct kperf_context
*context
)
275 assert(context
!= NULL
);
276 assert(cs
->kpkc_nframes
<= MAX_KCALLSTACK_FRAMES
);
278 thread
= context
->cur_thread
;
279 assert(thread
!= NULL
);
281 BUF_INFO(PERF_CS_KSAMPLE
| DBG_FUNC_START
, (uintptr_t)thread_tid(thread
),
284 cs
->kpkc_flags
= CALLSTACK_KERNEL
;
286 cs
->kpkc_flags
|= CALLSTACK_64BIT
;
289 if (ml_at_interrupt_context()) {
290 assert(thread
== current_thread());
291 cs
->kpkc_flags
|= CALLSTACK_KERNEL_WORDS
;
293 cs
->kpkc_nframes
= backtrace_interrupted(
294 cs
->kpkc_word_frames
, cs
->kpkc_nframes
- 1, &trunc
);
295 if (cs
->kpkc_nframes
!= 0) {
296 callstack_fixup_interrupted(cs
);
299 cs
->kpkc_flags
|= CALLSTACK_TRUNCATED
;
303 * Rely on legacy CHUD backtracer to backtrace kernel stacks on
307 kr
= chudxnu_thread_get_callstack64_kperf(thread
,
308 cs
->kpkc_frames
, &cs
->kpkc_nframes
, FALSE
);
309 if (kr
== KERN_SUCCESS
) {
310 cs
->kpkc_flags
|= CALLSTACK_VALID
;
311 } else if (kr
== KERN_RESOURCE_SHORTAGE
) {
312 cs
->kpkc_flags
|= CALLSTACK_VALID
;
313 cs
->kpkc_flags
|= CALLSTACK_TRUNCATED
;
315 cs
->kpkc_nframes
= 0;
319 if (!(cs
->kpkc_flags
& CALLSTACK_VALID
)) {
320 BUF_INFO(PERF_CS_ERROR
, ERR_GETSTACK
);
323 BUF_INFO(PERF_CS_KSAMPLE
| DBG_FUNC_END
, (uintptr_t)thread_tid(thread
),
324 cs
->kpkc_flags
, cs
->kpkc_nframes
);
328 kperf_ucallstack_sample(struct kp_ucallstack
*cs
, struct kperf_context
*context
)
330 assert(ml_get_interrupts_enabled() == TRUE
);
332 thread_t thread
= context
->cur_thread
;
333 assert(thread
!= NULL
);
335 BUF_INFO(PERF_CS_USAMPLE
| DBG_FUNC_START
,
336 (uintptr_t)thread_tid(thread
), cs
->kpuc_nframes
);
342 * Leave space for the fixup information.
344 unsigned int maxnframes
= cs
->kpuc_nframes
- 1;
345 unsigned int nframes
= backtrace_thread_user(thread
, cs
->kpuc_frames
,
346 maxnframes
, &error
, &user64
, &trunc
, true);
347 cs
->kpuc_nframes
= MIN(maxnframes
, nframes
);
350 * Ignore EFAULT to get as much of the stack as possible. It will be
351 * marked as truncated, below.
353 if (error
== 0 || error
== EFAULT
) {
354 callstack_fixup_user(cs
, thread
);
355 cs
->kpuc_flags
|= CALLSTACK_VALID
;
357 cs
->kpuc_nframes
= 0;
358 BUF_INFO(PERF_CS_ERROR
, ERR_GETSTACK
, error
);
361 cs
->kpuc_flags
|= CALLSTACK_KERNEL_WORDS
| (user64
? CALLSTACK_64BIT
: 0) |
362 (trunc
? CALLSTACK_TRUNCATED
: 0);
364 BUF_INFO(PERF_CS_USAMPLE
| DBG_FUNC_END
, (uintptr_t)thread_tid(thread
),
365 cs
->kpuc_flags
, cs
->kpuc_nframes
);
368 static inline uintptr_t
369 scrub_word(uintptr_t *bt
, int n_frames
, int frame
, bool kern
)
371 if (frame
< n_frames
) {
373 return VM_KERNEL_UNSLIDE(bt
[frame
]);
382 static inline uintptr_t
383 scrub_frame(uint64_t *bt
, int n_frames
, int frame
)
385 if (frame
< n_frames
) {
386 return (uintptr_t)(bt
[frame
]);
393 callstack_log(uint32_t hdrid
, uint32_t dataid
, void *vframes
,
394 unsigned int nframes
, unsigned int flags
)
396 BUF_VERB(PERF_CS_LOG
| DBG_FUNC_START
, flags
, nframes
);
398 BUF_DATA(hdrid
, flags
, nframes
);
400 unsigned int nevts
= nframes
/ 4;
401 unsigned int ovf
= nframes
% 4;
406 bool kern
= flags
& CALLSTACK_KERNEL
;
408 if (flags
& CALLSTACK_KERNEL_WORDS
) {
409 uintptr_t *frames
= vframes
;
410 for (unsigned int i
= 0; i
< nevts
; i
++) {
411 unsigned int j
= i
* 4;
413 scrub_word(frames
, nframes
, j
+ 0, kern
),
414 scrub_word(frames
, nframes
, j
+ 1, kern
),
415 scrub_word(frames
, nframes
, j
+ 2, kern
),
416 scrub_word(frames
, nframes
, j
+ 3, kern
));
419 for (unsigned int i
= 0; i
< nevts
; i
++) {
420 uint64_t *frames
= vframes
;
421 unsigned int j
= i
* 4;
423 scrub_frame(frames
, nframes
, j
+ 0),
424 scrub_frame(frames
, nframes
, j
+ 1),
425 scrub_frame(frames
, nframes
, j
+ 2),
426 scrub_frame(frames
, nframes
, j
+ 3));
430 BUF_VERB(PERF_CS_LOG
| DBG_FUNC_END
, flags
, nframes
);
434 kperf_kcallstack_log(struct kp_kcallstack
*cs
)
436 callstack_log(PERF_CS_KHDR
, PERF_CS_KDATA
, cs
->kpkc_frames
,
437 cs
->kpkc_nframes
, cs
->kpkc_flags
);
441 kperf_ucallstack_log(struct kp_ucallstack
*cs
)
443 callstack_log(PERF_CS_UHDR
, PERF_CS_UDATA
, cs
->kpuc_frames
,
444 cs
->kpuc_nframes
, cs
->kpuc_flags
);
448 kperf_ucallstack_pend(struct kperf_context
* context
, uint32_t depth
,
449 unsigned int actionid
)
454 kperf_ast_set_callstack_depth(context
->cur_thread
, depth
);
455 return kperf_ast_pend(context
->cur_thread
, T_KPERF_AST_CALLSTACK
,
460 chudxnu_kern_read(void *dstaddr
, vm_offset_t srcaddr
, vm_size_t size
)
462 return (ml_nofault_copy(srcaddr
, (vm_offset_t
)dstaddr
, size
) == size
) ?
463 KERN_SUCCESS
: KERN_FAILURE
;
473 //ppc version ported to arm
474 kern_return_t ret
= KERN_SUCCESS
;
476 if (ml_at_interrupt_context()) {
477 return KERN_FAILURE
; // can't look at tasks on interrupt stack
480 if (current_task() == task
) {
481 if (copyin(usraddr
, kernaddr
, size
)) {
485 vm_map_t map
= get_task_map(task
);
486 ret
= vm_map_read_user(map
, usraddr
, kernaddr
, size
);
492 static inline uint64_t
493 chudxnu_vm_unslide( uint64_t ptr
, int kaddr
)
499 return VM_KERNEL_UNSLIDE(ptr
);
503 #define ARM_SUPERVISOR_MODE(cpsr) ((((cpsr) & PSR_MODE_MASK) != PSR_USER_MODE) ? TRUE : FALSE)
504 #define CS_FLAG_EXTRASP 1 // capture extra sp register
506 chudxnu_thread_get_callstack64_internal(
509 mach_msg_type_number_t
*count
,
515 uint64_t currPC
= 0ULL, currLR
= 0ULL, currSP
= 0ULL;
516 uint64_t prevPC
= 0ULL;
517 uint32_t kernStackMin
= thread
->kernel_stack
;
518 uint32_t kernStackMax
= kernStackMin
+ kernel_stack_size
;
519 uint64_t *buffer
= callStack
;
522 int bufferMaxIndex
= 0;
523 boolean_t supervisor
= FALSE
;
524 struct arm_saved_state
*state
= NULL
;
525 uint32_t *fp
= NULL
, *nextFramePointer
= NULL
, *topfp
= NULL
;
528 task
= get_threadtask(thread
);
530 bufferMaxIndex
= *count
;
533 state
= find_user_regs(thread
);
535 state
= find_kern_regs(thread
);
543 /* make sure it is safe to dereference before you do it */
544 supervisor
= ARM_SUPERVISOR_MODE(state
->cpsr
);
546 /* can't take a kernel callstack if we've got a user frame */
547 if (!user_only
&& !supervisor
) {
552 * Reserve space for saving LR (and sometimes SP) at the end of the
555 if (flags
& CS_FLAG_EXTRASP
) {
561 if (bufferMaxIndex
< 2) {
563 return KERN_RESOURCE_SHORTAGE
;
566 currPC
= (uint64_t)state
->pc
; /* r15 */
567 if (state
->cpsr
& PSR_TF
) {
568 currPC
|= 1ULL; /* encode thumb mode into low bit of PC */
570 currLR
= (uint64_t)state
->lr
; /* r14 */
571 currSP
= (uint64_t)state
->sp
; /* r13 */
573 fp
= (uint32_t *)state
->r
[7]; /* frame pointer */
576 bufferIndex
= 0; // start with a stack of size zero
577 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currPC
, supervisor
); // save PC in position 0.
579 // Now, fill buffer with stack backtraces.
580 while (bufferIndex
< bufferMaxIndex
) {
583 * Below the frame pointer, the following values are saved:
588 * Note that we read the pc even for the first stack frame
589 * (which, in theory, is always empty because the callee fills
590 * it in just before it lowers the stack. However, if we
591 * catch the program in between filling in the return address
592 * and lowering the stack, we want to still have a valid
593 * backtrace. FixupStack correctly disregards this value if
597 if ((uint32_t)fp
== 0 || ((uint32_t)fp
& 0x3) != 0) {
598 /* frame pointer is invalid - stop backtracing */
604 if (((uint32_t)fp
> kernStackMax
) ||
605 ((uint32_t)fp
< kernStackMin
)) {
608 kr
= chudxnu_kern_read(&frame
,
610 (vm_size_t
)sizeof(frame
));
611 if (kr
== KERN_SUCCESS
) {
612 pc
= (uint64_t)frame
[1];
613 nextFramePointer
= (uint32_t *) (frame
[0]);
616 nextFramePointer
= 0ULL;
621 kr
= chudxnu_task_read(task
,
623 (((uint64_t)(uint32_t)fp
) & 0x00000000FFFFFFFFULL
),
625 if (kr
== KERN_SUCCESS
) {
626 pc
= (uint64_t) frame
[1];
627 nextFramePointer
= (uint32_t *) (frame
[0]);
630 nextFramePointer
= 0ULL;
635 if (kr
!= KERN_SUCCESS
) {
640 if (nextFramePointer
) {
641 buffer
[bufferIndex
++] = chudxnu_vm_unslide(pc
, supervisor
);
645 if (nextFramePointer
< fp
) {
648 fp
= nextFramePointer
;
652 if (bufferIndex
>= bufferMaxIndex
) {
653 bufferIndex
= bufferMaxIndex
;
654 kr
= KERN_RESOURCE_SHORTAGE
;
659 // Save link register and R13 (sp) at bottom of stack (used for later fixup).
660 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currLR
, supervisor
);
661 if (flags
& CS_FLAG_EXTRASP
) {
662 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currSP
, supervisor
);
665 *count
= bufferIndex
;
670 chudxnu_thread_get_callstack64_kperf(
673 mach_msg_type_number_t
*count
,
676 return chudxnu_thread_get_callstack64_internal( thread
, callStack
, count
, user_only
, 0 );
680 #if defined(HAS_APPLE_PAC)
684 // chudxnu_thread_get_callstack gathers a raw callstack along with any information needed to
685 // fix it up later (in case we stopped program as it was saving values into prev stack frame, etc.)
686 // after sampling has finished.
688 // For an N-entry callstack:
691 // [1..N-3] stack frames (including current one)
692 // [N-2] current LR (return value if we're in a leaf function)
693 // [N-1] current r0 (in case we've saved LR in r0) (optional)
696 #define ARM_SUPERVISOR_MODE(cpsr) ((((cpsr) & PSR_MODE_MASK) != PSR_USER_MODE) ? TRUE : FALSE)
698 #define CS_FLAG_EXTRASP 1 // capture extra sp register
701 chudxnu_thread_get_callstack64_internal(
704 mach_msg_type_number_t
*count
,
708 kern_return_t kr
= KERN_SUCCESS
;
710 uint64_t currPC
= 0ULL, currLR
= 0ULL, currSP
= 0ULL;
711 uint64_t prevPC
= 0ULL;
712 uint64_t kernStackMin
= thread
->kernel_stack
;
713 uint64_t kernStackMax
= kernStackMin
+ kernel_stack_size
;
714 uint64_t *buffer
= callStack
;
716 int bufferMaxIndex
= 0;
717 boolean_t kernel
= FALSE
;
718 struct arm_saved_state
*sstate
= NULL
;
721 task
= get_threadtask(thread
);
722 bufferMaxIndex
= *count
;
725 sstate
= find_user_regs(thread
);
727 sstate
= find_kern_regs(thread
);
735 if (is_saved_state64(sstate
)) {
736 struct arm_saved_state64
*state
= NULL
;
737 uint64_t *fp
= NULL
, *nextFramePointer
= NULL
, *topfp
= NULL
;
740 state
= saved_state64(sstate
);
742 /* make sure it is safe to dereference before you do it */
743 kernel
= PSR64_IS_KERNEL(state
->cpsr
);
745 /* can't take a kernel callstack if we've got a user frame */
746 if (!user_only
&& !kernel
) {
751 * Reserve space for saving LR (and sometimes SP) at the end of the
754 if (flags
& CS_FLAG_EXTRASP
) {
760 if (bufferMaxIndex
< 2) {
762 return KERN_RESOURCE_SHORTAGE
;
769 fp
= (uint64_t *)state
->fp
; /* frame pointer */
772 bufferIndex
= 0; // start with a stack of size zero
773 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currPC
, kernel
); // save PC in position 0.
775 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_START
, kernel
, 0);
777 // Now, fill buffer with stack backtraces.
778 while (bufferIndex
< bufferMaxIndex
) {
781 * Below the frame pointer, the following values are saved:
786 * Note that we read the pc even for the first stack frame
787 * (which, in theory, is always empty because the callee fills
788 * it in just before it lowers the stack. However, if we
789 * catch the program in between filling in the return address
790 * and lowering the stack, we want to still have a valid
791 * backtrace. FixupStack correctly disregards this value if
795 if ((uint64_t)fp
== 0 || ((uint64_t)fp
& 0x3) != 0) {
796 /* frame pointer is invalid - stop backtracing */
802 if (((uint64_t)fp
> kernStackMax
) ||
803 ((uint64_t)fp
< kernStackMin
)) {
806 kr
= chudxnu_kern_read(&frame
,
808 (vm_size_t
)sizeof(frame
));
809 if (kr
== KERN_SUCCESS
) {
810 #if defined(HAS_APPLE_PAC)
811 /* return addresses on stack will be signed by arm64e ABI */
812 pc
= (uint64_t)ptrauth_strip((void *)frame
[1], ptrauth_key_return_address
);
816 nextFramePointer
= (uint64_t *)frame
[0];
819 nextFramePointer
= 0ULL;
824 kr
= chudxnu_task_read(task
,
827 (vm_size_t
)sizeof(frame
));
828 if (kr
== KERN_SUCCESS
) {
829 #if defined(HAS_APPLE_PAC)
830 /* return addresses on stack will be signed by arm64e ABI */
831 pc
= (uint64_t)ptrauth_strip((void *)frame
[1], ptrauth_key_return_address
);
835 nextFramePointer
= (uint64_t *)(frame
[0]);
838 nextFramePointer
= 0ULL;
843 if (kr
!= KERN_SUCCESS
) {
848 if (nextFramePointer
) {
849 buffer
[bufferIndex
++] = chudxnu_vm_unslide(pc
, kernel
);
853 if (nextFramePointer
< fp
) {
856 fp
= nextFramePointer
;
860 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_END
, bufferIndex
);
862 if (bufferIndex
>= bufferMaxIndex
) {
863 bufferIndex
= bufferMaxIndex
;
864 kr
= KERN_RESOURCE_SHORTAGE
;
869 // Save link register and SP at bottom of stack (used for later fixup).
870 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currLR
, kernel
);
871 if (flags
& CS_FLAG_EXTRASP
) {
872 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currSP
, kernel
);
875 struct arm_saved_state32
*state
= NULL
;
876 uint32_t *fp
= NULL
, *nextFramePointer
= NULL
, *topfp
= NULL
;
878 /* 64-bit kernel stacks, 32-bit user stacks */
882 state
= saved_state32(sstate
);
884 /* make sure it is safe to dereference before you do it */
885 kernel
= ARM_SUPERVISOR_MODE(state
->cpsr
);
887 /* can't take a kernel callstack if we've got a user frame */
888 if (!user_only
&& !kernel
) {
893 * Reserve space for saving LR (and sometimes SP) at the end of the
896 if (flags
& CS_FLAG_EXTRASP
) {
902 if (bufferMaxIndex
< 2) {
904 return KERN_RESOURCE_SHORTAGE
;
907 currPC
= (uint64_t)state
->pc
; /* r15 */
908 if (state
->cpsr
& PSR_TF
) {
909 currPC
|= 1ULL; /* encode thumb mode into low bit of PC */
911 currLR
= (uint64_t)state
->lr
; /* r14 */
912 currSP
= (uint64_t)state
->sp
; /* r13 */
914 fp
= (uint32_t *)(uintptr_t)state
->r
[7]; /* frame pointer */
917 bufferIndex
= 0; // start with a stack of size zero
918 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currPC
, kernel
); // save PC in position 0.
920 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_START
, kernel
, 1);
922 // Now, fill buffer with stack backtraces.
923 while (bufferIndex
< bufferMaxIndex
) {
926 * Below the frame pointer, the following values are saved:
931 * Note that we read the pc even for the first stack frame
932 * (which, in theory, is always empty because the callee fills
933 * it in just before it lowers the stack. However, if we
934 * catch the program in between filling in the return address
935 * and lowering the stack, we want to still have a valid
936 * backtrace. FixupStack correctly disregards this value if
940 if ((uint32_t)fp
== 0 || ((uint32_t)fp
& 0x3) != 0) {
941 /* frame pointer is invalid - stop backtracing */
947 if (((uint32_t)fp
> kernStackMax
) ||
948 ((uint32_t)fp
< kernStackMin
)) {
951 kr
= chudxnu_kern_read(&frame
,
953 (vm_size_t
)sizeof(frame
));
954 if (kr
== KERN_SUCCESS
) {
955 pc
= (uint64_t)frame
[1];
956 nextFramePointer
= (uint32_t *) (frame
[0]);
959 nextFramePointer
= 0ULL;
964 kr
= chudxnu_task_read(task
,
966 (((uint64_t)(uint32_t)fp
) & 0x00000000FFFFFFFFULL
),
968 if (kr
== KERN_SUCCESS
) {
969 pc
= (uint64_t)frame32
[1];
970 nextFramePointer
= (uint32_t *)(uintptr_t)(frame32
[0]);
973 nextFramePointer
= 0ULL;
978 if (kr
!= KERN_SUCCESS
) {
983 if (nextFramePointer
) {
984 buffer
[bufferIndex
++] = chudxnu_vm_unslide(pc
, kernel
);
988 if (nextFramePointer
< fp
) {
991 fp
= nextFramePointer
;
995 BUF_VERB(PERF_CS_BACKTRACE
| DBG_FUNC_END
, bufferIndex
);
997 /* clamp callstack size to max */
998 if (bufferIndex
>= bufferMaxIndex
) {
999 bufferIndex
= bufferMaxIndex
;
1000 kr
= KERN_RESOURCE_SHORTAGE
;
1002 /* ignore all other failures */
1006 // Save link register and R13 (sp) at bottom of stack (used for later fixup).
1007 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currLR
, kernel
);
1008 if (flags
& CS_FLAG_EXTRASP
) {
1009 buffer
[bufferIndex
++] = chudxnu_vm_unslide(currSP
, kernel
);
1013 *count
= bufferIndex
;
1018 chudxnu_thread_get_callstack64_kperf(
1020 uint64_t *callStack
,
1021 mach_msg_type_number_t
*count
,
1022 boolean_t user_only
)
1024 return chudxnu_thread_get_callstack64_internal( thread
, callStack
, count
, user_only
, 0 );
1028 #define VALID_STACK_ADDRESS(supervisor, addr, minKernAddr, maxKernAddr) (supervisor ? (addr>=minKernAddr && addr<=maxKernAddr) : TRUE)
1029 // don't try to read in the hole
1030 #define VALID_STACK_ADDRESS64(supervisor, addr, minKernAddr, maxKernAddr) \
1031 (supervisor ? ((uint64_t)addr >= minKernAddr && (uint64_t)addr <= maxKernAddr) : \
1032 ((uint64_t)addr != 0ULL && ((uint64_t)addr <= 0x00007FFFFFFFFFFFULL || (uint64_t)addr >= 0xFFFF800000000000ULL)))
1034 typedef struct _cframe64_t
{
1035 uint64_t prevFP
; // can't use a real pointer here until we're a 64 bit kernel
1041 typedef struct _cframe_t
{
1042 uint32_t prev
; // this is really a user32-space pointer to the previous frame
1047 extern void * find_user_regs(thread_t
);
1048 extern x86_saved_state32_t
*find_kern_regs(thread_t
);
1050 static kern_return_t
1051 do_kernel_backtrace(
1053 struct x86_kernel_state
*regs
,
1055 mach_msg_type_number_t
*start_idx
,
1056 mach_msg_type_number_t max_idx
)
1058 uint64_t kernStackMin
= (uint64_t)thread
->kernel_stack
;
1059 uint64_t kernStackMax
= (uint64_t)kernStackMin
+ kernel_stack_size
;
1060 mach_msg_type_number_t ct
= *start_idx
;
1061 kern_return_t kr
= KERN_FAILURE
;
1064 uint64_t currPC
= 0ULL;
1065 uint64_t currFP
= 0ULL;
1066 uint64_t prevPC
= 0ULL;
1067 uint64_t prevFP
= 0ULL;
1068 if (KERN_SUCCESS
!= chudxnu_kern_read(&currPC
, (vm_offset_t
)&(regs
->k_rip
), sizeof(uint64_t))) {
1069 return KERN_FAILURE
;
1071 if (KERN_SUCCESS
!= chudxnu_kern_read(&currFP
, (vm_offset_t
)&(regs
->k_rbp
), sizeof(uint64_t))) {
1072 return KERN_FAILURE
;
1075 uint32_t currPC
= 0U;
1076 uint32_t currFP
= 0U;
1077 uint32_t prevPC
= 0U;
1078 uint32_t prevFP
= 0U;
1079 if (KERN_SUCCESS
!= chudxnu_kern_read(&currPC
, (vm_offset_t
)&(regs
->k_eip
), sizeof(uint32_t))) {
1080 return KERN_FAILURE
;
1082 if (KERN_SUCCESS
!= chudxnu_kern_read(&currFP
, (vm_offset_t
)&(regs
->k_ebp
), sizeof(uint32_t))) {
1083 return KERN_FAILURE
;
1087 if (*start_idx
>= max_idx
) {
1088 return KERN_RESOURCE_SHORTAGE
; // no frames traced
1091 return KERN_FAILURE
;
1094 frames
[ct
++] = chudxnu_vm_unslide((uint64_t)currPC
, 1);
1096 // build a backtrace of this kernel state
1098 while (VALID_STACK_ADDRESS64(TRUE
, currFP
, kernStackMin
, kernStackMax
)) {
1099 // this is the address where caller lives in the user thread
1100 uint64_t caller
= currFP
+ sizeof(uint64_t);
1102 while (VALID_STACK_ADDRESS(TRUE
, currFP
, kernStackMin
, kernStackMax
)) {
1103 uint32_t caller
= (uint32_t)currFP
+ sizeof(uint32_t);
1106 if (!currFP
|| !currPC
) {
1111 if (ct
>= max_idx
) {
1113 return KERN_RESOURCE_SHORTAGE
;
1116 /* read our caller */
1117 kr
= chudxnu_kern_read(&currPC
, (vm_offset_t
)caller
, sizeof(currPC
));
1119 if (kr
!= KERN_SUCCESS
|| !currPC
) {
1125 * retrive contents of the frame pointer and advance to the next stack
1126 * frame if it's valid
1129 kr
= chudxnu_kern_read(&prevFP
, (vm_offset_t
)currFP
, sizeof(currPC
));
1132 if (VALID_STACK_ADDRESS64(TRUE
, prevFP
, kernStackMin
, kernStackMax
)) {
1134 if (VALID_STACK_ADDRESS(TRUE
, prevFP
, kernStackMin
, kernStackMax
)) {
1136 frames
[ct
++] = chudxnu_vm_unslide((uint64_t)currPC
, 1);
1139 if (prevFP
<= currFP
) {
1147 return KERN_SUCCESS
;
1152 static kern_return_t
1156 x86_saved_state32_t
*regs
,
1158 mach_msg_type_number_t
*start_idx
,
1159 mach_msg_type_number_t max_idx
,
1160 boolean_t supervisor
)
1162 uint32_t tmpWord
= 0UL;
1163 uint64_t currPC
= (uint64_t) regs
->eip
;
1164 uint64_t currFP
= (uint64_t) regs
->ebp
;
1165 uint64_t prevPC
= 0ULL;
1166 uint64_t prevFP
= 0ULL;
1167 uint64_t kernStackMin
= thread
->kernel_stack
;
1168 uint64_t kernStackMax
= kernStackMin
+ kernel_stack_size
;
1169 mach_msg_type_number_t ct
= *start_idx
;
1170 kern_return_t kr
= KERN_FAILURE
;
1172 if (ct
>= max_idx
) {
1173 return KERN_RESOURCE_SHORTAGE
; // no frames traced
1175 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1177 // build a backtrace of this 32 bit state.
1178 while (VALID_STACK_ADDRESS(supervisor
, currFP
, kernStackMin
, kernStackMax
)) {
1179 cframe_t
*fp
= (cframe_t
*) (uintptr_t) currFP
;
1186 if (ct
>= max_idx
) {
1188 return KERN_RESOURCE_SHORTAGE
;
1191 /* read our caller */
1193 kr
= chudxnu_kern_read(&tmpWord
, (vm_offset_t
) &fp
->caller
, sizeof(uint32_t));
1195 kr
= chudxnu_task_read(task
, &tmpWord
, (vm_offset_t
) &fp
->caller
, sizeof(uint32_t));
1198 if (kr
!= KERN_SUCCESS
) {
1203 currPC
= (uint64_t) tmpWord
; // promote 32 bit address
1206 * retrive contents of the frame pointer and advance to the next stack
1207 * frame if it's valid
1211 kr
= chudxnu_kern_read(&tmpWord
, (vm_offset_t
)&fp
->prev
, sizeof(uint32_t));
1213 kr
= chudxnu_task_read(task
, &tmpWord
, (vm_offset_t
)&fp
->prev
, sizeof(uint32_t));
1215 prevFP
= (uint64_t) tmpWord
; // promote 32 bit address
1218 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1221 if (prevFP
< currFP
) {
1229 return KERN_SUCCESS
;
1232 static kern_return_t
1236 x86_saved_state64_t
*regs
,
1238 mach_msg_type_number_t
*start_idx
,
1239 mach_msg_type_number_t max_idx
,
1240 boolean_t supervisor
)
1242 uint64_t currPC
= regs
->isf
.rip
;
1243 uint64_t currFP
= regs
->rbp
;
1244 uint64_t prevPC
= 0ULL;
1245 uint64_t prevFP
= 0ULL;
1246 uint64_t kernStackMin
= (uint64_t)thread
->kernel_stack
;
1247 uint64_t kernStackMax
= (uint64_t)kernStackMin
+ kernel_stack_size
;
1248 mach_msg_type_number_t ct
= *start_idx
;
1249 kern_return_t kr
= KERN_FAILURE
;
1251 if (*start_idx
>= max_idx
) {
1252 return KERN_RESOURCE_SHORTAGE
; // no frames traced
1254 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1256 // build a backtrace of this 32 bit state.
1257 while (VALID_STACK_ADDRESS64(supervisor
, currFP
, kernStackMin
, kernStackMax
)) {
1258 // this is the address where caller lives in the user thread
1259 uint64_t caller
= currFP
+ sizeof(uint64_t);
1266 if (ct
>= max_idx
) {
1268 return KERN_RESOURCE_SHORTAGE
;
1271 /* read our caller */
1273 kr
= chudxnu_kern_read(&currPC
, (vm_offset_t
)caller
, sizeof(uint64_t));
1275 kr
= chudxnu_task_read(task
, &currPC
, caller
, sizeof(uint64_t));
1278 if (kr
!= KERN_SUCCESS
) {
1284 * retrive contents of the frame pointer and advance to the next stack
1285 * frame if it's valid
1289 kr
= chudxnu_kern_read(&prevFP
, (vm_offset_t
)currFP
, sizeof(uint64_t));
1291 kr
= chudxnu_task_read(task
, &prevFP
, currFP
, sizeof(uint64_t));
1294 if (VALID_STACK_ADDRESS64(supervisor
, prevFP
, kernStackMin
, kernStackMax
)) {
1295 frames
[ct
++] = chudxnu_vm_unslide(currPC
, supervisor
);
1298 if (prevFP
< currFP
) {
1306 return KERN_SUCCESS
;
1309 static kern_return_t
1310 chudxnu_thread_get_callstack64_internal(
1312 uint64_t *callstack
,
1313 mach_msg_type_number_t
*count
,
1314 boolean_t user_only
,
1315 boolean_t kern_only
)
1317 kern_return_t kr
= KERN_FAILURE
;
1318 task_t task
= thread
->task
;
1319 uint64_t currPC
= 0ULL;
1320 boolean_t supervisor
= FALSE
;
1321 mach_msg_type_number_t bufferIndex
= 0;
1322 mach_msg_type_number_t bufferMaxIndex
= *count
;
1323 x86_saved_state_t
*tagged_regs
= NULL
; // kernel register state
1324 x86_saved_state64_t
*regs64
= NULL
;
1325 x86_saved_state32_t
*regs32
= NULL
;
1326 x86_saved_state32_t
*u_regs32
= NULL
;
1327 x86_saved_state64_t
*u_regs64
= NULL
;
1328 struct x86_kernel_state
*kregs
= NULL
;
1330 if (ml_at_interrupt_context()) {
1332 /* can't backtrace user state on interrupt stack. */
1333 return KERN_FAILURE
;
1336 /* backtracing at interrupt context? */
1337 if (thread
== current_thread() && current_cpu_datap()->cpu_int_state
) {
1339 * Locate the registers for the interrupted thread, assuming it is
1342 tagged_regs
= current_cpu_datap()->cpu_int_state
;
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
);
1356 if (!ml_at_interrupt_context() && kernel_task
== task
) {
1357 if (!thread
->kernel_stack
) {
1358 return KERN_FAILURE
;
1361 // Kernel thread not at interrupt context
1362 kregs
= (struct x86_kernel_state
*)NULL
;
1364 // nofault read of the thread->kernel_stack pointer
1365 if (KERN_SUCCESS
!= chudxnu_kern_read(&kregs
, (vm_offset_t
)&(thread
->kernel_stack
), sizeof(void *))) {
1366 return KERN_FAILURE
;
1369 // Adjust to find the saved kernel state
1370 kregs
= STACK_IKS((vm_offset_t
)(uintptr_t)kregs
);
1373 } else if (!tagged_regs
) {
1375 * not at interrupt context, or tracing a different thread than
1376 * current_thread() at interrupt context
1378 tagged_regs
= USER_STATE(thread
);
1379 if (is_saved_state64(tagged_regs
)) {
1380 /* 64 bit registers */
1381 regs64
= saved_state64(tagged_regs
);
1382 supervisor
= ((regs64
->isf
.cs
& SEL_PL
) != SEL_PL_U
);
1384 /* 32 bit registers */
1385 regs32
= saved_state32(tagged_regs
);
1386 supervisor
= ((regs32
->cs
& SEL_PL
) != SEL_PL_U
);
1393 // the caller only wants a user callstack.
1395 // bail - we've only got kernel state
1396 return KERN_FAILURE
;
1399 // regs32(64) is not in supervisor mode.
1407 /* we only want to backtrace the user mode */
1408 if (!(u_regs32
|| u_regs64
)) {
1409 /* no user state to look at */
1410 return KERN_FAILURE
;
1415 * Order of preference for top of stack:
1416 * 64 bit kernel state (not likely)
1417 * 32 bit kernel state
1418 * 64 bit user land state
1419 * 32 bit user land state
1424 * nofault read of the registers from the kernel stack (as they can
1425 * disappear on the fly).
1428 if (KERN_SUCCESS
!= chudxnu_kern_read(&currPC
, (vm_offset_t
)&(kregs
->k_rip
), sizeof(uint64_t))) {
1429 return KERN_FAILURE
;
1431 } else if (regs64
) {
1432 currPC
= regs64
->isf
.rip
;
1433 } else if (regs32
) {
1434 currPC
= (uint64_t) regs32
->eip
;
1435 } else if (u_regs64
) {
1436 currPC
= u_regs64
->isf
.rip
;
1437 } else if (u_regs32
) {
1438 currPC
= (uint64_t) u_regs32
->eip
;
1442 /* no top of the stack, bail out */
1443 return KERN_FAILURE
;
1448 if (bufferMaxIndex
< 1) {
1450 return KERN_RESOURCE_SHORTAGE
;
1453 /* backtrace kernel */
1455 addr64_t address
= 0ULL;
1459 kr
= do_kernel_backtrace(thread
, kregs
, callstack
, &bufferIndex
, bufferMaxIndex
);
1461 // and do a nofault read of (r|e)sp
1462 uint64_t rsp
= 0ULL;
1463 size
= sizeof(uint64_t);
1465 if (KERN_SUCCESS
!= chudxnu_kern_read(&address
, (vm_offset_t
)&(kregs
->k_rsp
), size
)) {
1469 if (address
&& KERN_SUCCESS
== chudxnu_kern_read(&rsp
, (vm_offset_t
)address
, size
) && bufferIndex
< bufferMaxIndex
) {
1470 callstack
[bufferIndex
++] = (uint64_t)rsp
;
1472 } else if (regs64
) {
1473 uint64_t rsp
= 0ULL;
1475 // backtrace the 64bit side.
1476 kr
= do_backtrace64(task
, thread
, regs64
, callstack
, &bufferIndex
,
1477 bufferMaxIndex
- 1, TRUE
);
1479 if (KERN_SUCCESS
== chudxnu_kern_read(&rsp
, (vm_offset_t
) regs64
->isf
.rsp
, sizeof(uint64_t)) &&
1480 bufferIndex
< bufferMaxIndex
) {
1481 callstack
[bufferIndex
++] = rsp
;
1483 } else if (regs32
) {
1486 // backtrace the 32bit side.
1487 kr
= do_backtrace32(task
, thread
, regs32
, callstack
, &bufferIndex
,
1488 bufferMaxIndex
- 1, TRUE
);
1490 if (KERN_SUCCESS
== chudxnu_kern_read(&esp
, (vm_offset_t
) regs32
->uesp
, sizeof(uint32_t)) &&
1491 bufferIndex
< bufferMaxIndex
) {
1492 callstack
[bufferIndex
++] = (uint64_t) esp
;
1494 } else if (u_regs64
&& !kern_only
) {
1495 /* backtrace user land */
1496 uint64_t rsp
= 0ULL;
1498 kr
= do_backtrace64(task
, thread
, u_regs64
, callstack
, &bufferIndex
,
1499 bufferMaxIndex
- 1, FALSE
);
1501 if (KERN_SUCCESS
== chudxnu_task_read(task
, &rsp
, (addr64_t
) u_regs64
->isf
.rsp
, sizeof(uint64_t)) &&
1502 bufferIndex
< bufferMaxIndex
) {
1503 callstack
[bufferIndex
++] = rsp
;
1505 } else if (u_regs32
&& !kern_only
) {
1508 kr
= do_backtrace32(task
, thread
, u_regs32
, callstack
, &bufferIndex
,
1509 bufferMaxIndex
- 1, FALSE
);
1511 if (KERN_SUCCESS
== chudxnu_task_read(task
, &esp
, (addr64_t
) u_regs32
->uesp
, sizeof(uint32_t)) &&
1512 bufferIndex
< bufferMaxIndex
) {
1513 callstack
[bufferIndex
++] = (uint64_t) esp
;
1517 *count
= bufferIndex
;
1523 chudxnu_thread_get_callstack64_kperf(
1525 uint64_t *callstack
,
1526 mach_msg_type_number_t
*count
,
1529 return chudxnu_thread_get_callstack64_internal(thread
, callstack
, count
, is_user
, !is_user
);
1531 #else /* !__arm__ && !__arm64__ && !__x86_64__ */
1532 #error kperf: unsupported architecture
1533 #endif /* !__arm__ && !__arm64__ && !__x86_64__ */