Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | // Copyright (c) 2016-2021 Apple Inc. All rights reserved. // // @APPLE_OSREFERENCE_LICENSE_HEADER_START@ // // This file contains Original Code and/or Modifications of Original Code // as defined in and that are subject to the Apple Public Source License // Version 2.0 (the 'License'). You may not use this file except in // compliance with the License. The rights granted to you under the License // may not be used to create, or enable the creation or redistribution of, // unlawful or unlicensed copies of an Apple operating system, or to // circumvent, violate, or enable the circumvention or violation of, any // terms of an Apple operating system software license agreement. // // Please obtain a copy of the License at // http://www.opensource.apple.com/apsl/ and read it before using this file. // // The Original Code and all software distributed under the License are // distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER // EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, // INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. // Please see the License for the specific language governing rights and // limitations under the License. // // @APPLE_OSREFERENCE_LICENSE_HEADER_END@ #ifndef KERN_BACKTRACE_H #define KERN_BACKTRACE_H // Kernel and user space backtracing (call stack walking) functions. // // For the current kernel stack, call backtrace from any context: // // ```c // #define MAX_STK_LEN (8) // // void *ret_addrs[MAX_STK_LEN] = { 0 }; // backtrace_info_t info = BTI_NONE; // unsigned int stk_len = backtrace(ret_addrs, MAX_STK_LEN, NULL, &info); // for (unsigned int i = 0; i < stk_len; i++) { // printf("%p -> ", ret_addrs[i]); // } // printf("%s\n", (info & BTI_TRUNCATED) ? "TRUNC" : "NULL"); // ``` // // For user stacks, call backtrace_user from a faultable context: // // ```c // uintptr_t ret_addrs[MAX_STK_LEN] = { 0 }; // struct backtrace_user_info info = BTUINFO_INIT; // unsigned int stk_len = backtrace_user(ret_addrs, MAX_STK_LEN, NULL, &info); // if (info.btui_error != 0) { // printf("user space%s stack is %u frames deep\n", // (info->btui_info & BTI_TRUNCATED) ? " truncated" : "", stk_len); // } // ``` // // Refer to documentation in backtrace(9) for more information. #include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <sys/cdefs.h> // XXX Surgically include just the errno_t definition, so this can still be used // by Mach. #include <sys/_types/_errno_t.h> __BEGIN_DECLS // backtrace_flags_t change how the backtraces are recorded. __options_decl(backtrace_flags_t, uint32_t, { BTF_NONE = 0x0, // BTF_KERN_INTERRUPTED backtraces the interrupted kernel stack. BTF_KERN_INTERRUPTED = 0x1, }); // The copy function is used to copy call stack frame and other information from // the target call stack. If an error is returned, the backtrace is aborted. typedef errno_t (*backtrace_user_copy_fn)(void *ctx, void *dst, user_addr_t src, size_t size); // This copy function returns an error when a copy attempt is made, effectively // limiting the user backtrace to the PC. errno_t backtrace_user_copy_error(void *ctx, void *dst, user_addr_t src, size_t size); // Parameters that control how the backtrace is taken. struct backtrace_control { backtrace_flags_t btc_flags; // The frame address to start backtracing from; set to 0 to start from the // calling frame. uintptr_t btc_frame_addr; // A thread to backtrace user stacks of; must be either the current thread // or one which has been suspended. void *btc_user_thread; // A functions to call instead of the default copyin routine for // user space backtracing. backtrace_user_copy_fn btc_user_copy; // A context to pass to the user copy routine. void *btc_user_copy_context; // Apply an offset to each address stored by the backtracer. int64_t btc_addr_offset; }; // Use this offset when walking an async stack, so symbolicators that subtract 1 // from each address to find the call site see valid symbols, instead of // whatever function is at a lower address than the function pointer. #define BTCTL_ASYNC_ADDR_OFFSET ((int64_t)1) #define BTCTL_INIT \ ((struct backtrace_control){ \ .btc_flags = BTF_NONE, \ .btc_frame_addr = 0, \ .btc_user_thread = NULL, \ .btc_user_copy = NULL, \ .btc_user_copy_context = NULL, \ .btc_addr_offset = 0, \ }) // backtrace_info_t provides information about the backtrace. __options_decl(backtrace_info_t, uint32_t, { BTI_NONE = 0x0, // BTI_64_BIT is set when the backtrace is made up of 64-bit addresses. BTI_64_BIT = 0x1, // BTI_TRUNCATED is set when the backtrace has been truncated, either due // to an error copying data, an invalid frame pointer, or running out of // buffer space. BTI_TRUNCATED = 0x2, }); // Backtrace the current thread's kernel stack. unsigned int backtrace(uintptr_t *bt, unsigned int btlen, struct backtrace_control *ctl, backtrace_info_t *info_out) __attribute__((noinline)); // backtrace_pack_t changes the packing scheme for backtraces. __enum_decl(backtrace_pack_t, uint32_t, { // Leave the addresses alone. BTP_NONE = 0x0, // Subtract the kernel base address and store each offset in 4 bytes. BTP_KERN_OFFSET_32 = 0x01, }); // Backtrace the current thread's kernel stack and store in a packed // representation. size_t backtrace_packed(backtrace_pack_t packing, uint8_t *bt, size_t btsize, struct backtrace_control *ctl, backtrace_info_t *info_out) __attribute__((noinline)); // Convert an array of addresses to a packed representation. size_t backtrace_pack(backtrace_pack_t packing, uint8_t *dst, size_t dst_size, const uintptr_t *src, unsigned int src_len); // Convert a packed backtrace to an array of addresses. unsigned int backtrace_unpack(backtrace_pack_t packing, uintptr_t *dst, unsigned int dst_len, const uint8_t *src, size_t src_size); // backtrace_user_info describes a user backtrace. struct backtrace_user_info { backtrace_info_t btui_info; errno_t btui_error; // The index where the start of the async call stack was found. unsigned int btui_async_start_index; // The frame address that can be backtraced to follow the async call stack. uintptr_t btui_async_frame_addr; // The frame address to use to resume the backtrace when the call stack is // truncated by the size of the passed-in buffer. uintptr_t btui_next_frame_addr; }; #define BTUINFO_INIT \ ((struct backtrace_user_info){ \ .btui_error = 0, \ .btui_info = BTI_NONE, \ .btui_async_start_index = 0, \ .btui_async_frame_addr = 0, \ .btui_next_frame_addr = 0, \ }) // Backtrace a thread's user stack. unsigned int backtrace_user(uintptr_t *bt, unsigned int btlen, const struct backtrace_control *ctl, struct backtrace_user_info *info_out); __END_DECLS #endif // !defined(KERN_BACKTRACE_H) |