xref: /xnu-12377.81.4/osfmk/kern/btlog.h (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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 __exported_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 __exported_pop
319 
320 __ASSUME_PTR_ABI_SINGLE_END __END_DECLS
321 
322 #endif  /* _KERN_BTLOG_H_ */
323