]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/backtrace.c
xnu-6153.121.1.tar.gz
[apple/xnu.git] / osfmk / kern / backtrace.c
CommitLineData
39037602
A
1/*
2 * Copyright (c) 2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <stddef.h>
30#include <stdint.h>
31
32#include <kern/assert.h>
33#include <kern/backtrace.h>
34#include <kern/thread.h>
35#include <sys/errno.h>
36#include <vm/vm_map.h>
37
5ba3f43e
A
38#if defined(__arm__) || defined(__arm64__)
39#include <arm/cpu_data.h>
40#include <arm/cpu_data_internal.h>
41#endif
42
cb323159
A
43#if defined(HAS_APPLE_PAC)
44#include <ptrauth.h>
45#endif
39037602 46
d9a64523 47
cb323159
A
48unsigned int __attribute__((noinline))
49backtrace(uintptr_t *bt, unsigned int max_frames, bool *was_truncated_out)
39037602 50{
cb323159
A
51 return backtrace_frame(bt, max_frames, __builtin_frame_address(0),
52 was_truncated_out);
39037602
A
53}
54
55/*
56 * This function captures a backtrace from the current stack and returns the
57 * number of frames captured, limited by max_frames and starting at start_frame.
58 * It's fast because it does no checking to make sure there isn't bad data.
59 * Since it's only called from threads that we're going to keep executing,
60 * if there's bad data we were going to die eventually. If this function is
61 * inlined, it doesn't record the frame of the function it's inside (because
62 * there's no stack frame).
63 */
cb323159
A
64unsigned int __attribute__((noinline, not_tail_called))
65backtrace_frame(uintptr_t *bt, unsigned int max_frames, void *start_frame,
66 bool *was_truncated_out)
39037602
A
67{
68 thread_t thread = current_thread();
69 uintptr_t *fp;
cb323159 70 unsigned int frame_index = 0;
39037602 71 uintptr_t top, bottom;
5ba3f43e 72 bool in_valid_stack;
39037602
A
73
74 assert(bt != NULL);
75 assert(max_frames > 0);
76
77 fp = start_frame;
78 bottom = thread->kernel_stack;
79 top = bottom + kernel_stack_size;
80
5ba3f43e
A
81#define IN_STK_BOUNDS(__addr) \
82 (((uintptr_t)(__addr) >= (uintptr_t)bottom) && \
83 ((uintptr_t)(__addr) < (uintptr_t)top))
84
85 in_valid_stack = IN_STK_BOUNDS(fp);
86
87 if (!in_valid_stack) {
39037602
A
88 fp = NULL;
89 }
90
91 while (fp != NULL && frame_index < max_frames) {
5ba3f43e 92 uintptr_t *next_fp = (uintptr_t *)*fp;
d9a64523 93 uintptr_t ret_addr = *(fp + 1); /* return address is one word higher than frame pointer */
39037602
A
94
95 /*
96 * If the frame pointer is 0, backtracing has reached the top of
97 * the stack and there is no return address. Some stacks might not
98 * have set this up, so bounds check, as well.
99 */
5ba3f43e
A
100 in_valid_stack = IN_STK_BOUNDS(next_fp);
101
0a7de745 102 if (next_fp == NULL || !in_valid_stack) {
39037602
A
103 break;
104 }
105
cb323159
A
106#if defined(HAS_APPLE_PAC)
107 /* return addresses signed by arm64e ABI */
108 bt[frame_index++] = (uintptr_t) ptrauth_strip((void *)ret_addr, ptrauth_key_return_address);
109#else /* defined(HAS_APPLE_PAC) */
d9a64523 110 bt[frame_index++] = ret_addr;
cb323159 111#endif /* !defined(HAS_APPLE_PAC) */
39037602
A
112
113 /* stacks grow down; backtracing should be moving to higher addresses */
114 if (next_fp <= fp) {
115 break;
116 }
117 fp = next_fp;
118 }
119
cb323159
A
120 /* NULL-terminate the list, if space is available */
121 if (frame_index != max_frames) {
122 bt[frame_index] = 0;
123 }
124
125 if (fp != NULL && frame_index == max_frames && was_truncated_out) {
126 *was_truncated_out = true;
127 }
128
39037602 129 return frame_index;
5ba3f43e 130#undef IN_STK_BOUNDS
39037602
A
131}
132
133#if defined(__x86_64__)
134
135static kern_return_t
136interrupted_kernel_pc_fp(uintptr_t *pc, uintptr_t *fp)
137{
138 x86_saved_state_t *state;
139 bool state_64;
140 uint64_t cs;
141
142 state = current_cpu_datap()->cpu_int_state;
143 if (!state) {
144 return KERN_FAILURE;
145 }
146
147 state_64 = is_saved_state64(state);
148
149 if (state_64) {
150 cs = saved_state64(state)->isf.cs;
151 } else {
152 cs = saved_state32(state)->cs;
153 }
154 /* return early if interrupted a thread in user space */
155 if ((cs & SEL_PL) == SEL_PL_U) {
156 return KERN_FAILURE;
157 }
158
159 if (state_64) {
160 *pc = saved_state64(state)->isf.rip;
161 *fp = saved_state64(state)->rbp;
162 } else {
163 *pc = saved_state32(state)->eip;
164 *fp = saved_state32(state)->ebp;
165 }
166 return KERN_SUCCESS;
167}
168
5ba3f43e
A
169#elif defined(__arm64__)
170
171static kern_return_t
172interrupted_kernel_pc_fp(uintptr_t *pc, uintptr_t *fp)
173{
174 struct arm_saved_state *state;
175 bool state_64;
176
177 state = getCpuDatap()->cpu_int_state;
178 if (!state) {
179 return KERN_FAILURE;
180 }
181 state_64 = is_saved_state64(state);
182
183 /* return early if interrupted a thread in user space */
184 if (PSR64_IS_USER(get_saved_state_cpsr(state))) {
185 return KERN_FAILURE;
186 }
187
188 *pc = get_saved_state_pc(state);
189 *fp = get_saved_state_fp(state);
190 return KERN_SUCCESS;
191}
192
193#elif defined(__arm__)
194
195static kern_return_t
196interrupted_kernel_pc_fp(uintptr_t *pc, uintptr_t *fp)
197{
198 struct arm_saved_state *state;
199
200 state = getCpuDatap()->cpu_int_state;
201 if (!state) {
202 return KERN_FAILURE;
203 }
204
205 /* return early if interrupted a thread in user space */
206 if (PSR_IS_USER(get_saved_state_cpsr(state))) {
207 return KERN_FAILURE;
208 }
209
210 *pc = get_saved_state_pc(state);
211 *fp = get_saved_state_fp(state);
212 return KERN_SUCCESS;
213}
214
39037602
A
215#else /* defined(__arm__) */
216#error "interrupted_kernel_pc_fp: unsupported architecture"
217#endif /* !defined(__arm__) */
218
cb323159
A
219unsigned int
220backtrace_interrupted(uintptr_t *bt, unsigned int max_frames,
221 bool *was_truncated_out)
39037602
A
222{
223 uintptr_t pc;
5ba3f43e 224 uintptr_t fp;
39037602
A
225 kern_return_t kr;
226
227 assert(bt != NULL);
228 assert(max_frames > 0);
229 assert(ml_at_interrupt_context() == TRUE);
230
5ba3f43e 231 kr = interrupted_kernel_pc_fp(&pc, &fp);
39037602
A
232 if (kr != KERN_SUCCESS) {
233 return 0;
234 }
235
236 bt[0] = pc;
237 if (max_frames == 1) {
238 return 1;
239 }
240
cb323159
A
241 return backtrace_frame(bt + 1, max_frames - 1, (void *)fp,
242 was_truncated_out) + 1;
39037602
A
243}
244
ea3f0419 245unsigned int
cb323159 246backtrace_user(uintptr_t *bt, unsigned int max_frames,
ea3f0419 247 int *error_out, bool *user_64_out, bool *was_truncated_out)
39037602 248{
cb323159 249 return backtrace_thread_user(current_thread(), bt, max_frames,
ea3f0419 250 error_out, user_64_out, was_truncated_out);
39037602
A
251}
252
ea3f0419 253unsigned int
cb323159 254backtrace_thread_user(void *thread, uintptr_t *bt, unsigned int max_frames,
ea3f0419 255 int *error_out, bool *user_64_out, bool *was_truncated_out)
39037602
A
256{
257 bool user_64;
cb323159 258 uintptr_t pc = 0, fp = 0, next_fp = 0;
d9a64523 259 vm_map_t map = NULL, old_map = NULL;
cb323159 260 unsigned int frame_index = 0;
39037602 261 int err = 0;
cb323159 262 size_t frame_size = 0;
39037602 263
39037602
A
264 assert(bt != NULL);
265 assert(max_frames > 0);
39037602
A
266
267#if defined(__x86_64__)
268
269 /* don't allow a malformed user stack to copyin arbitrary kernel data */
270#define INVALID_USER_FP(FP) ((FP) == 0 || !IS_USERADDR64_CANONICAL((FP)))
271
272 x86_saved_state_t *state = get_user_regs(thread);
273
274 if (!state) {
275 return EINVAL;
276 }
277
278 user_64 = is_saved_state64(state);
279 if (user_64) {
280 pc = saved_state64(state)->isf.rip;
281 fp = saved_state64(state)->rbp;
282 } else {
283 pc = saved_state32(state)->eip;
284 fp = saved_state32(state)->ebp;
285 }
286
5ba3f43e
A
287#elif defined(__arm64__)
288
289 /* ARM expects stack frames to be aligned to 16 bytes */
290#define INVALID_USER_FP(FP) ((FP) == 0 || ((FP) & 0x3UL) != 0UL)
291
292 struct arm_saved_state *state = get_user_regs(thread);
293 if (!state) {
294 return EINVAL;
295 }
296
297 user_64 = is_saved_state64(state);
298 pc = get_saved_state_pc(state);
299 fp = get_saved_state_fp(state);
300
301#elif defined(__arm__)
302
303 /* ARM expects stack frames to be aligned to 16 bytes */
304#define INVALID_USER_FP(FP) ((FP) == 0 || ((FP) & 0x3UL) != 0UL)
305
306 struct arm_saved_state *state = get_user_regs(thread);
307 if (!state) {
308 return EINVAL;
309 }
310
311 user_64 = false;
312 pc = get_saved_state_pc(state);
313 fp = get_saved_state_fp(state);
314
39037602
A
315#else /* defined(__arm__) */
316#error "backtrace_thread_user: unsupported architecture"
317#endif /* !defined(__arm__) */
318
d9a64523
A
319 bt[frame_index++] = pc;
320
321 if (frame_index >= max_frames) {
322 goto out;
323 }
324
325 if (INVALID_USER_FP(fp)) {
326 goto out;
327 }
328
329 assert(ml_get_interrupts_enabled() == TRUE);
330 if (!ml_get_interrupts_enabled()) {
94ff46dc 331 goto out;
39037602
A
332 }
333
334 union {
335 struct {
336 uint64_t fp;
337 uint64_t ret;
338 } u64;
339 struct {
340 uint32_t fp;
341 uint32_t ret;
342 } u32;
343 } frame;
39037602 344
cb323159 345 frame_size = 2 * (user_64 ? 8 : 4);
39037602 346
d9a64523
A
347 /* switch to the correct map, for copyin */
348 if (thread != current_thread()) {
349 map = get_task_map_reference(get_threadtask(thread));
350 if (map == NULL) {
94ff46dc 351 goto out;
d9a64523
A
352 }
353 old_map = vm_map_switch(map);
354 } else {
355 map = NULL;
39037602
A
356 }
357
358 while (fp != 0 && frame_index < max_frames) {
359 err = copyin(fp, (char *)&frame, frame_size);
360 if (err) {
cb323159
A
361 if (was_truncated_out) {
362 *was_truncated_out = true;
363 }
39037602
A
364 goto out;
365 }
366
367 next_fp = user_64 ? frame.u64.fp : frame.u32.fp;
368
369 if (INVALID_USER_FP(next_fp)) {
370 break;
371 }
372
d9a64523 373 uintptr_t ret_addr = user_64 ? frame.u64.ret : frame.u32.ret;
cb323159
A
374#if defined(HAS_APPLE_PAC)
375 /* return addresses signed by arm64e ABI */
376 bt[frame_index++] = (uintptr_t)ptrauth_strip((void *)ret_addr,
377 ptrauth_key_return_address);
378#else /* defined(HAS_APPLE_PAC) */
d9a64523 379 bt[frame_index++] = ret_addr;
cb323159 380#endif /* !defined(HAS_APPLE_PAC) */
39037602
A
381
382 /* stacks grow down; backtracing should be moving to higher addresses */
383 if (next_fp <= fp) {
384 break;
385 }
386 fp = next_fp;
387 }
388
389out:
390 if (map) {
391 (void)vm_map_switch(old_map);
392 vm_map_deallocate(map);
393 }
394
cb323159
A
395 /* NULL-terminate the list, if space is available */
396 if (frame_index != max_frames) {
397 bt[frame_index] = 0;
398 }
399
400 if (fp != 0 && frame_index == max_frames && was_truncated_out) {
401 *was_truncated_out = true;
402 }
403
404 if (user_64_out) {
405 *user_64_out = user_64;
406 }
ea3f0419
A
407 if (error_out) {
408 *error_out = err;
409 }
cb323159 410
ea3f0419 411 return frame_index;
39037602
A
412#undef INVALID_USER_FP
413}