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
79struct btlog;
80struct zone_btrecord;
81
82typedef 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 */
91typedef 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 */
110extern 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 */
120extern btref_t btref_retain(
121 btref_t ref);
122
123/*!
124 * @function btref_put()
125 *
126 * @brief
127 * Release a given backtrace ref.
128 */
129extern 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 */
141extern 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 */
172extern 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 */
188extern 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 */
202extern 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 */
211extern 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 */
220extern 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 */
229extern 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 */
239extern 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 */
250extern 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 */
265extern 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 */
276extern 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 */
293extern 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 */
310extern 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