xref: /xnu-11417.140.69/osfmk/kperf/callstack.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1*43a90889SApple OSS Distributions /*
2*43a90889SApple OSS Distributions  * Copyright (c) 2011-2022 Apple Computer, Inc. All rights reserved.
3*43a90889SApple OSS Distributions  *
4*43a90889SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*43a90889SApple OSS Distributions  *
6*43a90889SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*43a90889SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*43a90889SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*43a90889SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*43a90889SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*43a90889SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*43a90889SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*43a90889SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*43a90889SApple OSS Distributions  *
15*43a90889SApple OSS Distributions  * Please obtain a copy of the License at
16*43a90889SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*43a90889SApple OSS Distributions  *
18*43a90889SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*43a90889SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*43a90889SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*43a90889SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*43a90889SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*43a90889SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*43a90889SApple OSS Distributions  * limitations under the License.
25*43a90889SApple OSS Distributions  *
26*43a90889SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*43a90889SApple OSS Distributions  */
28*43a90889SApple OSS Distributions 
29*43a90889SApple OSS Distributions /* Collect kernel callstacks */
30*43a90889SApple OSS Distributions 
31*43a90889SApple OSS Distributions #include <mach/mach_types.h>
32*43a90889SApple OSS Distributions #include <kern/thread.h>
33*43a90889SApple OSS Distributions #include <kern/backtrace.h>
34*43a90889SApple OSS Distributions #include <kern/cambria_layout.h>
35*43a90889SApple OSS Distributions #include <vm/vm_map_xnu.h>
36*43a90889SApple OSS Distributions #include <kperf/buffer.h>
37*43a90889SApple OSS Distributions #include <kperf/context.h>
38*43a90889SApple OSS Distributions #include <kperf/callstack.h>
39*43a90889SApple OSS Distributions #include <kperf/ast.h>
40*43a90889SApple OSS Distributions #include <sys/errno.h>
41*43a90889SApple OSS Distributions #include <mach/exclaves.h>
42*43a90889SApple OSS Distributions 
43*43a90889SApple OSS Distributions #if defined(__arm64__)
44*43a90889SApple OSS Distributions #include <arm/cpu_data.h>
45*43a90889SApple OSS Distributions #include <arm/cpu_data_internal.h>
46*43a90889SApple OSS Distributions #endif
47*43a90889SApple OSS Distributions 
48*43a90889SApple OSS Distributions static void
callstack_fixup_user(struct kp_ucallstack * cs,thread_t thread)49*43a90889SApple OSS Distributions callstack_fixup_user(struct kp_ucallstack *cs, thread_t thread)
50*43a90889SApple OSS Distributions {
51*43a90889SApple OSS Distributions 	uint64_t fixup_val = 0;
52*43a90889SApple OSS Distributions 	assert(cs->kpuc_nframes < MAX_UCALLSTACK_FRAMES);
53*43a90889SApple OSS Distributions 
54*43a90889SApple OSS Distributions #if defined(__x86_64__)
55*43a90889SApple OSS Distributions 	user_addr_t sp_user;
56*43a90889SApple OSS Distributions 	bool user_64;
57*43a90889SApple OSS Distributions 	x86_saved_state_t *state;
58*43a90889SApple OSS Distributions 
59*43a90889SApple OSS Distributions 	state = get_user_regs(thread);
60*43a90889SApple OSS Distributions 	if (!state) {
61*43a90889SApple OSS Distributions 		goto out;
62*43a90889SApple OSS Distributions 	}
63*43a90889SApple OSS Distributions 
64*43a90889SApple OSS Distributions 	user_64 = is_saved_state64(state);
65*43a90889SApple OSS Distributions 	if (user_64) {
66*43a90889SApple OSS Distributions 		sp_user = saved_state64(state)->isf.rsp;
67*43a90889SApple OSS Distributions 	} else {
68*43a90889SApple OSS Distributions 		sp_user = saved_state32(state)->uesp;
69*43a90889SApple OSS Distributions 	}
70*43a90889SApple OSS Distributions 
71*43a90889SApple OSS Distributions 	if (thread == current_thread()) {
72*43a90889SApple OSS Distributions 		(void)copyin(sp_user, (char *)&fixup_val,
73*43a90889SApple OSS Distributions 		    user_64 ? sizeof(uint64_t) : sizeof(uint32_t));
74*43a90889SApple OSS Distributions 	} else {
75*43a90889SApple OSS Distributions 		(void)vm_map_read_user(get_task_map(get_threadtask(thread)), sp_user,
76*43a90889SApple OSS Distributions 		    &fixup_val, user_64 ? sizeof(uint64_t) : sizeof(uint32_t));
77*43a90889SApple OSS Distributions 	}
78*43a90889SApple OSS Distributions 
79*43a90889SApple OSS Distributions #elif defined(__arm64__)
80*43a90889SApple OSS Distributions 
81*43a90889SApple OSS Distributions 	struct arm_saved_state *state = get_user_regs(thread);
82*43a90889SApple OSS Distributions 	if (!state) {
83*43a90889SApple OSS Distributions 		goto out;
84*43a90889SApple OSS Distributions 	}
85*43a90889SApple OSS Distributions 
86*43a90889SApple OSS Distributions 	/* encode thumb mode into low bit of PC */
87*43a90889SApple OSS Distributions 	if (is_saved_state32(state) && (get_saved_state_cpsr(state) & PSR_TF)) {
88*43a90889SApple OSS Distributions 		cs->kpuc_frames[0] |= 1ULL;
89*43a90889SApple OSS Distributions 	}
90*43a90889SApple OSS Distributions 
91*43a90889SApple OSS Distributions 
92*43a90889SApple OSS Distributions 	fixup_val = get_saved_state_lr(state);
93*43a90889SApple OSS Distributions 
94*43a90889SApple OSS Distributions #else
95*43a90889SApple OSS Distributions #error "callstack_fixup_user: unsupported architecture"
96*43a90889SApple OSS Distributions #endif
97*43a90889SApple OSS Distributions 
98*43a90889SApple OSS Distributions out:
99*43a90889SApple OSS Distributions 	cs->kpuc_frames[cs->kpuc_nframes++] = fixup_val;
100*43a90889SApple OSS Distributions }
101*43a90889SApple OSS Distributions 
102*43a90889SApple OSS Distributions #if defined(__x86_64__)
103*43a90889SApple OSS Distributions 
104*43a90889SApple OSS Distributions __attribute__((used))
105*43a90889SApple OSS Distributions static kern_return_t
interrupted_kernel_sp_value(uintptr_t * sp_val)106*43a90889SApple OSS Distributions interrupted_kernel_sp_value(uintptr_t *sp_val)
107*43a90889SApple OSS Distributions {
108*43a90889SApple OSS Distributions 	x86_saved_state_t *state;
109*43a90889SApple OSS Distributions 	uintptr_t sp;
110*43a90889SApple OSS Distributions 	bool state_64;
111*43a90889SApple OSS Distributions 	uint64_t cs;
112*43a90889SApple OSS Distributions 	uintptr_t top, bottom;
113*43a90889SApple OSS Distributions 
114*43a90889SApple OSS Distributions 	state = current_cpu_datap()->cpu_int_state;
115*43a90889SApple OSS Distributions 	if (!state) {
116*43a90889SApple OSS Distributions 		return KERN_FAILURE;
117*43a90889SApple OSS Distributions 	}
118*43a90889SApple OSS Distributions 
119*43a90889SApple OSS Distributions 	state_64 = is_saved_state64(state);
120*43a90889SApple OSS Distributions 
121*43a90889SApple OSS Distributions 	if (state_64) {
122*43a90889SApple OSS Distributions 		cs = saved_state64(state)->isf.cs;
123*43a90889SApple OSS Distributions 	} else {
124*43a90889SApple OSS Distributions 		cs = saved_state32(state)->cs;
125*43a90889SApple OSS Distributions 	}
126*43a90889SApple OSS Distributions 	/* return early if interrupted a thread in user space */
127*43a90889SApple OSS Distributions 	if ((cs & SEL_PL) == SEL_PL_U) {
128*43a90889SApple OSS Distributions 		return KERN_FAILURE;
129*43a90889SApple OSS Distributions 	}
130*43a90889SApple OSS Distributions 
131*43a90889SApple OSS Distributions 	if (state_64) {
132*43a90889SApple OSS Distributions 		sp = saved_state64(state)->isf.rsp;
133*43a90889SApple OSS Distributions 	} else {
134*43a90889SApple OSS Distributions 		sp = saved_state32(state)->uesp;
135*43a90889SApple OSS Distributions 	}
136*43a90889SApple OSS Distributions 
137*43a90889SApple OSS Distributions 	/* make sure the stack pointer is pointing somewhere in this stack */
138*43a90889SApple OSS Distributions 	bottom = current_thread()->kernel_stack;
139*43a90889SApple OSS Distributions 	top = bottom + kernel_stack_size;
140*43a90889SApple OSS Distributions 	if (sp >= bottom && sp < top) {
141*43a90889SApple OSS Distributions 		return KERN_FAILURE;
142*43a90889SApple OSS Distributions 	}
143*43a90889SApple OSS Distributions 
144*43a90889SApple OSS Distributions 	*sp_val = *(uintptr_t *)sp;
145*43a90889SApple OSS Distributions 	return KERN_SUCCESS;
146*43a90889SApple OSS Distributions }
147*43a90889SApple OSS Distributions 
148*43a90889SApple OSS Distributions #elif defined(__arm64__)
149*43a90889SApple OSS Distributions 
150*43a90889SApple OSS Distributions __attribute__((used))
151*43a90889SApple OSS Distributions static kern_return_t
interrupted_kernel_lr(uintptr_t * lr)152*43a90889SApple OSS Distributions interrupted_kernel_lr(uintptr_t *lr)
153*43a90889SApple OSS Distributions {
154*43a90889SApple OSS Distributions 	struct arm_saved_state *state;
155*43a90889SApple OSS Distributions 
156*43a90889SApple OSS Distributions 	state = getCpuDatap()->cpu_int_state;
157*43a90889SApple OSS Distributions 
158*43a90889SApple OSS Distributions 	/* return early if interrupted a thread in user space */
159*43a90889SApple OSS Distributions 	if (PSR64_IS_USER(get_saved_state_cpsr(state))) {
160*43a90889SApple OSS Distributions 		return KERN_FAILURE;
161*43a90889SApple OSS Distributions 	}
162*43a90889SApple OSS Distributions 
163*43a90889SApple OSS Distributions 	*lr = get_saved_state_lr(state);
164*43a90889SApple OSS Distributions 	return KERN_SUCCESS;
165*43a90889SApple OSS Distributions }
166*43a90889SApple OSS Distributions #else /* defined(__arm64__) */
167*43a90889SApple OSS Distributions #error "interrupted_kernel_{sp,lr}: unsupported architecture"
168*43a90889SApple OSS Distributions #endif /* !defined(__arm64__) */
169*43a90889SApple OSS Distributions 
170*43a90889SApple OSS Distributions 
171*43a90889SApple OSS Distributions static void
callstack_fixup_interrupted(struct kp_kcallstack * cs)172*43a90889SApple OSS Distributions callstack_fixup_interrupted(struct kp_kcallstack *cs)
173*43a90889SApple OSS Distributions {
174*43a90889SApple OSS Distributions 	uintptr_t fixup_val = 0;
175*43a90889SApple OSS Distributions 	assert(cs->kpkc_nframes < MAX_KCALLSTACK_FRAMES);
176*43a90889SApple OSS Distributions 
177*43a90889SApple OSS Distributions 	/*
178*43a90889SApple OSS Distributions 	 * Only provide arbitrary data on development or debug kernels.
179*43a90889SApple OSS Distributions 	 */
180*43a90889SApple OSS Distributions #if DEVELOPMENT || DEBUG
181*43a90889SApple OSS Distributions #if defined(__x86_64__)
182*43a90889SApple OSS Distributions 	(void)interrupted_kernel_sp_value(&fixup_val);
183*43a90889SApple OSS Distributions #elif defined(__arm64__)
184*43a90889SApple OSS Distributions 	(void)interrupted_kernel_lr(&fixup_val);
185*43a90889SApple OSS Distributions #endif /* defined(__x86_64__) */
186*43a90889SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
187*43a90889SApple OSS Distributions 
188*43a90889SApple OSS Distributions 	assert(cs->kpkc_flags & CALLSTACK_KERNEL);
189*43a90889SApple OSS Distributions 	cs->kpkc_frames[cs->kpkc_nframes++] = fixup_val;
190*43a90889SApple OSS Distributions }
191*43a90889SApple OSS Distributions 
192*43a90889SApple OSS Distributions void
kperf_continuation_sample(struct kp_kcallstack * cs,struct kperf_context * context)193*43a90889SApple OSS Distributions kperf_continuation_sample(struct kp_kcallstack *cs, struct kperf_context *context)
194*43a90889SApple OSS Distributions {
195*43a90889SApple OSS Distributions 	thread_t thread;
196*43a90889SApple OSS Distributions 
197*43a90889SApple OSS Distributions 	assert(cs != NULL);
198*43a90889SApple OSS Distributions 	assert(context != NULL);
199*43a90889SApple OSS Distributions 
200*43a90889SApple OSS Distributions 	thread = context->cur_thread;
201*43a90889SApple OSS Distributions 	assert(thread != NULL);
202*43a90889SApple OSS Distributions 	assert(thread->continuation != NULL);
203*43a90889SApple OSS Distributions 
204*43a90889SApple OSS Distributions 	cs->kpkc_flags = CALLSTACK_CONTINUATION | CALLSTACK_VALID | CALLSTACK_KERNEL;
205*43a90889SApple OSS Distributions #ifdef __LP64__
206*43a90889SApple OSS Distributions 	cs->kpkc_flags |= CALLSTACK_64BIT;
207*43a90889SApple OSS Distributions #endif
208*43a90889SApple OSS Distributions 
209*43a90889SApple OSS Distributions 	cs->kpkc_nframes = 1;
210*43a90889SApple OSS Distributions 	cs->kpkc_frames[0] = VM_KERNEL_UNSLIDE(thread->continuation);
211*43a90889SApple OSS Distributions }
212*43a90889SApple OSS Distributions 
213*43a90889SApple OSS Distributions void
kperf_backtrace_sample(struct kp_kcallstack * cs,struct kperf_context * context)214*43a90889SApple OSS Distributions kperf_backtrace_sample(struct kp_kcallstack *cs, struct kperf_context *context)
215*43a90889SApple OSS Distributions {
216*43a90889SApple OSS Distributions 	assert(cs != NULL);
217*43a90889SApple OSS Distributions 	assert(context != NULL);
218*43a90889SApple OSS Distributions 	assert(context->cur_thread == current_thread());
219*43a90889SApple OSS Distributions 
220*43a90889SApple OSS Distributions 	cs->kpkc_flags = CALLSTACK_KERNEL | CALLSTACK_KERNEL_WORDS;
221*43a90889SApple OSS Distributions #ifdef __LP64__
222*43a90889SApple OSS Distributions 	cs->kpkc_flags |= CALLSTACK_64BIT;
223*43a90889SApple OSS Distributions #endif
224*43a90889SApple OSS Distributions 
225*43a90889SApple OSS Distributions 	BUF_VERB(PERF_CS_BACKTRACE | DBG_FUNC_START, 1);
226*43a90889SApple OSS Distributions 
227*43a90889SApple OSS Distributions 	backtrace_info_t btinfo = BTI_NONE;
228*43a90889SApple OSS Distributions 	struct backtrace_control ctl = {
229*43a90889SApple OSS Distributions 		.btc_frame_addr = (uintptr_t)context->starting_fp,
230*43a90889SApple OSS Distributions 	};
231*43a90889SApple OSS Distributions 	cs->kpkc_nframes = backtrace(cs->kpkc_word_frames, cs->kpkc_nframes - 1,
232*43a90889SApple OSS Distributions 	    &ctl, &btinfo);
233*43a90889SApple OSS Distributions 	if (cs->kpkc_nframes > 0) {
234*43a90889SApple OSS Distributions 		cs->kpkc_flags |= CALLSTACK_VALID;
235*43a90889SApple OSS Distributions 
236*43a90889SApple OSS Distributions 		cs->kpkc_exclaves_offset = 0;
237*43a90889SApple OSS Distributions #if CONFIG_EXCLAVES
238*43a90889SApple OSS Distributions 		if ((context->cur_thread->th_exclaves_state & TH_EXCLAVES_RPC) != 0) {
239*43a90889SApple OSS Distributions 			cs->kpkc_exclaves_offset = exclaves_stack_offset(cs->kpkc_word_frames, cs->kpkc_nframes, true);
240*43a90889SApple OSS Distributions 		}
241*43a90889SApple OSS Distributions #endif /* CONFIG_EXCLAVES */
242*43a90889SApple OSS Distributions 
243*43a90889SApple OSS Distributions 		/*
244*43a90889SApple OSS Distributions 		 * Fake the value pointed to by the stack pointer or the link
245*43a90889SApple OSS Distributions 		 * register for symbolicators.
246*43a90889SApple OSS Distributions 		 */
247*43a90889SApple OSS Distributions 		cs->kpkc_word_frames[cs->kpkc_nframes + 1] = 0;
248*43a90889SApple OSS Distributions 		cs->kpkc_nframes += 1;
249*43a90889SApple OSS Distributions 	}
250*43a90889SApple OSS Distributions 	if ((btinfo & BTI_TRUNCATED)) {
251*43a90889SApple OSS Distributions 		cs->kpkc_flags |= CALLSTACK_TRUNCATED;
252*43a90889SApple OSS Distributions 	}
253*43a90889SApple OSS Distributions 
254*43a90889SApple OSS Distributions 	BUF_VERB(PERF_CS_BACKTRACE | DBG_FUNC_END, cs->kpkc_nframes);
255*43a90889SApple OSS Distributions }
256*43a90889SApple OSS Distributions 
257*43a90889SApple OSS Distributions kern_return_t chudxnu_thread_get_callstack64_kperf(thread_t thread,
258*43a90889SApple OSS Distributions     uint64_t *callStack, mach_msg_type_number_t *count,
259*43a90889SApple OSS Distributions     boolean_t user_only);
260*43a90889SApple OSS Distributions 
261*43a90889SApple OSS Distributions void
kperf_kcallstack_sample(struct kp_kcallstack * cs,struct kperf_context * context)262*43a90889SApple OSS Distributions kperf_kcallstack_sample(struct kp_kcallstack *cs, struct kperf_context *context)
263*43a90889SApple OSS Distributions {
264*43a90889SApple OSS Distributions 	thread_t thread;
265*43a90889SApple OSS Distributions 
266*43a90889SApple OSS Distributions 	assert(cs != NULL);
267*43a90889SApple OSS Distributions 	assert(context != NULL);
268*43a90889SApple OSS Distributions 	assert(cs->kpkc_nframes <= MAX_KCALLSTACK_FRAMES);
269*43a90889SApple OSS Distributions 
270*43a90889SApple OSS Distributions 	thread = context->cur_thread;
271*43a90889SApple OSS Distributions 	assert(thread != NULL);
272*43a90889SApple OSS Distributions 
273*43a90889SApple OSS Distributions 	BUF_INFO(PERF_CS_KSAMPLE | DBG_FUNC_START, (uintptr_t)thread_tid(thread),
274*43a90889SApple OSS Distributions 	    cs->kpkc_nframes);
275*43a90889SApple OSS Distributions 
276*43a90889SApple OSS Distributions 	cs->kpkc_flags = CALLSTACK_KERNEL;
277*43a90889SApple OSS Distributions #ifdef __LP64__
278*43a90889SApple OSS Distributions 	cs->kpkc_flags |= CALLSTACK_64BIT;
279*43a90889SApple OSS Distributions #endif
280*43a90889SApple OSS Distributions 
281*43a90889SApple OSS Distributions 	if (ml_at_interrupt_context()) {
282*43a90889SApple OSS Distributions 		assert(thread == current_thread());
283*43a90889SApple OSS Distributions 		cs->kpkc_flags |= CALLSTACK_KERNEL_WORDS;
284*43a90889SApple OSS Distributions 		backtrace_info_t btinfo = BTI_NONE;
285*43a90889SApple OSS Distributions 		struct backtrace_control ctl = { .btc_flags = BTF_KERN_INTERRUPTED, };
286*43a90889SApple OSS Distributions 		cs->kpkc_nframes = backtrace(cs->kpkc_word_frames, cs->kpkc_nframes - 1,
287*43a90889SApple OSS Distributions 		    &ctl, &btinfo);
288*43a90889SApple OSS Distributions 		if (cs->kpkc_nframes != 0) {
289*43a90889SApple OSS Distributions 			callstack_fixup_interrupted(cs);
290*43a90889SApple OSS Distributions 		}
291*43a90889SApple OSS Distributions 		if ((btinfo & BTI_TRUNCATED)) {
292*43a90889SApple OSS Distributions 			cs->kpkc_flags |= CALLSTACK_TRUNCATED;
293*43a90889SApple OSS Distributions 		}
294*43a90889SApple OSS Distributions 
295*43a90889SApple OSS Distributions 		cs->kpkc_exclaves_offset = 0;
296*43a90889SApple OSS Distributions #if CONFIG_EXCLAVES
297*43a90889SApple OSS Distributions 		if ((thread->th_exclaves_state & TH_EXCLAVES_RPC) != 0) {
298*43a90889SApple OSS Distributions 			cs->kpkc_exclaves_offset = exclaves_stack_offset(cs->kpkc_word_frames, cs->kpkc_nframes, true);
299*43a90889SApple OSS Distributions 		}
300*43a90889SApple OSS Distributions #endif /* CONFIG_EXCLAVES */
301*43a90889SApple OSS Distributions 	} else {
302*43a90889SApple OSS Distributions 		/*
303*43a90889SApple OSS Distributions 		 * Rely on legacy CHUD backtracer to backtrace kernel stacks on
304*43a90889SApple OSS Distributions 		 * other threads.
305*43a90889SApple OSS Distributions 		 */
306*43a90889SApple OSS Distributions 		kern_return_t kr;
307*43a90889SApple OSS Distributions 		kr = chudxnu_thread_get_callstack64_kperf(thread,
308*43a90889SApple OSS Distributions 		    cs->kpkc_frames, &cs->kpkc_nframes, FALSE);
309*43a90889SApple OSS Distributions 		if (kr == KERN_SUCCESS) {
310*43a90889SApple OSS Distributions 			cs->kpkc_flags |= CALLSTACK_VALID;
311*43a90889SApple OSS Distributions 		} else if (kr == KERN_RESOURCE_SHORTAGE) {
312*43a90889SApple OSS Distributions 			cs->kpkc_flags |= CALLSTACK_VALID;
313*43a90889SApple OSS Distributions 			cs->kpkc_flags |= CALLSTACK_TRUNCATED;
314*43a90889SApple OSS Distributions 		} else {
315*43a90889SApple OSS Distributions 			cs->kpkc_nframes = 0;
316*43a90889SApple OSS Distributions 		}
317*43a90889SApple OSS Distributions 	}
318*43a90889SApple OSS Distributions 
319*43a90889SApple OSS Distributions 	if (!(cs->kpkc_flags & CALLSTACK_VALID)) {
320*43a90889SApple OSS Distributions 		BUF_INFO(PERF_CS_ERROR, ERR_GETSTACK);
321*43a90889SApple OSS Distributions 	}
322*43a90889SApple OSS Distributions 
323*43a90889SApple OSS Distributions 	BUF_INFO(PERF_CS_KSAMPLE | DBG_FUNC_END, (uintptr_t)thread_tid(thread),
324*43a90889SApple OSS Distributions 	    cs->kpkc_flags, cs->kpkc_nframes);
325*43a90889SApple OSS Distributions }
326*43a90889SApple OSS Distributions 
327*43a90889SApple OSS Distributions void
kperf_ucallstack_sample(struct kp_ucallstack * cs,struct kperf_context * context)328*43a90889SApple OSS Distributions kperf_ucallstack_sample(struct kp_ucallstack *cs, struct kperf_context *context)
329*43a90889SApple OSS Distributions {
330*43a90889SApple OSS Distributions 	assert(ml_get_interrupts_enabled() == TRUE);
331*43a90889SApple OSS Distributions 
332*43a90889SApple OSS Distributions 	thread_t thread = context->cur_thread;
333*43a90889SApple OSS Distributions 	assert(thread != NULL);
334*43a90889SApple OSS Distributions 
335*43a90889SApple OSS Distributions 	BUF_INFO(PERF_CS_USAMPLE | DBG_FUNC_START,
336*43a90889SApple OSS Distributions 	    (uintptr_t)thread_tid(thread), cs->kpuc_nframes);
337*43a90889SApple OSS Distributions 
338*43a90889SApple OSS Distributions 	struct backtrace_user_info btinfo = BTUINFO_INIT;
339*43a90889SApple OSS Distributions 	/*
340*43a90889SApple OSS Distributions 	 * Leave space for the fixup information.
341*43a90889SApple OSS Distributions 	 */
342*43a90889SApple OSS Distributions 	unsigned int maxnframes = cs->kpuc_nframes - 1;
343*43a90889SApple OSS Distributions 	struct backtrace_control ctl = { .btc_user_thread = thread, };
344*43a90889SApple OSS Distributions 	unsigned int nframes = backtrace_user(cs->kpuc_frames, maxnframes, &ctl,
345*43a90889SApple OSS Distributions 	    &btinfo);
346*43a90889SApple OSS Distributions 	cs->kpuc_nframes = MIN(maxnframes, nframes);
347*43a90889SApple OSS Distributions 
348*43a90889SApple OSS Distributions 	cs->kpuc_flags |= CALLSTACK_KERNEL_WORDS |
349*43a90889SApple OSS Distributions 	    ((btinfo.btui_info & BTI_TRUNCATED) ? CALLSTACK_TRUNCATED : 0) |
350*43a90889SApple OSS Distributions 	    ((btinfo.btui_info & BTI_64_BIT) ? CALLSTACK_64BIT : 0);
351*43a90889SApple OSS Distributions 
352*43a90889SApple OSS Distributions 	/*
353*43a90889SApple OSS Distributions 	 * Ignore EFAULT to get as much of the stack as possible.
354*43a90889SApple OSS Distributions 	 */
355*43a90889SApple OSS Distributions 	if (btinfo.btui_error == 0 || btinfo.btui_error == EFAULT) {
356*43a90889SApple OSS Distributions 		callstack_fixup_user(cs, thread);
357*43a90889SApple OSS Distributions 		cs->kpuc_flags |= CALLSTACK_VALID;
358*43a90889SApple OSS Distributions 
359*43a90889SApple OSS Distributions 		if (cs->kpuc_nframes < maxnframes &&
360*43a90889SApple OSS Distributions 		    btinfo.btui_async_frame_addr != 0) {
361*43a90889SApple OSS Distributions 			cs->kpuc_async_index = btinfo.btui_async_start_index;
362*43a90889SApple OSS Distributions 			ctl.btc_frame_addr = btinfo.btui_async_frame_addr;
363*43a90889SApple OSS Distributions 			ctl.btc_addr_offset = BTCTL_ASYNC_ADDR_OFFSET;
364*43a90889SApple OSS Distributions 			maxnframes -= cs->kpuc_nframes;
365*43a90889SApple OSS Distributions 			btinfo = BTUINFO_INIT;
366*43a90889SApple OSS Distributions 			unsigned int nasync_frames = backtrace_user(
367*43a90889SApple OSS Distributions 			    &cs->kpuc_frames[cs->kpuc_nframes], maxnframes, &ctl, &btinfo);
368*43a90889SApple OSS Distributions 			if (btinfo.btui_info & BTI_TRUNCATED) {
369*43a90889SApple OSS Distributions 				cs->kpuc_flags |= CALLSTACK_TRUNCATED;
370*43a90889SApple OSS Distributions 			}
371*43a90889SApple OSS Distributions 			if (btinfo.btui_error == 0 || btinfo.btui_error == EFAULT) {
372*43a90889SApple OSS Distributions 				cs->kpuc_flags |= CALLSTACK_HAS_ASYNC;
373*43a90889SApple OSS Distributions 				cs->kpuc_async_nframes = nasync_frames;
374*43a90889SApple OSS Distributions 			}
375*43a90889SApple OSS Distributions 		}
376*43a90889SApple OSS Distributions 	} else {
377*43a90889SApple OSS Distributions 		cs->kpuc_nframes = 0;
378*43a90889SApple OSS Distributions 		BUF_INFO(PERF_CS_ERROR, ERR_GETSTACK, btinfo.btui_error);
379*43a90889SApple OSS Distributions 	}
380*43a90889SApple OSS Distributions 
381*43a90889SApple OSS Distributions 	BUF_INFO(PERF_CS_USAMPLE | DBG_FUNC_END, (uintptr_t)thread_tid(thread),
382*43a90889SApple OSS Distributions 	    cs->kpuc_flags, cs->kpuc_nframes);
383*43a90889SApple OSS Distributions }
384*43a90889SApple OSS Distributions 
385*43a90889SApple OSS Distributions static inline uintptr_t
scrub_word(uintptr_t * bt,int n_frames,int frame,bool kern)386*43a90889SApple OSS Distributions scrub_word(uintptr_t *bt, int n_frames, int frame, bool kern)
387*43a90889SApple OSS Distributions {
388*43a90889SApple OSS Distributions 	if (frame < n_frames) {
389*43a90889SApple OSS Distributions 		if (kern) {
390*43a90889SApple OSS Distributions 			return VM_KERNEL_UNSLIDE(bt[frame]);
391*43a90889SApple OSS Distributions 		} else {
392*43a90889SApple OSS Distributions 			return bt[frame];
393*43a90889SApple OSS Distributions 		}
394*43a90889SApple OSS Distributions 	} else {
395*43a90889SApple OSS Distributions 		return 0;
396*43a90889SApple OSS Distributions 	}
397*43a90889SApple OSS Distributions }
398*43a90889SApple OSS Distributions 
399*43a90889SApple OSS Distributions static inline uintptr_t
scrub_frame(uint64_t * bt,int n_frames,int frame)400*43a90889SApple OSS Distributions scrub_frame(uint64_t *bt, int n_frames, int frame)
401*43a90889SApple OSS Distributions {
402*43a90889SApple OSS Distributions 	if (frame < n_frames) {
403*43a90889SApple OSS Distributions 		return (uintptr_t)(bt[frame]);
404*43a90889SApple OSS Distributions 	} else {
405*43a90889SApple OSS Distributions 		return 0;
406*43a90889SApple OSS Distributions 	}
407*43a90889SApple OSS Distributions }
408*43a90889SApple OSS Distributions 
409*43a90889SApple OSS Distributions static void
callstack_log(uint32_t hdrid,uint32_t dataid,void * vframes,unsigned int nframes,unsigned int flags,unsigned int async_index,unsigned int async_nframes)410*43a90889SApple OSS Distributions callstack_log(uint32_t hdrid, uint32_t dataid, void *vframes,
411*43a90889SApple OSS Distributions     unsigned int nframes, unsigned int flags, unsigned int async_index,
412*43a90889SApple OSS Distributions     unsigned int async_nframes)
413*43a90889SApple OSS Distributions {
414*43a90889SApple OSS Distributions 	BUF_VERB(PERF_CS_LOG | DBG_FUNC_START, flags, nframes);
415*43a90889SApple OSS Distributions 	BUF_DATA(hdrid, flags, nframes - async_nframes, async_index, async_nframes);
416*43a90889SApple OSS Distributions 
417*43a90889SApple OSS Distributions 	unsigned int nevts = nframes / 4;
418*43a90889SApple OSS Distributions 	unsigned int ovf = nframes % 4;
419*43a90889SApple OSS Distributions 	if (ovf != 0) {
420*43a90889SApple OSS Distributions 		nevts++;
421*43a90889SApple OSS Distributions 	}
422*43a90889SApple OSS Distributions 
423*43a90889SApple OSS Distributions 	bool kern = flags & CALLSTACK_KERNEL;
424*43a90889SApple OSS Distributions 
425*43a90889SApple OSS Distributions 	if (flags & CALLSTACK_KERNEL_WORDS) {
426*43a90889SApple OSS Distributions 		uintptr_t *frames = vframes;
427*43a90889SApple OSS Distributions 		for (unsigned int i = 0; i < nevts; i++) {
428*43a90889SApple OSS Distributions 			unsigned int j = i * 4;
429*43a90889SApple OSS Distributions 			BUF_DATA(dataid,
430*43a90889SApple OSS Distributions 			    scrub_word(frames, nframes, j + 0, kern),
431*43a90889SApple OSS Distributions 			    scrub_word(frames, nframes, j + 1, kern),
432*43a90889SApple OSS Distributions 			    scrub_word(frames, nframes, j + 2, kern),
433*43a90889SApple OSS Distributions 			    scrub_word(frames, nframes, j + 3, kern));
434*43a90889SApple OSS Distributions 		}
435*43a90889SApple OSS Distributions 	} else {
436*43a90889SApple OSS Distributions 		for (unsigned int i = 0; i < nevts; i++) {
437*43a90889SApple OSS Distributions 			uint64_t *frames = vframes;
438*43a90889SApple OSS Distributions 			unsigned int j = i * 4;
439*43a90889SApple OSS Distributions 			BUF_DATA(dataid,
440*43a90889SApple OSS Distributions 			    scrub_frame(frames, nframes, j + 0),
441*43a90889SApple OSS Distributions 			    scrub_frame(frames, nframes, j + 1),
442*43a90889SApple OSS Distributions 			    scrub_frame(frames, nframes, j + 2),
443*43a90889SApple OSS Distributions 			    scrub_frame(frames, nframes, j + 3));
444*43a90889SApple OSS Distributions 		}
445*43a90889SApple OSS Distributions 	}
446*43a90889SApple OSS Distributions 
447*43a90889SApple OSS Distributions 	BUF_VERB(PERF_CS_LOG | DBG_FUNC_END, flags, nframes);
448*43a90889SApple OSS Distributions }
449*43a90889SApple OSS Distributions 
450*43a90889SApple OSS Distributions void
kperf_kcallstack_log(struct kp_kcallstack * cs)451*43a90889SApple OSS Distributions kperf_kcallstack_log(struct kp_kcallstack *cs)
452*43a90889SApple OSS Distributions {
453*43a90889SApple OSS Distributions 	callstack_log(PERF_CS_KHDR, PERF_CS_KDATA, cs->kpkc_frames,
454*43a90889SApple OSS Distributions 	    cs->kpkc_nframes, cs->kpkc_flags, 0, 0);
455*43a90889SApple OSS Distributions 
456*43a90889SApple OSS Distributions 	if (cs->kpkc_exclaves_offset != 0) {
457*43a90889SApple OSS Distributions 		BUF_DATA(PERF_CS_KEXOFFSET, cs->kpkc_exclaves_offset);
458*43a90889SApple OSS Distributions 	}
459*43a90889SApple OSS Distributions }
460*43a90889SApple OSS Distributions 
461*43a90889SApple OSS Distributions void
kperf_ucallstack_log(struct kp_ucallstack * cs)462*43a90889SApple OSS Distributions kperf_ucallstack_log(struct kp_ucallstack *cs)
463*43a90889SApple OSS Distributions {
464*43a90889SApple OSS Distributions 	callstack_log(PERF_CS_UHDR, PERF_CS_UDATA, cs->kpuc_frames,
465*43a90889SApple OSS Distributions 	    cs->kpuc_nframes + cs->kpuc_async_nframes, cs->kpuc_flags,
466*43a90889SApple OSS Distributions 	    cs->kpuc_async_index, cs->kpuc_async_nframes);
467*43a90889SApple OSS Distributions }
468*43a90889SApple OSS Distributions 
469*43a90889SApple OSS Distributions #if CONFIG_EXCLAVES
470*43a90889SApple OSS Distributions void
kperf_excallstack_log(const stackshottypes_ipcstackentry_s * ipcstack)471*43a90889SApple OSS Distributions kperf_excallstack_log(const stackshottypes_ipcstackentry_s *ipcstack)
472*43a90889SApple OSS Distributions {
473*43a90889SApple OSS Distributions 	__block unsigned int nframes = 0;
474*43a90889SApple OSS Distributions 	__block unsigned int flags = CALLSTACK_VALID;
475*43a90889SApple OSS Distributions 	uint64_t frames[MAX_EXCALLSTACK_FRAMES] = {};
476*43a90889SApple OSS Distributions 	uint64_t *frames_block = frames;
477*43a90889SApple OSS Distributions 
478*43a90889SApple OSS Distributions 	BUF_DATA(PERF_CS_EXSTACK, ipcstack->asid);
479*43a90889SApple OSS Distributions 
480*43a90889SApple OSS Distributions 	if (ipcstack->stacktrace.has_value) {
481*43a90889SApple OSS Distributions 		address__v_visit(&ipcstack->stacktrace.value, ^(size_t i, const stackshottypes_address_s item) {
482*43a90889SApple OSS Distributions 			if (i >= MAX_EXCALLSTACK_FRAMES) {
483*43a90889SApple OSS Distributions 				flags |= CALLSTACK_TRUNCATED;
484*43a90889SApple OSS Distributions 				return;
485*43a90889SApple OSS Distributions 			}
486*43a90889SApple OSS Distributions 			frames_block[i] = item;
487*43a90889SApple OSS Distributions 			nframes += 1;
488*43a90889SApple OSS Distributions 		});
489*43a90889SApple OSS Distributions 		callstack_log(PERF_CS_EXHDR, PERF_CS_EXDATA, frames, nframes, flags, 0, 0);
490*43a90889SApple OSS Distributions 	}
491*43a90889SApple OSS Distributions }
492*43a90889SApple OSS Distributions 
493*43a90889SApple OSS Distributions bool
kperf_exclave_callstack_pend(struct kperf_context * context,unsigned int actionid)494*43a90889SApple OSS Distributions kperf_exclave_callstack_pend(struct kperf_context *context, unsigned int actionid)
495*43a90889SApple OSS Distributions {
496*43a90889SApple OSS Distributions 	if ((context->cur_thread->th_exclaves_state & TH_EXCLAVES_RPC)
497*43a90889SApple OSS Distributions 	    && (os_atomic_load(&context->cur_thread->th_exclaves_inspection_state, relaxed) & TH_EXCLAVES_INSPECTION_NOINSPECT) == 0) {
498*43a90889SApple OSS Distributions 		os_atomic_or(&context->cur_thread->th_exclaves_inspection_state, TH_EXCLAVES_INSPECTION_KPERF, relaxed);
499*43a90889SApple OSS Distributions 		context->cur_thread->kperf_exclaves_ast |= T_KPERF_SET_ACTIONID(actionid);
500*43a90889SApple OSS Distributions 		return true;
501*43a90889SApple OSS Distributions 	}
502*43a90889SApple OSS Distributions 	return false;
503*43a90889SApple OSS Distributions }
504*43a90889SApple OSS Distributions #endif /* CONFIG_EXCLAVES */
505*43a90889SApple OSS Distributions 
506*43a90889SApple OSS Distributions int
kperf_ucallstack_pend(struct kperf_context * context,uint32_t depth,unsigned int actionid)507*43a90889SApple OSS Distributions kperf_ucallstack_pend(struct kperf_context * context, uint32_t depth,
508*43a90889SApple OSS Distributions     unsigned int actionid)
509*43a90889SApple OSS Distributions {
510*43a90889SApple OSS Distributions 	if (depth < 2) {
511*43a90889SApple OSS Distributions 		panic("HUH");
512*43a90889SApple OSS Distributions 	}
513*43a90889SApple OSS Distributions 	kperf_ast_set_callstack_depth(context->cur_thread, depth);
514*43a90889SApple OSS Distributions 	return kperf_ast_pend(context->cur_thread, T_KPERF_AST_CALLSTACK,
515*43a90889SApple OSS Distributions 	           actionid);
516*43a90889SApple OSS Distributions }
517*43a90889SApple OSS Distributions 
518*43a90889SApple OSS Distributions static kern_return_t
chudxnu_kern_read(void * dstaddr,vm_offset_t srcaddr,vm_size_t size)519*43a90889SApple OSS Distributions chudxnu_kern_read(void *dstaddr, vm_offset_t srcaddr, vm_size_t size)
520*43a90889SApple OSS Distributions {
521*43a90889SApple OSS Distributions 	return (ml_nofault_copy(srcaddr, (vm_offset_t)dstaddr, size) == size) ?
522*43a90889SApple OSS Distributions 	       KERN_SUCCESS : KERN_FAILURE;
523*43a90889SApple OSS Distributions }
524*43a90889SApple OSS Distributions 
525*43a90889SApple OSS Distributions static kern_return_t
chudxnu_task_read(task_t task,void * kernaddr,uint64_t usraddr,vm_size_t size)526*43a90889SApple OSS Distributions chudxnu_task_read(
527*43a90889SApple OSS Distributions 	task_t      task,
528*43a90889SApple OSS Distributions 	void        *kernaddr,
529*43a90889SApple OSS Distributions 	uint64_t    usraddr,
530*43a90889SApple OSS Distributions 	vm_size_t   size)
531*43a90889SApple OSS Distributions {
532*43a90889SApple OSS Distributions 	//ppc version ported to arm
533*43a90889SApple OSS Distributions 	kern_return_t ret = KERN_SUCCESS;
534*43a90889SApple OSS Distributions 
535*43a90889SApple OSS Distributions 	if (ml_at_interrupt_context()) {
536*43a90889SApple OSS Distributions 		return KERN_FAILURE;    // can't look at tasks on interrupt stack
537*43a90889SApple OSS Distributions 	}
538*43a90889SApple OSS Distributions 
539*43a90889SApple OSS Distributions 	if (current_task() == task) {
540*43a90889SApple OSS Distributions 		if (copyin(usraddr, kernaddr, size)) {
541*43a90889SApple OSS Distributions 			ret = KERN_FAILURE;
542*43a90889SApple OSS Distributions 		}
543*43a90889SApple OSS Distributions 	} else {
544*43a90889SApple OSS Distributions 		vm_map_t map = get_task_map(task);
545*43a90889SApple OSS Distributions 		ret = vm_map_read_user(map, usraddr, kernaddr, size);
546*43a90889SApple OSS Distributions 	}
547*43a90889SApple OSS Distributions 
548*43a90889SApple OSS Distributions 	return ret;
549*43a90889SApple OSS Distributions }
550*43a90889SApple OSS Distributions 
551*43a90889SApple OSS Distributions static inline uint64_t
chudxnu_vm_unslide(uint64_t ptr,int kaddr)552*43a90889SApple OSS Distributions chudxnu_vm_unslide( uint64_t ptr, int kaddr )
553*43a90889SApple OSS Distributions {
554*43a90889SApple OSS Distributions 	if (!kaddr) {
555*43a90889SApple OSS Distributions 		return ptr;
556*43a90889SApple OSS Distributions 	}
557*43a90889SApple OSS Distributions 
558*43a90889SApple OSS Distributions 	return VM_KERNEL_UNSLIDE(ptr);
559*43a90889SApple OSS Distributions }
560*43a90889SApple OSS Distributions 
561*43a90889SApple OSS Distributions #if __arm64__
562*43a90889SApple OSS Distributions 
563*43a90889SApple OSS Distributions #if defined(HAS_APPLE_PAC)
564*43a90889SApple OSS Distributions #include <ptrauth.h>
565*43a90889SApple OSS Distributions #endif
566*43a90889SApple OSS Distributions 
567*43a90889SApple OSS Distributions // chudxnu_thread_get_callstack gathers a raw callstack along with any information needed to
568*43a90889SApple OSS Distributions // fix it up later (in case we stopped program as it was saving values into prev stack frame, etc.)
569*43a90889SApple OSS Distributions // after sampling has finished.
570*43a90889SApple OSS Distributions //
571*43a90889SApple OSS Distributions // For an N-entry callstack:
572*43a90889SApple OSS Distributions //
573*43a90889SApple OSS Distributions // [0]      current pc
574*43a90889SApple OSS Distributions // [1..N-3] stack frames (including current one)
575*43a90889SApple OSS Distributions // [N-2]    current LR (return value if we're in a leaf function)
576*43a90889SApple OSS Distributions // [N-1]    current r0 (in case we've saved LR in r0) (optional)
577*43a90889SApple OSS Distributions //
578*43a90889SApple OSS Distributions //
579*43a90889SApple OSS Distributions #define CS_FLAG_EXTRASP  1  // capture extra sp register
580*43a90889SApple OSS Distributions 
581*43a90889SApple OSS Distributions static kern_return_t
chudxnu_thread_get_callstack64_internal(thread_t thread,uint64_t * callStack,mach_msg_type_number_t * count,boolean_t user_only,int flags)582*43a90889SApple OSS Distributions chudxnu_thread_get_callstack64_internal(
583*43a90889SApple OSS Distributions 	thread_t                thread,
584*43a90889SApple OSS Distributions 	uint64_t                *callStack,
585*43a90889SApple OSS Distributions 	mach_msg_type_number_t  *count,
586*43a90889SApple OSS Distributions 	boolean_t               user_only,
587*43a90889SApple OSS Distributions 	int flags)
588*43a90889SApple OSS Distributions {
589*43a90889SApple OSS Distributions 	kern_return_t   kr = KERN_SUCCESS;
590*43a90889SApple OSS Distributions 	task_t                  task;
591*43a90889SApple OSS Distributions 	uint64_t                currPC = 0ULL, currLR = 0ULL, currSP = 0ULL;
592*43a90889SApple OSS Distributions 	uint64_t                prevPC = 0ULL;
593*43a90889SApple OSS Distributions 	uint64_t                kernStackMin = thread->kernel_stack;
594*43a90889SApple OSS Distributions 	uint64_t                kernStackMax = kernStackMin + kernel_stack_size;
595*43a90889SApple OSS Distributions 	uint64_t       *buffer = callStack;
596*43a90889SApple OSS Distributions 	int             bufferIndex = 0;
597*43a90889SApple OSS Distributions 	int             bufferMaxIndex = 0;
598*43a90889SApple OSS Distributions 	boolean_t       kernel = FALSE;
599*43a90889SApple OSS Distributions 	struct arm_saved_state *sstate = NULL;
600*43a90889SApple OSS Distributions 	uint64_t                pc = 0ULL;
601*43a90889SApple OSS Distributions 
602*43a90889SApple OSS Distributions 	task = get_threadtask(thread);
603*43a90889SApple OSS Distributions 	bufferMaxIndex = *count;
604*43a90889SApple OSS Distributions 	//get thread state
605*43a90889SApple OSS Distributions 	if (user_only) {
606*43a90889SApple OSS Distributions 		sstate = find_user_regs(thread);
607*43a90889SApple OSS Distributions 	} else {
608*43a90889SApple OSS Distributions 		sstate = find_kern_regs(thread);
609*43a90889SApple OSS Distributions 	}
610*43a90889SApple OSS Distributions 
611*43a90889SApple OSS Distributions 	if (!sstate) {
612*43a90889SApple OSS Distributions 		*count = 0;
613*43a90889SApple OSS Distributions 		return KERN_FAILURE;
614*43a90889SApple OSS Distributions 	}
615*43a90889SApple OSS Distributions 
616*43a90889SApple OSS Distributions 	if (is_saved_state64(sstate)) {
617*43a90889SApple OSS Distributions 		struct arm_saved_state64 *state = NULL;
618*43a90889SApple OSS Distributions 		uint64_t *fp = NULL, *nextFramePointer = NULL, *topfp = NULL;
619*43a90889SApple OSS Distributions 		uint64_t frame[2];
620*43a90889SApple OSS Distributions 
621*43a90889SApple OSS Distributions 		state = saved_state64(sstate);
622*43a90889SApple OSS Distributions 
623*43a90889SApple OSS Distributions 		/* make sure it is safe to dereference before you do it */
624*43a90889SApple OSS Distributions 		kernel = PSR64_IS_KERNEL(state->cpsr);
625*43a90889SApple OSS Distributions 
626*43a90889SApple OSS Distributions 		/* can't take a kernel callstack if we've got a user frame */
627*43a90889SApple OSS Distributions 		if (!user_only && !kernel) {
628*43a90889SApple OSS Distributions 			return KERN_FAILURE;
629*43a90889SApple OSS Distributions 		}
630*43a90889SApple OSS Distributions 
631*43a90889SApple OSS Distributions 		/*
632*43a90889SApple OSS Distributions 		 * Reserve space for saving LR (and sometimes SP) at the end of the
633*43a90889SApple OSS Distributions 		 * backtrace.
634*43a90889SApple OSS Distributions 		 */
635*43a90889SApple OSS Distributions 		if (flags & CS_FLAG_EXTRASP) {
636*43a90889SApple OSS Distributions 			bufferMaxIndex -= 2;
637*43a90889SApple OSS Distributions 		} else {
638*43a90889SApple OSS Distributions 			bufferMaxIndex -= 1;
639*43a90889SApple OSS Distributions 		}
640*43a90889SApple OSS Distributions 
641*43a90889SApple OSS Distributions 		if (bufferMaxIndex < 2) {
642*43a90889SApple OSS Distributions 			*count = 0;
643*43a90889SApple OSS Distributions 			return KERN_RESOURCE_SHORTAGE;
644*43a90889SApple OSS Distributions 		}
645*43a90889SApple OSS Distributions 
646*43a90889SApple OSS Distributions 		currPC = state->pc;
647*43a90889SApple OSS Distributions 		currLR = state->lr;
648*43a90889SApple OSS Distributions 		currSP = state->sp;
649*43a90889SApple OSS Distributions 
650*43a90889SApple OSS Distributions 		fp = (uint64_t *)state->fp; /* frame pointer */
651*43a90889SApple OSS Distributions #if defined(HAS_APPLE_PAC)
652*43a90889SApple OSS Distributions 		/* frame pointers on stack will be signed by arm64e ABI */
653*43a90889SApple OSS Distributions 		fp = ptrauth_strip(fp, ptrauth_key_frame_pointer);
654*43a90889SApple OSS Distributions #endif
655*43a90889SApple OSS Distributions 		topfp = fp;
656*43a90889SApple OSS Distributions 
657*43a90889SApple OSS Distributions 		bufferIndex = 0;  // start with a stack of size zero
658*43a90889SApple OSS Distributions 		buffer[bufferIndex++] = chudxnu_vm_unslide(currPC, kernel); // save PC in position 0.
659*43a90889SApple OSS Distributions 
660*43a90889SApple OSS Distributions 		BUF_VERB(PERF_CS_BACKTRACE | DBG_FUNC_START, kernel, 0);
661*43a90889SApple OSS Distributions 
662*43a90889SApple OSS Distributions 		// Now, fill buffer with stack backtraces.
663*43a90889SApple OSS Distributions 		while (bufferIndex < bufferMaxIndex) {
664*43a90889SApple OSS Distributions 			pc = 0ULL;
665*43a90889SApple OSS Distributions 			/*
666*43a90889SApple OSS Distributions 			 * Below the frame pointer, the following values are saved:
667*43a90889SApple OSS Distributions 			 * -> FP
668*43a90889SApple OSS Distributions 			 */
669*43a90889SApple OSS Distributions 
670*43a90889SApple OSS Distributions 			/*
671*43a90889SApple OSS Distributions 			 * Note that we read the pc even for the first stack frame
672*43a90889SApple OSS Distributions 			 * (which, in theory, is always empty because the callee fills
673*43a90889SApple OSS Distributions 			 * it in just before it lowers the stack.  However, if we
674*43a90889SApple OSS Distributions 			 * catch the program in between filling in the return address
675*43a90889SApple OSS Distributions 			 * and lowering the stack, we want to still have a valid
676*43a90889SApple OSS Distributions 			 * backtrace. FixupStack correctly disregards this value if
677*43a90889SApple OSS Distributions 			 * necessary.
678*43a90889SApple OSS Distributions 			 */
679*43a90889SApple OSS Distributions 
680*43a90889SApple OSS Distributions 			if ((uint64_t)fp == 0 || ((uint64_t)fp & 0x3) != 0) {
681*43a90889SApple OSS Distributions 				/* frame pointer is invalid - stop backtracing */
682*43a90889SApple OSS Distributions 				pc = 0ULL;
683*43a90889SApple OSS Distributions 				break;
684*43a90889SApple OSS Distributions 			}
685*43a90889SApple OSS Distributions 
686*43a90889SApple OSS Distributions 			if (kernel) {
687*43a90889SApple OSS Distributions 				if (((uint64_t)fp > kernStackMax) ||
688*43a90889SApple OSS Distributions 				    ((uint64_t)fp < kernStackMin)) {
689*43a90889SApple OSS Distributions 					kr = KERN_FAILURE;
690*43a90889SApple OSS Distributions 				} else {
691*43a90889SApple OSS Distributions 					kr = chudxnu_kern_read(&frame,
692*43a90889SApple OSS Distributions 					    (vm_offset_t)fp,
693*43a90889SApple OSS Distributions 					    (vm_size_t)sizeof(frame));
694*43a90889SApple OSS Distributions 					if (kr == KERN_SUCCESS) {
695*43a90889SApple OSS Distributions #if defined(HAS_APPLE_PAC)
696*43a90889SApple OSS Distributions 						/* return addresses on stack will be signed by arm64e ABI */
697*43a90889SApple OSS Distributions 						pc = (uint64_t)ptrauth_strip((void *)frame[1], ptrauth_key_return_address);
698*43a90889SApple OSS Distributions #else
699*43a90889SApple OSS Distributions 						pc = frame[1];
700*43a90889SApple OSS Distributions #endif
701*43a90889SApple OSS Distributions 						nextFramePointer = (uint64_t *)frame[0];
702*43a90889SApple OSS Distributions #if defined(HAS_APPLE_PAC)
703*43a90889SApple OSS Distributions 						/* frame pointers on stack will be signed by arm64e ABI */
704*43a90889SApple OSS Distributions 						nextFramePointer = ptrauth_strip(nextFramePointer, ptrauth_key_frame_pointer);
705*43a90889SApple OSS Distributions #endif
706*43a90889SApple OSS Distributions 					} else {
707*43a90889SApple OSS Distributions 						pc = 0ULL;
708*43a90889SApple OSS Distributions 						nextFramePointer = 0ULL;
709*43a90889SApple OSS Distributions 						kr = KERN_FAILURE;
710*43a90889SApple OSS Distributions 					}
711*43a90889SApple OSS Distributions 				}
712*43a90889SApple OSS Distributions 			} else {
713*43a90889SApple OSS Distributions 				kr = chudxnu_task_read(task,
714*43a90889SApple OSS Distributions 				    &frame,
715*43a90889SApple OSS Distributions 				    (vm_offset_t)fp,
716*43a90889SApple OSS Distributions 				    (vm_size_t)sizeof(frame));
717*43a90889SApple OSS Distributions 				if (kr == KERN_SUCCESS) {
718*43a90889SApple OSS Distributions #if defined(HAS_APPLE_PAC)
719*43a90889SApple OSS Distributions 					/* return addresses on stack will be signed by arm64e ABI */
720*43a90889SApple OSS Distributions 					pc = (uint64_t)ptrauth_strip((void *)frame[1], ptrauth_key_return_address);
721*43a90889SApple OSS Distributions #else
722*43a90889SApple OSS Distributions 					pc = frame[1];
723*43a90889SApple OSS Distributions #endif
724*43a90889SApple OSS Distributions 					nextFramePointer = (uint64_t *)(frame[0]);
725*43a90889SApple OSS Distributions #if defined(HAS_APPLE_PAC)
726*43a90889SApple OSS Distributions 					/* frame pointers on stack will be signed by arm64e ABI */
727*43a90889SApple OSS Distributions 					nextFramePointer = ptrauth_strip(nextFramePointer, ptrauth_key_frame_pointer);
728*43a90889SApple OSS Distributions #endif
729*43a90889SApple OSS Distributions 				} else {
730*43a90889SApple OSS Distributions 					pc = 0ULL;
731*43a90889SApple OSS Distributions 					nextFramePointer = 0ULL;
732*43a90889SApple OSS Distributions 					kr = KERN_FAILURE;
733*43a90889SApple OSS Distributions 				}
734*43a90889SApple OSS Distributions 			}
735*43a90889SApple OSS Distributions 
736*43a90889SApple OSS Distributions 			if (kr != KERN_SUCCESS) {
737*43a90889SApple OSS Distributions 				pc = 0ULL;
738*43a90889SApple OSS Distributions 				break;
739*43a90889SApple OSS Distributions 			}
740*43a90889SApple OSS Distributions 
741*43a90889SApple OSS Distributions 			if (nextFramePointer) {
742*43a90889SApple OSS Distributions 				buffer[bufferIndex++] = chudxnu_vm_unslide(pc, kernel);
743*43a90889SApple OSS Distributions 				prevPC = pc;
744*43a90889SApple OSS Distributions 			}
745*43a90889SApple OSS Distributions 
746*43a90889SApple OSS Distributions 			if (nextFramePointer < fp) {
747*43a90889SApple OSS Distributions 				break;
748*43a90889SApple OSS Distributions 			} else {
749*43a90889SApple OSS Distributions 				fp = nextFramePointer;
750*43a90889SApple OSS Distributions 			}
751*43a90889SApple OSS Distributions 		}
752*43a90889SApple OSS Distributions 
753*43a90889SApple OSS Distributions 		BUF_VERB(PERF_CS_BACKTRACE | DBG_FUNC_END, bufferIndex);
754*43a90889SApple OSS Distributions 
755*43a90889SApple OSS Distributions 		if (bufferIndex >= bufferMaxIndex) {
756*43a90889SApple OSS Distributions 			bufferIndex = bufferMaxIndex;
757*43a90889SApple OSS Distributions 			kr = KERN_RESOURCE_SHORTAGE;
758*43a90889SApple OSS Distributions 		} else {
759*43a90889SApple OSS Distributions 			kr = KERN_SUCCESS;
760*43a90889SApple OSS Distributions 		}
761*43a90889SApple OSS Distributions 
762*43a90889SApple OSS Distributions 		// Save link register and SP at bottom of stack (used for later fixup).
763*43a90889SApple OSS Distributions 		buffer[bufferIndex++] = chudxnu_vm_unslide(currLR, kernel);
764*43a90889SApple OSS Distributions 		if (flags & CS_FLAG_EXTRASP) {
765*43a90889SApple OSS Distributions 			buffer[bufferIndex++] = chudxnu_vm_unslide(currSP, kernel);
766*43a90889SApple OSS Distributions 		}
767*43a90889SApple OSS Distributions 	} else {
768*43a90889SApple OSS Distributions 		struct arm_saved_state32 *state = NULL;
769*43a90889SApple OSS Distributions 		uint32_t *fp = NULL, *nextFramePointer = NULL, *topfp = NULL;
770*43a90889SApple OSS Distributions 
771*43a90889SApple OSS Distributions 		/* 64-bit kernel stacks, 32-bit user stacks */
772*43a90889SApple OSS Distributions 		uint64_t frame[2];
773*43a90889SApple OSS Distributions 		uint32_t frame32[2];
774*43a90889SApple OSS Distributions 
775*43a90889SApple OSS Distributions 		state = saved_state32(sstate);
776*43a90889SApple OSS Distributions 
777*43a90889SApple OSS Distributions 		/* make sure it is safe to dereference before you do it */
778*43a90889SApple OSS Distributions 		kernel = PSR_IS_KERNEL(state->cpsr);
779*43a90889SApple OSS Distributions 
780*43a90889SApple OSS Distributions 		/* can't take a kernel callstack if we've got a user frame */
781*43a90889SApple OSS Distributions 		if (!user_only && !kernel) {
782*43a90889SApple OSS Distributions 			return KERN_FAILURE;
783*43a90889SApple OSS Distributions 		}
784*43a90889SApple OSS Distributions 
785*43a90889SApple OSS Distributions 		/*
786*43a90889SApple OSS Distributions 		 * Reserve space for saving LR (and sometimes SP) at the end of the
787*43a90889SApple OSS Distributions 		 * backtrace.
788*43a90889SApple OSS Distributions 		 */
789*43a90889SApple OSS Distributions 		if (flags & CS_FLAG_EXTRASP) {
790*43a90889SApple OSS Distributions 			bufferMaxIndex -= 2;
791*43a90889SApple OSS Distributions 		} else {
792*43a90889SApple OSS Distributions 			bufferMaxIndex -= 1;
793*43a90889SApple OSS Distributions 		}
794*43a90889SApple OSS Distributions 
795*43a90889SApple OSS Distributions 		if (bufferMaxIndex < 2) {
796*43a90889SApple OSS Distributions 			*count = 0;
797*43a90889SApple OSS Distributions 			return KERN_RESOURCE_SHORTAGE;
798*43a90889SApple OSS Distributions 		}
799*43a90889SApple OSS Distributions 
800*43a90889SApple OSS Distributions 		currPC = (uint64_t)state->pc; /* r15 */
801*43a90889SApple OSS Distributions 		if (state->cpsr & PSR_TF) {
802*43a90889SApple OSS Distributions 			currPC |= 1ULL; /* encode thumb mode into low bit of PC */
803*43a90889SApple OSS Distributions 		}
804*43a90889SApple OSS Distributions 		currLR = (uint64_t)state->lr; /* r14 */
805*43a90889SApple OSS Distributions 		currSP = (uint64_t)state->sp; /* r13 */
806*43a90889SApple OSS Distributions 
807*43a90889SApple OSS Distributions 		fp = (uint32_t *)(uintptr_t)state->r[7]; /* frame pointer */
808*43a90889SApple OSS Distributions 		topfp = fp;
809*43a90889SApple OSS Distributions 
810*43a90889SApple OSS Distributions 		bufferIndex = 0;  // start with a stack of size zero
811*43a90889SApple OSS Distributions 		buffer[bufferIndex++] = chudxnu_vm_unslide(currPC, kernel); // save PC in position 0.
812*43a90889SApple OSS Distributions 
813*43a90889SApple OSS Distributions 		BUF_VERB(PERF_CS_BACKTRACE | DBG_FUNC_START, kernel, 1);
814*43a90889SApple OSS Distributions 
815*43a90889SApple OSS Distributions 		// Now, fill buffer with stack backtraces.
816*43a90889SApple OSS Distributions 		while (bufferIndex < bufferMaxIndex) {
817*43a90889SApple OSS Distributions 			pc = 0ULL;
818*43a90889SApple OSS Distributions 			/*
819*43a90889SApple OSS Distributions 			 * Below the frame pointer, the following values are saved:
820*43a90889SApple OSS Distributions 			 * -> FP
821*43a90889SApple OSS Distributions 			 */
822*43a90889SApple OSS Distributions 
823*43a90889SApple OSS Distributions 			/*
824*43a90889SApple OSS Distributions 			 * Note that we read the pc even for the first stack frame
825*43a90889SApple OSS Distributions 			 * (which, in theory, is always empty because the callee fills
826*43a90889SApple OSS Distributions 			 * it in just before it lowers the stack.  However, if we
827*43a90889SApple OSS Distributions 			 * catch the program in between filling in the return address
828*43a90889SApple OSS Distributions 			 * and lowering the stack, we want to still have a valid
829*43a90889SApple OSS Distributions 			 * backtrace. FixupStack correctly disregards this value if
830*43a90889SApple OSS Distributions 			 * necessary.
831*43a90889SApple OSS Distributions 			 */
832*43a90889SApple OSS Distributions 
833*43a90889SApple OSS Distributions 			if ((uint32_t)fp == 0 || ((uint32_t)fp & 0x3) != 0) {
834*43a90889SApple OSS Distributions 				/* frame pointer is invalid - stop backtracing */
835*43a90889SApple OSS Distributions 				pc = 0ULL;
836*43a90889SApple OSS Distributions 				break;
837*43a90889SApple OSS Distributions 			}
838*43a90889SApple OSS Distributions 
839*43a90889SApple OSS Distributions 			if (kernel) {
840*43a90889SApple OSS Distributions 				if (((uint32_t)fp > kernStackMax) ||
841*43a90889SApple OSS Distributions 				    ((uint32_t)fp < kernStackMin)) {
842*43a90889SApple OSS Distributions 					kr = KERN_FAILURE;
843*43a90889SApple OSS Distributions 				} else {
844*43a90889SApple OSS Distributions 					kr = chudxnu_kern_read(&frame,
845*43a90889SApple OSS Distributions 					    (vm_offset_t)fp,
846*43a90889SApple OSS Distributions 					    (vm_size_t)sizeof(frame));
847*43a90889SApple OSS Distributions 					if (kr == KERN_SUCCESS) {
848*43a90889SApple OSS Distributions 						pc = (uint64_t)frame[1];
849*43a90889SApple OSS Distributions 						nextFramePointer = (uint32_t *) (frame[0]);
850*43a90889SApple OSS Distributions 					} else {
851*43a90889SApple OSS Distributions 						pc = 0ULL;
852*43a90889SApple OSS Distributions 						nextFramePointer = 0ULL;
853*43a90889SApple OSS Distributions 						kr = KERN_FAILURE;
854*43a90889SApple OSS Distributions 					}
855*43a90889SApple OSS Distributions 				}
856*43a90889SApple OSS Distributions 			} else {
857*43a90889SApple OSS Distributions 				kr = chudxnu_task_read(task,
858*43a90889SApple OSS Distributions 				    &frame32,
859*43a90889SApple OSS Distributions 				    (((uint64_t)(uint32_t)fp) & 0x00000000FFFFFFFFULL),
860*43a90889SApple OSS Distributions 				    sizeof(frame32));
861*43a90889SApple OSS Distributions 				if (kr == KERN_SUCCESS) {
862*43a90889SApple OSS Distributions 					pc = (uint64_t)frame32[1];
863*43a90889SApple OSS Distributions 					nextFramePointer = (uint32_t *)(uintptr_t)(frame32[0]);
864*43a90889SApple OSS Distributions 				} else {
865*43a90889SApple OSS Distributions 					pc = 0ULL;
866*43a90889SApple OSS Distributions 					nextFramePointer = 0ULL;
867*43a90889SApple OSS Distributions 					kr = KERN_FAILURE;
868*43a90889SApple OSS Distributions 				}
869*43a90889SApple OSS Distributions 			}
870*43a90889SApple OSS Distributions 
871*43a90889SApple OSS Distributions 			if (kr != KERN_SUCCESS) {
872*43a90889SApple OSS Distributions 				pc = 0ULL;
873*43a90889SApple OSS Distributions 				break;
874*43a90889SApple OSS Distributions 			}
875*43a90889SApple OSS Distributions 
876*43a90889SApple OSS Distributions 			if (nextFramePointer) {
877*43a90889SApple OSS Distributions 				buffer[bufferIndex++] = chudxnu_vm_unslide(pc, kernel);
878*43a90889SApple OSS Distributions 				prevPC = pc;
879*43a90889SApple OSS Distributions 			}
880*43a90889SApple OSS Distributions 
881*43a90889SApple OSS Distributions 			if (nextFramePointer < fp) {
882*43a90889SApple OSS Distributions 				break;
883*43a90889SApple OSS Distributions 			} else {
884*43a90889SApple OSS Distributions 				fp = nextFramePointer;
885*43a90889SApple OSS Distributions 			}
886*43a90889SApple OSS Distributions 		}
887*43a90889SApple OSS Distributions 
888*43a90889SApple OSS Distributions 		BUF_VERB(PERF_CS_BACKTRACE | DBG_FUNC_END, bufferIndex);
889*43a90889SApple OSS Distributions 
890*43a90889SApple OSS Distributions 		/* clamp callstack size to max */
891*43a90889SApple OSS Distributions 		if (bufferIndex >= bufferMaxIndex) {
892*43a90889SApple OSS Distributions 			bufferIndex = bufferMaxIndex;
893*43a90889SApple OSS Distributions 			kr = KERN_RESOURCE_SHORTAGE;
894*43a90889SApple OSS Distributions 		} else {
895*43a90889SApple OSS Distributions 			/* ignore all other failures */
896*43a90889SApple OSS Distributions 			kr = KERN_SUCCESS;
897*43a90889SApple OSS Distributions 		}
898*43a90889SApple OSS Distributions 
899*43a90889SApple OSS Distributions 		// Save link register and R13 (sp) at bottom of stack (used for later fixup).
900*43a90889SApple OSS Distributions 		buffer[bufferIndex++] = chudxnu_vm_unslide(currLR, kernel);
901*43a90889SApple OSS Distributions 		if (flags & CS_FLAG_EXTRASP) {
902*43a90889SApple OSS Distributions 			buffer[bufferIndex++] = chudxnu_vm_unslide(currSP, kernel);
903*43a90889SApple OSS Distributions 		}
904*43a90889SApple OSS Distributions 	}
905*43a90889SApple OSS Distributions 
906*43a90889SApple OSS Distributions 	*count = bufferIndex;
907*43a90889SApple OSS Distributions 	return kr;
908*43a90889SApple OSS Distributions }
909*43a90889SApple OSS Distributions 
910*43a90889SApple OSS Distributions kern_return_t
chudxnu_thread_get_callstack64_kperf(thread_t thread,uint64_t * callStack,mach_msg_type_number_t * count,boolean_t user_only)911*43a90889SApple OSS Distributions chudxnu_thread_get_callstack64_kperf(
912*43a90889SApple OSS Distributions 	thread_t                thread,
913*43a90889SApple OSS Distributions 	uint64_t                *callStack,
914*43a90889SApple OSS Distributions 	mach_msg_type_number_t  *count,
915*43a90889SApple OSS Distributions 	boolean_t               user_only)
916*43a90889SApple OSS Distributions {
917*43a90889SApple OSS Distributions 	return chudxnu_thread_get_callstack64_internal( thread, callStack, count, user_only, 0 );
918*43a90889SApple OSS Distributions }
919*43a90889SApple OSS Distributions #elif __x86_64__
920*43a90889SApple OSS Distributions 
921*43a90889SApple OSS Distributions #define VALID_STACK_ADDRESS(supervisor, addr, minKernAddr, maxKernAddr)   (supervisor ? (addr>=minKernAddr && addr<=maxKernAddr) : TRUE)
922*43a90889SApple OSS Distributions // don't try to read in the hole
923*43a90889SApple OSS Distributions #define VALID_STACK_ADDRESS64(supervisor, addr, minKernAddr, maxKernAddr) \
924*43a90889SApple OSS Distributions (supervisor ? ((uint64_t)addr >= minKernAddr && (uint64_t)addr <= maxKernAddr) : \
925*43a90889SApple OSS Distributions ((uint64_t)addr != 0ULL && ((uint64_t)addr <= 0x00007FFFFFFFFFFFULL || (uint64_t)addr >= 0xFFFF800000000000ULL)))
926*43a90889SApple OSS Distributions 
927*43a90889SApple OSS Distributions typedef struct _cframe64_t {
928*43a90889SApple OSS Distributions 	uint64_t        prevFP;         // can't use a real pointer here until we're a 64 bit kernel
929*43a90889SApple OSS Distributions 	uint64_t        caller;
930*43a90889SApple OSS Distributions 	uint64_t        args[0];
931*43a90889SApple OSS Distributions }cframe64_t;
932*43a90889SApple OSS Distributions 
933*43a90889SApple OSS Distributions 
934*43a90889SApple OSS Distributions typedef struct _cframe_t {
935*43a90889SApple OSS Distributions 	uint32_t                prev;   // this is really a user32-space pointer to the previous frame
936*43a90889SApple OSS Distributions 	uint32_t                caller;
937*43a90889SApple OSS Distributions 	uint32_t                args[0];
938*43a90889SApple OSS Distributions } cframe_t;
939*43a90889SApple OSS Distributions 
940*43a90889SApple OSS Distributions extern void * find_user_regs(thread_t);
941*43a90889SApple OSS Distributions extern x86_saved_state32_t *find_kern_regs(thread_t);
942*43a90889SApple OSS Distributions 
943*43a90889SApple OSS Distributions static kern_return_t
do_kernel_backtrace(thread_t thread,struct x86_kernel_state * regs,uint64_t * frames,mach_msg_type_number_t * start_idx,mach_msg_type_number_t max_idx)944*43a90889SApple OSS Distributions do_kernel_backtrace(
945*43a90889SApple OSS Distributions 	thread_t thread,
946*43a90889SApple OSS Distributions 	struct x86_kernel_state *regs,
947*43a90889SApple OSS Distributions 	uint64_t *frames,
948*43a90889SApple OSS Distributions 	mach_msg_type_number_t *start_idx,
949*43a90889SApple OSS Distributions 	mach_msg_type_number_t max_idx)
950*43a90889SApple OSS Distributions {
951*43a90889SApple OSS Distributions 	uint64_t kernStackMin = (uint64_t)thread->kernel_stack;
952*43a90889SApple OSS Distributions 	uint64_t kernStackMax = (uint64_t)kernStackMin + kernel_stack_size;
953*43a90889SApple OSS Distributions 	mach_msg_type_number_t ct = *start_idx;
954*43a90889SApple OSS Distributions 	kern_return_t kr = KERN_FAILURE;
955*43a90889SApple OSS Distributions 
956*43a90889SApple OSS Distributions #if __LP64__
957*43a90889SApple OSS Distributions 	uint64_t currPC = 0ULL;
958*43a90889SApple OSS Distributions 	uint64_t currFP = 0ULL;
959*43a90889SApple OSS Distributions 	uint64_t prevPC = 0ULL;
960*43a90889SApple OSS Distributions 	uint64_t prevFP = 0ULL;
961*43a90889SApple OSS Distributions 	if (KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(regs->k_rip), sizeof(uint64_t))) {
962*43a90889SApple OSS Distributions 		return KERN_FAILURE;
963*43a90889SApple OSS Distributions 	}
964*43a90889SApple OSS Distributions 	if (KERN_SUCCESS != chudxnu_kern_read(&currFP, (vm_offset_t)&(regs->k_rbp), sizeof(uint64_t))) {
965*43a90889SApple OSS Distributions 		return KERN_FAILURE;
966*43a90889SApple OSS Distributions 	}
967*43a90889SApple OSS Distributions #else
968*43a90889SApple OSS Distributions 	uint32_t currPC = 0U;
969*43a90889SApple OSS Distributions 	uint32_t currFP = 0U;
970*43a90889SApple OSS Distributions 	uint32_t prevPC = 0U;
971*43a90889SApple OSS Distributions 	uint32_t prevFP = 0U;
972*43a90889SApple OSS Distributions 	if (KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(regs->k_eip), sizeof(uint32_t))) {
973*43a90889SApple OSS Distributions 		return KERN_FAILURE;
974*43a90889SApple OSS Distributions 	}
975*43a90889SApple OSS Distributions 	if (KERN_SUCCESS != chudxnu_kern_read(&currFP, (vm_offset_t)&(regs->k_ebp), sizeof(uint32_t))) {
976*43a90889SApple OSS Distributions 		return KERN_FAILURE;
977*43a90889SApple OSS Distributions 	}
978*43a90889SApple OSS Distributions #endif
979*43a90889SApple OSS Distributions 
980*43a90889SApple OSS Distributions 	if (*start_idx >= max_idx) {
981*43a90889SApple OSS Distributions 		return KERN_RESOURCE_SHORTAGE;  // no frames traced
982*43a90889SApple OSS Distributions 	}
983*43a90889SApple OSS Distributions 	if (!currPC) {
984*43a90889SApple OSS Distributions 		return KERN_FAILURE;
985*43a90889SApple OSS Distributions 	}
986*43a90889SApple OSS Distributions 
987*43a90889SApple OSS Distributions 	frames[ct++] = chudxnu_vm_unslide((uint64_t)currPC, 1);
988*43a90889SApple OSS Distributions 
989*43a90889SApple OSS Distributions 	// build a backtrace of this kernel state
990*43a90889SApple OSS Distributions #if __LP64__
991*43a90889SApple OSS Distributions 	while (VALID_STACK_ADDRESS64(TRUE, currFP, kernStackMin, kernStackMax)) {
992*43a90889SApple OSS Distributions 		// this is the address where caller lives in the user thread
993*43a90889SApple OSS Distributions 		uint64_t caller = currFP + sizeof(uint64_t);
994*43a90889SApple OSS Distributions #else
995*43a90889SApple OSS Distributions 	while (VALID_STACK_ADDRESS(TRUE, currFP, kernStackMin, kernStackMax)) {
996*43a90889SApple OSS Distributions 		uint32_t caller = (uint32_t)currFP + sizeof(uint32_t);
997*43a90889SApple OSS Distributions #endif
998*43a90889SApple OSS Distributions 
999*43a90889SApple OSS Distributions 		if (!currFP || !currPC) {
1000*43a90889SApple OSS Distributions 			currPC = 0;
1001*43a90889SApple OSS Distributions 			break;
1002*43a90889SApple OSS Distributions 		}
1003*43a90889SApple OSS Distributions 
1004*43a90889SApple OSS Distributions 		if (ct >= max_idx) {
1005*43a90889SApple OSS Distributions 			*start_idx = ct;
1006*43a90889SApple OSS Distributions 			return KERN_RESOURCE_SHORTAGE;
1007*43a90889SApple OSS Distributions 		}
1008*43a90889SApple OSS Distributions 
1009*43a90889SApple OSS Distributions 		/* read our caller */
1010*43a90889SApple OSS Distributions 		kr = chudxnu_kern_read(&currPC, (vm_offset_t)caller, sizeof(currPC));
1011*43a90889SApple OSS Distributions 
1012*43a90889SApple OSS Distributions 		if (kr != KERN_SUCCESS || !currPC) {
1013*43a90889SApple OSS Distributions 			currPC = 0UL;
1014*43a90889SApple OSS Distributions 			break;
1015*43a90889SApple OSS Distributions 		}
1016*43a90889SApple OSS Distributions 
1017*43a90889SApple OSS Distributions 		/*
1018*43a90889SApple OSS Distributions 		 * retrive contents of the frame pointer and advance to the next stack
1019*43a90889SApple OSS Distributions 		 * frame if it's valid
1020*43a90889SApple OSS Distributions 		 */
1021*43a90889SApple OSS Distributions 		prevFP = 0;
1022*43a90889SApple OSS Distributions 		kr = chudxnu_kern_read(&prevFP, (vm_offset_t)currFP, sizeof(currPC));
1023*43a90889SApple OSS Distributions 
1024*43a90889SApple OSS Distributions #if __LP64__
1025*43a90889SApple OSS Distributions 		if (VALID_STACK_ADDRESS64(TRUE, prevFP, kernStackMin, kernStackMax)) {
1026*43a90889SApple OSS Distributions #else
1027*43a90889SApple OSS Distributions 		if (VALID_STACK_ADDRESS(TRUE, prevFP, kernStackMin, kernStackMax)) {
1028*43a90889SApple OSS Distributions #endif
1029*43a90889SApple OSS Distributions 			frames[ct++] = chudxnu_vm_unslide((uint64_t)currPC, 1);
1030*43a90889SApple OSS Distributions 			prevPC = currPC;
1031*43a90889SApple OSS Distributions 		}
1032*43a90889SApple OSS Distributions 		if (prevFP <= currFP) {
1033*43a90889SApple OSS Distributions 			break;
1034*43a90889SApple OSS Distributions 		} else {
1035*43a90889SApple OSS Distributions 			currFP = prevFP;
1036*43a90889SApple OSS Distributions 		}
1037*43a90889SApple OSS Distributions 	}
1038*43a90889SApple OSS Distributions 
1039*43a90889SApple OSS Distributions 	*start_idx = ct;
1040*43a90889SApple OSS Distributions 	return KERN_SUCCESS;
1041*43a90889SApple OSS Distributions }
1042*43a90889SApple OSS Distributions 
1043*43a90889SApple OSS Distributions 
1044*43a90889SApple OSS Distributions 
1045*43a90889SApple OSS Distributions static kern_return_t
1046*43a90889SApple OSS Distributions do_backtrace32(
1047*43a90889SApple OSS Distributions 	task_t task,
1048*43a90889SApple OSS Distributions 	thread_t thread,
1049*43a90889SApple OSS Distributions 	x86_saved_state32_t *regs,
1050*43a90889SApple OSS Distributions 	uint64_t *frames,
1051*43a90889SApple OSS Distributions 	mach_msg_type_number_t *start_idx,
1052*43a90889SApple OSS Distributions 	mach_msg_type_number_t max_idx,
1053*43a90889SApple OSS Distributions 	boolean_t supervisor)
1054*43a90889SApple OSS Distributions {
1055*43a90889SApple OSS Distributions 	uint32_t tmpWord = 0UL;
1056*43a90889SApple OSS Distributions 	uint64_t currPC = (uint64_t) regs->eip;
1057*43a90889SApple OSS Distributions 	uint64_t currFP = (uint64_t) regs->ebp;
1058*43a90889SApple OSS Distributions 	uint64_t prevPC = 0ULL;
1059*43a90889SApple OSS Distributions 	uint64_t prevFP = 0ULL;
1060*43a90889SApple OSS Distributions 	uint64_t kernStackMin = thread->kernel_stack;
1061*43a90889SApple OSS Distributions 	uint64_t kernStackMax = kernStackMin + kernel_stack_size;
1062*43a90889SApple OSS Distributions 	mach_msg_type_number_t ct = *start_idx;
1063*43a90889SApple OSS Distributions 	kern_return_t kr = KERN_FAILURE;
1064*43a90889SApple OSS Distributions 
1065*43a90889SApple OSS Distributions 	if (ct >= max_idx) {
1066*43a90889SApple OSS Distributions 		return KERN_RESOURCE_SHORTAGE;  // no frames traced
1067*43a90889SApple OSS Distributions 	}
1068*43a90889SApple OSS Distributions 	frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
1069*43a90889SApple OSS Distributions 
1070*43a90889SApple OSS Distributions 	// build a backtrace of this 32 bit state.
1071*43a90889SApple OSS Distributions 	while (VALID_STACK_ADDRESS(supervisor, currFP, kernStackMin, kernStackMax)) {
1072*43a90889SApple OSS Distributions 		cframe_t *fp = (cframe_t *) (uintptr_t) currFP;
1073*43a90889SApple OSS Distributions 
1074*43a90889SApple OSS Distributions 		if (!currFP) {
1075*43a90889SApple OSS Distributions 			currPC = 0;
1076*43a90889SApple OSS Distributions 			break;
1077*43a90889SApple OSS Distributions 		}
1078*43a90889SApple OSS Distributions 
1079*43a90889SApple OSS Distributions 		if (ct >= max_idx) {
1080*43a90889SApple OSS Distributions 			*start_idx = ct;
1081*43a90889SApple OSS Distributions 			return KERN_RESOURCE_SHORTAGE;
1082*43a90889SApple OSS Distributions 		}
1083*43a90889SApple OSS Distributions 
1084*43a90889SApple OSS Distributions 		/* read our caller */
1085*43a90889SApple OSS Distributions 		if (supervisor) {
1086*43a90889SApple OSS Distributions 			kr = chudxnu_kern_read(&tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t));
1087*43a90889SApple OSS Distributions 		} else {
1088*43a90889SApple OSS Distributions 			kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t));
1089*43a90889SApple OSS Distributions 		}
1090*43a90889SApple OSS Distributions 
1091*43a90889SApple OSS Distributions 		if (kr != KERN_SUCCESS) {
1092*43a90889SApple OSS Distributions 			currPC = 0ULL;
1093*43a90889SApple OSS Distributions 			break;
1094*43a90889SApple OSS Distributions 		}
1095*43a90889SApple OSS Distributions 
1096*43a90889SApple OSS Distributions 		currPC = (uint64_t) tmpWord;    // promote 32 bit address
1097*43a90889SApple OSS Distributions 
1098*43a90889SApple OSS Distributions 		/*
1099*43a90889SApple OSS Distributions 		 * retrive contents of the frame pointer and advance to the next stack
1100*43a90889SApple OSS Distributions 		 * frame if it's valid
1101*43a90889SApple OSS Distributions 		 */
1102*43a90889SApple OSS Distributions 		prevFP = 0;
1103*43a90889SApple OSS Distributions 		if (supervisor) {
1104*43a90889SApple OSS Distributions 			kr = chudxnu_kern_read(&tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t));
1105*43a90889SApple OSS Distributions 		} else {
1106*43a90889SApple OSS Distributions 			kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t));
1107*43a90889SApple OSS Distributions 		}
1108*43a90889SApple OSS Distributions 		prevFP = (uint64_t) tmpWord;    // promote 32 bit address
1109*43a90889SApple OSS Distributions 
1110*43a90889SApple OSS Distributions 		if (prevFP) {
1111*43a90889SApple OSS Distributions 			frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
1112*43a90889SApple OSS Distributions 			prevPC = currPC;
1113*43a90889SApple OSS Distributions 		}
1114*43a90889SApple OSS Distributions 		if (prevFP < currFP) {
1115*43a90889SApple OSS Distributions 			break;
1116*43a90889SApple OSS Distributions 		} else {
1117*43a90889SApple OSS Distributions 			currFP = prevFP;
1118*43a90889SApple OSS Distributions 		}
1119*43a90889SApple OSS Distributions 	}
1120*43a90889SApple OSS Distributions 
1121*43a90889SApple OSS Distributions 	*start_idx = ct;
1122*43a90889SApple OSS Distributions 	return KERN_SUCCESS;
1123*43a90889SApple OSS Distributions }
1124*43a90889SApple OSS Distributions 
1125*43a90889SApple OSS Distributions static kern_return_t
1126*43a90889SApple OSS Distributions do_backtrace64(
1127*43a90889SApple OSS Distributions 	task_t task,
1128*43a90889SApple OSS Distributions 	thread_t thread,
1129*43a90889SApple OSS Distributions 	x86_saved_state64_t *regs,
1130*43a90889SApple OSS Distributions 	uint64_t *frames,
1131*43a90889SApple OSS Distributions 	mach_msg_type_number_t *start_idx,
1132*43a90889SApple OSS Distributions 	mach_msg_type_number_t max_idx,
1133*43a90889SApple OSS Distributions 	boolean_t supervisor)
1134*43a90889SApple OSS Distributions {
1135*43a90889SApple OSS Distributions 	uint64_t currPC = regs->isf.rip;
1136*43a90889SApple OSS Distributions 	uint64_t currFP = regs->rbp;
1137*43a90889SApple OSS Distributions 	uint64_t prevPC = 0ULL;
1138*43a90889SApple OSS Distributions 	uint64_t prevFP = 0ULL;
1139*43a90889SApple OSS Distributions 	uint64_t kernStackMin = (uint64_t)thread->kernel_stack;
1140*43a90889SApple OSS Distributions 	uint64_t kernStackMax = (uint64_t)kernStackMin + kernel_stack_size;
1141*43a90889SApple OSS Distributions 	mach_msg_type_number_t ct = *start_idx;
1142*43a90889SApple OSS Distributions 	kern_return_t kr = KERN_FAILURE;
1143*43a90889SApple OSS Distributions 
1144*43a90889SApple OSS Distributions 	if (*start_idx >= max_idx) {
1145*43a90889SApple OSS Distributions 		return KERN_RESOURCE_SHORTAGE;  // no frames traced
1146*43a90889SApple OSS Distributions 	}
1147*43a90889SApple OSS Distributions 	frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
1148*43a90889SApple OSS Distributions 
1149*43a90889SApple OSS Distributions 	// build a backtrace of this 32 bit state.
1150*43a90889SApple OSS Distributions 	while (VALID_STACK_ADDRESS64(supervisor, currFP, kernStackMin, kernStackMax)) {
1151*43a90889SApple OSS Distributions 		// this is the address where caller lives in the user thread
1152*43a90889SApple OSS Distributions 		uint64_t caller = currFP + sizeof(uint64_t);
1153*43a90889SApple OSS Distributions 
1154*43a90889SApple OSS Distributions 		if (!currFP) {
1155*43a90889SApple OSS Distributions 			currPC = 0;
1156*43a90889SApple OSS Distributions 			break;
1157*43a90889SApple OSS Distributions 		}
1158*43a90889SApple OSS Distributions 
1159*43a90889SApple OSS Distributions 		if (ct >= max_idx) {
1160*43a90889SApple OSS Distributions 			*start_idx = ct;
1161*43a90889SApple OSS Distributions 			return KERN_RESOURCE_SHORTAGE;
1162*43a90889SApple OSS Distributions 		}
1163*43a90889SApple OSS Distributions 
1164*43a90889SApple OSS Distributions 		/* read our caller */
1165*43a90889SApple OSS Distributions 		if (supervisor) {
1166*43a90889SApple OSS Distributions 			kr = chudxnu_kern_read(&currPC, (vm_offset_t)caller, sizeof(uint64_t));
1167*43a90889SApple OSS Distributions 		} else {
1168*43a90889SApple OSS Distributions 			kr = chudxnu_task_read(task, &currPC, caller, sizeof(uint64_t));
1169*43a90889SApple OSS Distributions 		}
1170*43a90889SApple OSS Distributions 
1171*43a90889SApple OSS Distributions 		if (kr != KERN_SUCCESS) {
1172*43a90889SApple OSS Distributions 			currPC = 0ULL;
1173*43a90889SApple OSS Distributions 			break;
1174*43a90889SApple OSS Distributions 		}
1175*43a90889SApple OSS Distributions 
1176*43a90889SApple OSS Distributions 		/*
1177*43a90889SApple OSS Distributions 		 * retrive contents of the frame pointer and advance to the next stack
1178*43a90889SApple OSS Distributions 		 * frame if it's valid
1179*43a90889SApple OSS Distributions 		 */
1180*43a90889SApple OSS Distributions 		prevFP = 0;
1181*43a90889SApple OSS Distributions 		if (supervisor) {
1182*43a90889SApple OSS Distributions 			kr = chudxnu_kern_read(&prevFP, (vm_offset_t)currFP, sizeof(uint64_t));
1183*43a90889SApple OSS Distributions 		} else {
1184*43a90889SApple OSS Distributions 			kr = chudxnu_task_read(task, &prevFP, currFP, sizeof(uint64_t));
1185*43a90889SApple OSS Distributions 		}
1186*43a90889SApple OSS Distributions 
1187*43a90889SApple OSS Distributions 		if (VALID_STACK_ADDRESS64(supervisor, prevFP, kernStackMin, kernStackMax)) {
1188*43a90889SApple OSS Distributions 			frames[ct++] = chudxnu_vm_unslide(currPC, supervisor);
1189*43a90889SApple OSS Distributions 			prevPC = currPC;
1190*43a90889SApple OSS Distributions 		}
1191*43a90889SApple OSS Distributions 		if (prevFP < currFP) {
1192*43a90889SApple OSS Distributions 			break;
1193*43a90889SApple OSS Distributions 		} else {
1194*43a90889SApple OSS Distributions 			currFP = prevFP;
1195*43a90889SApple OSS Distributions 		}
1196*43a90889SApple OSS Distributions 	}
1197*43a90889SApple OSS Distributions 
1198*43a90889SApple OSS Distributions 	*start_idx = ct;
1199*43a90889SApple OSS Distributions 	return KERN_SUCCESS;
1200*43a90889SApple OSS Distributions }
1201*43a90889SApple OSS Distributions 
1202*43a90889SApple OSS Distributions static kern_return_t
1203*43a90889SApple OSS Distributions chudxnu_thread_get_callstack64_internal(
1204*43a90889SApple OSS Distributions 	thread_t                thread,
1205*43a90889SApple OSS Distributions 	uint64_t                *callstack,
1206*43a90889SApple OSS Distributions 	mach_msg_type_number_t  *count,
1207*43a90889SApple OSS Distributions 	boolean_t               user_only,
1208*43a90889SApple OSS Distributions 	boolean_t               kern_only)
1209*43a90889SApple OSS Distributions {
1210*43a90889SApple OSS Distributions 	kern_return_t kr = KERN_FAILURE;
1211*43a90889SApple OSS Distributions 	task_t task = get_threadtask(thread);
1212*43a90889SApple OSS Distributions 	uint64_t currPC = 0ULL;
1213*43a90889SApple OSS Distributions 	boolean_t supervisor = FALSE;
1214*43a90889SApple OSS Distributions 	mach_msg_type_number_t bufferIndex = 0;
1215*43a90889SApple OSS Distributions 	mach_msg_type_number_t bufferMaxIndex = *count;
1216*43a90889SApple OSS Distributions 	x86_saved_state_t *tagged_regs = NULL;          // kernel register state
1217*43a90889SApple OSS Distributions 	x86_saved_state64_t *regs64 = NULL;
1218*43a90889SApple OSS Distributions 	x86_saved_state32_t *regs32 = NULL;
1219*43a90889SApple OSS Distributions 	x86_saved_state32_t *u_regs32 = NULL;
1220*43a90889SApple OSS Distributions 	x86_saved_state64_t *u_regs64 = NULL;
1221*43a90889SApple OSS Distributions 	struct x86_kernel_state *kregs = NULL;
1222*43a90889SApple OSS Distributions 
1223*43a90889SApple OSS Distributions 	if (ml_at_interrupt_context()) {
1224*43a90889SApple OSS Distributions 		if (user_only) {
1225*43a90889SApple OSS Distributions 			/* can't backtrace user state on interrupt stack. */
1226*43a90889SApple OSS Distributions 			return KERN_FAILURE;
1227*43a90889SApple OSS Distributions 		}
1228*43a90889SApple OSS Distributions 
1229*43a90889SApple OSS Distributions 		/* backtracing at interrupt context? */
1230*43a90889SApple OSS Distributions 		if (thread == current_thread() && current_cpu_datap()->cpu_int_state) {
1231*43a90889SApple OSS Distributions 			/*
1232*43a90889SApple OSS Distributions 			 * Locate the registers for the interrupted thread, assuming it is
1233*43a90889SApple OSS Distributions 			 * current_thread().
1234*43a90889SApple OSS Distributions 			 */
1235*43a90889SApple OSS Distributions 			tagged_regs = current_cpu_datap()->cpu_int_state;
1236*43a90889SApple OSS Distributions 
1237*43a90889SApple OSS Distributions 			if (is_saved_state64(tagged_regs)) {
1238*43a90889SApple OSS Distributions 				/* 64 bit registers */
1239*43a90889SApple OSS Distributions 				regs64 = saved_state64(tagged_regs);
1240*43a90889SApple OSS Distributions 				supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U);
1241*43a90889SApple OSS Distributions 			} else {
1242*43a90889SApple OSS Distributions 				/* 32 bit registers */
1243*43a90889SApple OSS Distributions 				regs32 = saved_state32(tagged_regs);
1244*43a90889SApple OSS Distributions 				supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U);
1245*43a90889SApple OSS Distributions 			}
1246*43a90889SApple OSS Distributions 		}
1247*43a90889SApple OSS Distributions 	}
1248*43a90889SApple OSS Distributions 
1249*43a90889SApple OSS Distributions 	if (!ml_at_interrupt_context() && kernel_task == task) {
1250*43a90889SApple OSS Distributions 		if (!thread->kernel_stack) {
1251*43a90889SApple OSS Distributions 			return KERN_FAILURE;
1252*43a90889SApple OSS Distributions 		}
1253*43a90889SApple OSS Distributions 
1254*43a90889SApple OSS Distributions 		// Kernel thread not at interrupt context
1255*43a90889SApple OSS Distributions 		kregs = (struct x86_kernel_state *)NULL;
1256*43a90889SApple OSS Distributions 
1257*43a90889SApple OSS Distributions 		// nofault read of the thread->kernel_stack pointer
1258*43a90889SApple OSS Distributions 		if (KERN_SUCCESS != chudxnu_kern_read(&kregs, (vm_offset_t)&(thread->kernel_stack), sizeof(void *))) {
1259*43a90889SApple OSS Distributions 			return KERN_FAILURE;
1260*43a90889SApple OSS Distributions 		}
1261*43a90889SApple OSS Distributions 
1262*43a90889SApple OSS Distributions 		// Adjust to find the saved kernel state
1263*43a90889SApple OSS Distributions 		kregs = STACK_IKS((vm_offset_t)(uintptr_t)kregs);
1264*43a90889SApple OSS Distributions 
1265*43a90889SApple OSS Distributions 		supervisor = TRUE;
1266*43a90889SApple OSS Distributions 	} else if (!tagged_regs) {
1267*43a90889SApple OSS Distributions 		/*
1268*43a90889SApple OSS Distributions 		 * not at interrupt context, or tracing a different thread than
1269*43a90889SApple OSS Distributions 		 * current_thread() at interrupt context
1270*43a90889SApple OSS Distributions 		 */
1271*43a90889SApple OSS Distributions 		tagged_regs = USER_STATE(thread);
1272*43a90889SApple OSS Distributions 		if (is_saved_state64(tagged_regs)) {
1273*43a90889SApple OSS Distributions 			/* 64 bit registers */
1274*43a90889SApple OSS Distributions 			regs64 = saved_state64(tagged_regs);
1275*43a90889SApple OSS Distributions 			supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U);
1276*43a90889SApple OSS Distributions 		} else {
1277*43a90889SApple OSS Distributions 			/* 32 bit registers */
1278*43a90889SApple OSS Distributions 			regs32 = saved_state32(tagged_regs);
1279*43a90889SApple OSS Distributions 			supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U);
1280*43a90889SApple OSS Distributions 		}
1281*43a90889SApple OSS Distributions 	}
1282*43a90889SApple OSS Distributions 
1283*43a90889SApple OSS Distributions 	*count = 0;
1284*43a90889SApple OSS Distributions 
1285*43a90889SApple OSS Distributions 	if (supervisor) {
1286*43a90889SApple OSS Distributions 		// the caller only wants a user callstack.
1287*43a90889SApple OSS Distributions 		if (user_only) {
1288*43a90889SApple OSS Distributions 			// bail - we've only got kernel state
1289*43a90889SApple OSS Distributions 			return KERN_FAILURE;
1290*43a90889SApple OSS Distributions 		}
1291*43a90889SApple OSS Distributions 	} else {
1292*43a90889SApple OSS Distributions 		// regs32(64) is not in supervisor mode.
1293*43a90889SApple OSS Distributions 		u_regs32 = regs32;
1294*43a90889SApple OSS Distributions 		u_regs64 = regs64;
1295*43a90889SApple OSS Distributions 		regs32 = NULL;
1296*43a90889SApple OSS Distributions 		regs64 = NULL;
1297*43a90889SApple OSS Distributions 	}
1298*43a90889SApple OSS Distributions 
1299*43a90889SApple OSS Distributions 	if (user_only) {
1300*43a90889SApple OSS Distributions 		/* we only want to backtrace the user mode */
1301*43a90889SApple OSS Distributions 		if (!(u_regs32 || u_regs64)) {
1302*43a90889SApple OSS Distributions 			/* no user state to look at */
1303*43a90889SApple OSS Distributions 			return KERN_FAILURE;
1304*43a90889SApple OSS Distributions 		}
1305*43a90889SApple OSS Distributions 	}
1306*43a90889SApple OSS Distributions 
1307*43a90889SApple OSS Distributions 	/*
1308*43a90889SApple OSS Distributions 	 * Order of preference for top of stack:
1309*43a90889SApple OSS Distributions 	 * 64 bit kernel state (not likely)
1310*43a90889SApple OSS Distributions 	 * 32 bit kernel state
1311*43a90889SApple OSS Distributions 	 * 64 bit user land state
1312*43a90889SApple OSS Distributions 	 * 32 bit user land state
1313*43a90889SApple OSS Distributions 	 */
1314*43a90889SApple OSS Distributions 
1315*43a90889SApple OSS Distributions 	if (kregs) {
1316*43a90889SApple OSS Distributions 		/*
1317*43a90889SApple OSS Distributions 		 * nofault read of the registers from the kernel stack (as they can
1318*43a90889SApple OSS Distributions 		 * disappear on the fly).
1319*43a90889SApple OSS Distributions 		 */
1320*43a90889SApple OSS Distributions 
1321*43a90889SApple OSS Distributions 		if (KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(kregs->k_rip), sizeof(uint64_t))) {
1322*43a90889SApple OSS Distributions 			return KERN_FAILURE;
1323*43a90889SApple OSS Distributions 		}
1324*43a90889SApple OSS Distributions 	} else if (regs64) {
1325*43a90889SApple OSS Distributions 		currPC = regs64->isf.rip;
1326*43a90889SApple OSS Distributions 	} else if (regs32) {
1327*43a90889SApple OSS Distributions 		currPC = (uint64_t) regs32->eip;
1328*43a90889SApple OSS Distributions 	} else if (u_regs64) {
1329*43a90889SApple OSS Distributions 		currPC = u_regs64->isf.rip;
1330*43a90889SApple OSS Distributions 	} else if (u_regs32) {
1331*43a90889SApple OSS Distributions 		currPC = (uint64_t) u_regs32->eip;
1332*43a90889SApple OSS Distributions 	}
1333*43a90889SApple OSS Distributions 
1334*43a90889SApple OSS Distributions 	if (!currPC) {
1335*43a90889SApple OSS Distributions 		/* no top of the stack, bail out */
1336*43a90889SApple OSS Distributions 		return KERN_FAILURE;
1337*43a90889SApple OSS Distributions 	}
1338*43a90889SApple OSS Distributions 
1339*43a90889SApple OSS Distributions 	bufferIndex = 0;
1340*43a90889SApple OSS Distributions 
1341*43a90889SApple OSS Distributions 	if (bufferMaxIndex < 1) {
1342*43a90889SApple OSS Distributions 		*count = 0;
1343*43a90889SApple OSS Distributions 		return KERN_RESOURCE_SHORTAGE;
1344*43a90889SApple OSS Distributions 	}
1345*43a90889SApple OSS Distributions 
1346*43a90889SApple OSS Distributions 	/* backtrace kernel */
1347*43a90889SApple OSS Distributions 	if (kregs) {
1348*43a90889SApple OSS Distributions 		addr64_t address = 0ULL;
1349*43a90889SApple OSS Distributions 		size_t size = 0UL;
1350*43a90889SApple OSS Distributions 
1351*43a90889SApple OSS Distributions 		// do the backtrace
1352*43a90889SApple OSS Distributions 		kr = do_kernel_backtrace(thread, kregs, callstack, &bufferIndex, bufferMaxIndex);
1353*43a90889SApple OSS Distributions 
1354*43a90889SApple OSS Distributions 		// and do a nofault read of (r|e)sp
1355*43a90889SApple OSS Distributions 		uint64_t rsp = 0ULL;
1356*43a90889SApple OSS Distributions 		size = sizeof(uint64_t);
1357*43a90889SApple OSS Distributions 
1358*43a90889SApple OSS Distributions 		if (KERN_SUCCESS != chudxnu_kern_read(&address, (vm_offset_t)&(kregs->k_rsp), size)) {
1359*43a90889SApple OSS Distributions 			address = 0ULL;
1360*43a90889SApple OSS Distributions 		}
1361*43a90889SApple OSS Distributions 
1362*43a90889SApple OSS Distributions 		if (address && KERN_SUCCESS == chudxnu_kern_read(&rsp, (vm_offset_t)address, size) && bufferIndex < bufferMaxIndex) {
1363*43a90889SApple OSS Distributions 			callstack[bufferIndex++] = (uint64_t)rsp;
1364*43a90889SApple OSS Distributions 		}
1365*43a90889SApple OSS Distributions 	} else if (regs64) {
1366*43a90889SApple OSS Distributions 		uint64_t rsp = 0ULL;
1367*43a90889SApple OSS Distributions 
1368*43a90889SApple OSS Distributions 		// backtrace the 64bit side.
1369*43a90889SApple OSS Distributions 		kr = do_backtrace64(task, thread, regs64, callstack, &bufferIndex,
1370*43a90889SApple OSS Distributions 		    bufferMaxIndex - 1, TRUE);
1371*43a90889SApple OSS Distributions 
1372*43a90889SApple OSS Distributions 		if (KERN_SUCCESS == chudxnu_kern_read(&rsp, (vm_offset_t) regs64->isf.rsp, sizeof(uint64_t)) &&
1373*43a90889SApple OSS Distributions 		    bufferIndex < bufferMaxIndex) {
1374*43a90889SApple OSS Distributions 			callstack[bufferIndex++] = rsp;
1375*43a90889SApple OSS Distributions 		}
1376*43a90889SApple OSS Distributions 	} else if (regs32) {
1377*43a90889SApple OSS Distributions 		uint32_t esp = 0UL;
1378*43a90889SApple OSS Distributions 
1379*43a90889SApple OSS Distributions 		// backtrace the 32bit side.
1380*43a90889SApple OSS Distributions 		kr = do_backtrace32(task, thread, regs32, callstack, &bufferIndex,
1381*43a90889SApple OSS Distributions 		    bufferMaxIndex - 1, TRUE);
1382*43a90889SApple OSS Distributions 
1383*43a90889SApple OSS Distributions 		if (KERN_SUCCESS == chudxnu_kern_read(&esp, (vm_offset_t) regs32->uesp, sizeof(uint32_t)) &&
1384*43a90889SApple OSS Distributions 		    bufferIndex < bufferMaxIndex) {
1385*43a90889SApple OSS Distributions 			callstack[bufferIndex++] = (uint64_t) esp;
1386*43a90889SApple OSS Distributions 		}
1387*43a90889SApple OSS Distributions 	} else if (u_regs64 && !kern_only) {
1388*43a90889SApple OSS Distributions 		/* backtrace user land */
1389*43a90889SApple OSS Distributions 		uint64_t rsp = 0ULL;
1390*43a90889SApple OSS Distributions 
1391*43a90889SApple OSS Distributions 		kr = do_backtrace64(task, thread, u_regs64, callstack, &bufferIndex,
1392*43a90889SApple OSS Distributions 		    bufferMaxIndex - 1, FALSE);
1393*43a90889SApple OSS Distributions 
1394*43a90889SApple OSS Distributions 		if (KERN_SUCCESS == chudxnu_task_read(task, &rsp, (addr64_t) u_regs64->isf.rsp, sizeof(uint64_t)) &&
1395*43a90889SApple OSS Distributions 		    bufferIndex < bufferMaxIndex) {
1396*43a90889SApple OSS Distributions 			callstack[bufferIndex++] = rsp;
1397*43a90889SApple OSS Distributions 		}
1398*43a90889SApple OSS Distributions 	} else if (u_regs32 && !kern_only) {
1399*43a90889SApple OSS Distributions 		uint32_t esp = 0UL;
1400*43a90889SApple OSS Distributions 
1401*43a90889SApple OSS Distributions 		kr = do_backtrace32(task, thread, u_regs32, callstack, &bufferIndex,
1402*43a90889SApple OSS Distributions 		    bufferMaxIndex - 1, FALSE);
1403*43a90889SApple OSS Distributions 
1404*43a90889SApple OSS Distributions 		if (KERN_SUCCESS == chudxnu_task_read(task, &esp, (addr64_t) u_regs32->uesp, sizeof(uint32_t)) &&
1405*43a90889SApple OSS Distributions 		    bufferIndex < bufferMaxIndex) {
1406*43a90889SApple OSS Distributions 			callstack[bufferIndex++] = (uint64_t) esp;
1407*43a90889SApple OSS Distributions 		}
1408*43a90889SApple OSS Distributions 	}
1409*43a90889SApple OSS Distributions 
1410*43a90889SApple OSS Distributions 	*count = bufferIndex;
1411*43a90889SApple OSS Distributions 	return kr;
1412*43a90889SApple OSS Distributions }
1413*43a90889SApple OSS Distributions 
1414*43a90889SApple OSS Distributions __private_extern__
1415*43a90889SApple OSS Distributions kern_return_t
1416*43a90889SApple OSS Distributions chudxnu_thread_get_callstack64_kperf(
1417*43a90889SApple OSS Distributions 	thread_t                thread,
1418*43a90889SApple OSS Distributions 	uint64_t                *callstack,
1419*43a90889SApple OSS Distributions 	mach_msg_type_number_t  *count,
1420*43a90889SApple OSS Distributions 	boolean_t               is_user)
1421*43a90889SApple OSS Distributions {
1422*43a90889SApple OSS Distributions 	return chudxnu_thread_get_callstack64_internal(thread, callstack, count, is_user, !is_user);
1423*43a90889SApple OSS Distributions }
1424*43a90889SApple OSS Distributions #else /* !__arm64__ && !__x86_64__ */
1425*43a90889SApple OSS Distributions #error kperf: unsupported architecture
1426*43a90889SApple OSS Distributions #endif /* !__arm64__ && !__x86_64__ */
1427