1 /* 2 * Copyright (c) 2012-2021 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 #ifndef _KERN_BTLOG_H_ 30 #define _KERN_BTLOG_H_ 31 32 #include <sys/cdefs.h> 33 #include <stdbool.h> 34 #include <stdint.h> 35 36 #include <mach/vm_types.h> 37 #include <kern/kern_types.h> 38 #include <kern/debug.h> 39 40 __BEGIN_DECLS __ASSUME_PTR_ABI_SINGLE_BEGIN 41 42 #pragma GCC visibility push(hidden) 43 44 /* 45 * The btlog subsystem allows for fast unobtrusive backtraces 46 * to be recorded and maintained in chronological order. 47 * 48 * Each backtrace is associated with an element/object, 49 * and an operation. For example, memory allocations and 50 * frees can be tracked with this infrastructure. So 51 * can refcounts. The "operation" namespace is maintained 52 * by the caller. 53 * 54 * When the event buffer fills, records are reused in FIFO 55 * order. 56 * 57 * When a btlog_t is created, callbacks can be provided 58 * to ensure proper locking of the datastructures. If these 59 * are not provided, the caller is responsible for 60 * preventing simultaneous modification. 61 */ 62 63 /* 64 * BTLOG_MAX_DEPTH configures how deep of a stack trace is stored. 15 65 * levels is usually enough to get past all the layers of code in 66 * kalloc and IOKit and see who the actual caller is up above these 67 * lower levels, when used by the zone allocator logging code. 68 */ 69 70 #define BTLOG_MAX_DEPTH 15 71 72 #if __has_attribute(diagnose_if) 73 #define __btlog_check(cond, msg) \ 74 __attribute__((diagnose_if(cond, msg, "error"))) 75 #else 76 #define __btlog_check(cond, msg) 77 #endif 78 79 struct btlog; 80 struct zone_btrecord; 81 82 typedef struct btlog *btlog_t; 83 84 /*! 85 * @typedef btref_t 86 * 87 * @brief 88 * A backtrace ref is a compact pointer referencing a unique backtrace 89 * in the centralized backtrace pool. 90 */ 91 typedef uint32_t btref_t; 92 #define BTREF_NULL ((btref_t)0) 93 94 __options_decl(btref_get_flags_t, uint32_t, { 95 BTREF_GET_PERMANENT = 0x0001, 96 BTREF_GET_NOWAIT = 0x0002, 97 }); 98 99 /*! 100 * @function btref_get() 101 * 102 * @brief 103 * Get the backtrace reference anchored at the given @c fp 104 * for the current thread. 105 * 106 * @returns 107 * - BTREF_NULL if allocating the backtrace failed 108 * - a non 0 backtrace reference otherwise with a +1 refcount. 109 */ 110 extern btref_t btref_get( 111 void *fp, 112 btref_get_flags_t flags); 113 114 /*! 115 * @function btref_retain() 116 * 117 * @brief 118 * Retains a given backtrace ref. 119 */ 120 extern btref_t btref_retain( 121 btref_t ref); 122 123 /*! 124 * @function btref_put() 125 * 126 * @brief 127 * Release a given backtrace ref. 128 */ 129 extern void btref_put( 130 btref_t btref); 131 132 /*! 133 * @function btref_decode_unslide() 134 * 135 * @brief 136 * Decodes a backtrace into a specified buffer with unslid addresses. 137 * 138 * @returns 139 * The number of frames in the buffer. 140 */ 141 extern uint32_t btref_decode_unslide( 142 btref_t btref, 143 mach_vm_address_t bt[__counted_by(BTLOG_MAX_DEPTH)]); 144 145 146 /*! 147 * @typedef btlog_type_t 148 * 149 * @const BTLOG_LOG 150 * A linear log of entries, as a circular buffer. 151 * 152 * @const BTLOG_HASH 153 * A log of entries indexed by element address, 154 * where entries can be pruned by element address, 155 * but where entries might go missing. 156 */ 157 __enum_decl(btlog_type_t, uint8_t, { 158 BTLOG_LOG = 1, 159 BTLOG_HASH = 2, 160 }); 161 162 /*! 163 * @function btlog_create() 164 * 165 * @brief 166 * Creates a backtrace log of the specified type. 167 * 168 * @param type the log type to create. 169 * @param num_records how many records the log should hold. 170 * @param sample sampling rate (0 to disable). 171 */ 172 extern btlog_t btlog_create( 173 btlog_type_t type, 174 uint32_t num_records, 175 uint32_t sample); 176 177 /*! 178 * @function btlog_enable() 179 * 180 * @brief 181 * Enable the specified btlog back. 182 * 183 * @discussion 184 * This operation is not thread safe with respect 185 * to @c btlog_disable() or @c btlog_destroy(), 186 * and the caller is supposed to provide serialization. 187 */ 188 extern kern_return_t btlog_enable( 189 btlog_t log); 190 191 /*! 192 * @function btlog_disable() 193 * 194 * @brief 195 * Disables the specified btlog. 196 * 197 * @discussion 198 * This operation is not thread safe with respect 199 * to @c btlog_enable() or @c btlog_destroy(), 200 * and the caller is supposed to provide serialization. 201 */ 202 extern void btlog_disable( 203 btlog_t log); 204 205 /*! 206 * @function btlog_destroy() 207 * 208 * @brief 209 * Destroys a backtrace log made with btlog_create(). 210 */ 211 extern void btlog_destroy( 212 btlog_t btlog); 213 214 /*! 215 * @function btlog_get_type() 216 * 217 * @brief 218 * Returns the type for the given btlog. 219 */ 220 extern btlog_type_t btlog_get_type( 221 btlog_t btlog) __pure2; 222 223 /*! 224 * @function btlog_get_count() 225 * 226 * @brief 227 * Returns how many records this log can hold. 228 */ 229 extern uint32_t btlog_get_count( 230 btlog_t btlog) __pure2; 231 232 233 /*! 234 * @function btlog_sample() 235 * 236 * @brief 237 * Returns whether it's the right time to record an event. 238 */ 239 extern bool btlog_sample( 240 btlog_t btlog); 241 242 /*! 243 * @function btlog_record() 244 * 245 * @brief 246 * Records an event for a given address with 247 * a user provided "operation" to tag it. 248 * btlog_record will consume a reference on btref. 249 */ 250 extern void btlog_record( 251 btlog_t btlog, 252 void *element, 253 uint8_t op, 254 btref_t btref); 255 256 /*! 257 * @function btlog_erase() 258 * 259 * @brief 260 * Erase all records for a given address. 261 * 262 * @discussion 263 * This only does something for BTLOG_HASH logs. 264 */ 265 extern void btlog_erase( 266 btlog_t btlog, 267 void *element); 268 269 #if !__has_ptrcheck // rdar://88209707 270 /*! 271 * @function btlog_get_records() 272 * 273 * @brief 274 * Translates btlog records into zone bt records. 275 */ 276 extern kern_return_t btlog_get_records( 277 btlog_t btlog, 278 struct zone_btrecord *__counted_by(*numrecs) *records, 279 unsigned int *numrecs); 280 #endif 281 282 /*! 283 * @function btlog_guess_top() 284 * 285 * @brief 286 * Tries to guess the "top" active backtrace 287 * in a @c BTLOG_HASH btlog. 288 * 289 * @returns 290 * The number of outstanding records for this backtrace, 291 * or 0 if something bad happened. 292 */ 293 extern uint32_t btlog_guess_top( 294 btlog_t btlog, 295 vm_address_t bt[__counted_by(BTLOG_MAX_DEPTH)], 296 uint32_t *len); 297 298 #if DEBUG || DEVELOPMENT 299 300 /*! 301 * @function btlog_copy_backtraces_for_elements() 302 * 303 * @brief 304 * Copy backtraces for the specified list of elements. 305 * 306 * @discussion 307 * This only does something for BTLOG_HASH logs with a single event per element. 308 * This is really tailored for zalloc and isn't a very useful interface as is. 309 */ 310 extern void btlog_copy_backtraces_for_elements( 311 btlog_t btlog, 312 vm_address_t *__counted_by(*count)instances, 313 uint32_t *count, 314 uint32_t elem_size, 315 leak_site_proc proc); 316 317 #endif /* DEBUG || DEVELOPMENT */ 318 #pragma GCC visibility pop 319 320 __ASSUME_PTR_ABI_SINGLE_END __END_DECLS 321 322 #endif /* _KERN_BTLOG_H_ */ 323