xref: /xnu-11215.1.10/libkern/os/trace.h (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
1 /*
2  * Copyright (c) 2013-2015 Apple Inc. All rights reserved.
3  *
4  * @APPLE_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. Please obtain a copy of the License at
10  * http://www.opensource.apple.com/apsl/ and read it before using this
11  * file.
12  *
13  * The Original Code and all software distributed under the License are
14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18  * Please see the License for the specific language governing rights and
19  * limitations under the License.
20  *
21  * @APPLE_LICENSE_HEADER_END@
22  */
23 
24 #ifndef __OS_TRACE_H__
25 #define __OS_TRACE_H__
26 
27 #include <Availability.h>
28 #include <os/base.h>
29 #include <sys/types.h>
30 #include <stdint.h>
31 #include <stdbool.h>
32 #include <stdarg.h>
33 #if __has_include(<xpc/xpc.h>)
34 #include <xpc/xpc.h>
35 #else
36 typedef void *xpc_object_t;
37 #endif
38 
39 #if !__GNUC__
40 #error "must be GNU C compatible"
41 #endif
42 
43 __BEGIN_DECLS
44 
45 extern void *__dso_handle;
46 
47 OS_ALWAYS_INLINE
48 static inline void
_os_trace_verify_printf(const char * msg,...)49 _os_trace_verify_printf(const char *msg, ...)
50 __attribute__((format(printf, 1, 2)))
51 {
52 #pragma unused(msg)
53 }
54 
55 #if !defined OS_COUNT_ARGS
56 #define OS_COUNT_ARGS(...) OS_COUNT_ARGS1(, ##__VA_ARGS__, _8, _7, _6, _5, _4, _3, _2, _1, _0)
57 #define OS_COUNT_ARGS1(z, a, b, c, d, e, f, g, h, cnt, ...) cnt
58 #endif
59 
60 /* use old macros for anything less than iOS 10 and MacOS 10.12 */
61 #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0) \
62         || (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && __WATCH_OS_VERSION_MIN_REQUIRED < __WATCHOS_3_0) \
63         || (defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < __TVOS_10_0) \
64         || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_12)
65 
66 #define _os_trace_0(_l, _m, _t) __extension__({ \
67 	_os_trace_verify_printf(_l); \
68 	_os_trace_with_buffer(&__dso_handle, _m, _t, NULL, 0, NULL); \
69 	__asm__(""); /* avoid tailcall */ \
70 })
71 
72 #define _os_trace_1(_l, _m, _t, _1) __extension__({ \
73 	_Pragma("clang diagnostic push") \
74 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
75 	const __typeof__(_1) _c1 = _1; \
76 	_os_trace_verify_printf(_l, _c1); \
77 	const struct __attribute__((packed)) { \
78 	        __typeof__(_c1) _f1; \
79 	        uint8_t _s[1]; \
80 	        uint8_t _cnt; \
81 	} _buf = { \
82 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
83 	        ._cnt = 1, \
84 	}; \
85 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
86 	__asm__(""); /* avoid tailcall */ \
87 	_Pragma("clang diagnostic pop") \
88 })
89 
90 #define _os_trace_2(_l, _m, _t, _1, _2) __extension__({ \
91 	_Pragma("clang diagnostic push") \
92 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
93 	const __typeof__(_1) _c1 = _1; \
94 	const __typeof__(_2) _c2 = _2; \
95 	_os_trace_verify_printf(_l, _c1, _c2); \
96 	const struct __attribute__((packed)) { \
97 	        __typeof__(_c1) _f1; \
98 	        __typeof__(_c2) _f2; \
99 	        uint8_t _s[2]; \
100 	        uint8_t _cnt; \
101 	} _buf = { \
102 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
103 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
104 	        ._cnt = 2, \
105 	}; \
106 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
107 	__asm__(""); /* avoid tailcall */ \
108 	_Pragma("clang diagnostic pop") \
109 })
110 
111 #define _os_trace_3(_l, _m, _t, _1, _2, _3) __extension__({ \
112 	_Pragma("clang diagnostic push") \
113 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
114 	const __typeof__(_1) _c1 = _1; \
115 	const __typeof__(_2) _c2 = _2; \
116 	const __typeof__(_3) _c3 = _3; \
117 	_os_trace_verify_printf(_l, _c1, _c2, _c3); \
118 	const struct __attribute__((packed)) { \
119 	        __typeof__(_c1) _f1; \
120 	        __typeof__(_c2) _f2; \
121 	        __typeof__(_c3) _f3; \
122 	        uint8_t _s[3]; \
123 	        uint8_t _cnt; \
124 	} _buf = { \
125 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
126 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
127 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
128 	        ._cnt = 3, \
129 	}; \
130 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
131 	__asm__(""); /* avoid tailcall */ \
132 	_Pragma("clang diagnostic pop") \
133 })
134 
135 #define _os_trace_4(_l, _m, _t, _1, _2, _3, _4) __extension__({ \
136 	_Pragma("clang diagnostic push") \
137 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
138 	const __typeof__(_1) _c1 = _1; \
139 	const __typeof__(_2) _c2 = _2; \
140 	const __typeof__(_3) _c3 = _3; \
141 	const __typeof__(_4) _c4 = _4; \
142 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4); \
143 	const struct __attribute__((packed)) { \
144 	        __typeof__(_c1) _f1; \
145 	        __typeof__(_c2) _f2; \
146 	        __typeof__(_c3) _f3; \
147 	        __typeof__(_c4) _f4; \
148 	        uint8_t _s[4]; \
149 	        uint8_t _cnt; \
150 	} _buf = { \
151 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
152 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
153 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
154 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
155 	        ._cnt = 4, \
156 	}; \
157 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
158 	__asm__(""); /* avoid tailcall */ \
159 	_Pragma("clang diagnostic pop") \
160 })
161 
162 #define _os_trace_5(_l, _m, _t, _1, _2, _3, _4, _5) __extension__({ \
163 	_Pragma("clang diagnostic push") \
164 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
165 	const __typeof__(_1) _c1 = _1; \
166 	const __typeof__(_2) _c2 = _2; \
167 	const __typeof__(_3) _c3 = _3; \
168 	const __typeof__(_4) _c4 = _4; \
169 	const __typeof__(_5) _c5 = _5; \
170 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4, _c5); \
171 	const struct __attribute__((packed)) { \
172 	        __typeof__(_c1) _f1; \
173 	        __typeof__(_c2) _f2; \
174 	        __typeof__(_c3) _f3; \
175 	        __typeof__(_c4) _f4; \
176 	        __typeof__(_c5) _f5; \
177 	        uint8_t _s[5]; \
178 	        uint8_t _cnt; \
179 	} _buf = { \
180 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
181 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
182 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
183 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
184 	        ._f5 = _c5, ._s[4] = sizeof(_c5), \
185 	        ._cnt = 5, \
186 	}; \
187 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
188 	__asm__(""); /* avoid tailcall */ \
189 	_Pragma("clang diagnostic pop") \
190 })
191 
192 #define _os_trace_6(_l, _m, _t, _1, _2, _3, _4, _5, _6) __extension__({ \
193 	_Pragma("clang diagnostic push") \
194 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
195 	const __typeof__(_1) _c1 = _1; \
196 	const __typeof__(_2) _c2 = _2; \
197 	const __typeof__(_3) _c3 = _3; \
198 	const __typeof__(_4) _c4 = _4; \
199 	const __typeof__(_5) _c5 = _5; \
200 	const __typeof__(_6) _c6 = _6; \
201 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4, _c5, _c6); \
202 	const struct __attribute__((packed)) { \
203 	        __typeof__(_c1) _f1; \
204 	        __typeof__(_c2) _f2; \
205 	        __typeof__(_c3) _f3; \
206 	        __typeof__(_c4) _f4; \
207 	        __typeof__(_c5) _f5; \
208 	        __typeof__(_c6) _f6; \
209 	        uint8_t _s[6]; \
210 	        uint8_t _cnt; \
211 	} _buf = { \
212 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
213 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
214 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
215 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
216 	        ._f5 = _c5, ._s[4] = sizeof(_c5), \
217 	        ._f6 = _c6, ._s[5] = sizeof(_c6), \
218 	        ._cnt = 6, \
219 	}; \
220 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
221 	__asm__(""); /* avoid tailcall */ \
222 	_Pragma("clang diagnostic pop") \
223 })
224 
225 #define _os_trace_7(_l, _m, _t, _1, _2, _3, _4, _5, _6, _7) __extension__({ \
226 	_Pragma("clang diagnostic push") \
227 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
228 	const __typeof__(_1) _c1 = _1; \
229 	const __typeof__(_2) _c2 = _2; \
230 	const __typeof__(_3) _c3 = _3; \
231 	const __typeof__(_4) _c4 = _4; \
232 	const __typeof__(_5) _c5 = _5; \
233 	const __typeof__(_6) _c6 = _6; \
234 	const __typeof__(_7) _c7 = _7; \
235 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4, _c5, _c6, _c7); \
236 	const struct __attribute__((packed)) { \
237 	        __typeof__(_c1) _f1; \
238 	        __typeof__(_c2) _f2; \
239 	        __typeof__(_c3) _f3; \
240 	        __typeof__(_c4) _f4; \
241 	        __typeof__(_c5) _f5; \
242 	        __typeof__(_c6) _f6; \
243 	        __typeof__(_c7) _f7; \
244 	        uint8_t _s[7]; \
245 	        uint8_t _cnt; \
246 	} _buf = { \
247 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
248 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
249 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
250 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
251 	        ._f5 = _c5, ._s[4] = sizeof(_c5), \
252 	        ._f6 = _c6, ._s[5] = sizeof(_c6), \
253 	        ._f7 = _c7, ._s[6] = sizeof(_c7), \
254 	        ._cnt = 7, \
255 	}; \
256 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
257 	__asm__(""); /* avoid tailcall */ \
258 	_Pragma("clang diagnostic pop") \
259 })
260 
261 #define _os_trace_with_payload_1(_l, _m, _t, _payload) __extension__({ \
262 	_os_trace_verify_printf(_l); \
263 	_os_trace_with_buffer(&__dso_handle, _m, _t, NULL, 0, _payload); \
264 	__asm__(""); /* avoid tailcall */ \
265 })
266 
267 #define _os_trace_with_payload_2(_l, _m, _t, _1, _payload) __extension__({ \
268 	_Pragma("clang diagnostic push") \
269 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
270 	const __typeof__(_1) _c1 = _1; \
271 	_os_trace_verify_printf(_l, _c1); \
272 	const struct __attribute__((packed)) { \
273 	        __typeof__(_c1) _f1; \
274 	        uint8_t _s[1]; \
275 	        uint8_t _cnt; \
276 	} _buf = { \
277 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
278 	        ._cnt = 1, \
279 	}; \
280 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
281 	__asm__(""); /* avoid tailcall */ \
282 	_Pragma("clang diagnostic pop") \
283 })
284 
285 #define _os_trace_with_payload_3(_l, _m, _t, _1, _2, _payload) __extension__({ \
286 	_Pragma("clang diagnostic push") \
287 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
288 	const __typeof__(_1) _c1 = _1; \
289 	const __typeof__(_2) _c2 = _2; \
290 	_os_trace_verify_printf(_l, _c1, _c2); \
291 	const struct __attribute__((packed)) { \
292 	        __typeof__(_c1) _f1; \
293 	        __typeof__(_c2) _f2; \
294 	        uint8_t _s[2]; \
295 	        uint8_t _cnt; \
296 	} _buf = { \
297 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
298 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
299 	        ._cnt = 2, \
300 	}; \
301 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
302 	__asm__(""); /* avoid tailcall */ \
303 	_Pragma("clang diagnostic pop") \
304 })
305 
306 #define _os_trace_with_payload_4(_l, _m, _t, _1, _2, _3, _payload) __extension__({ \
307 	_Pragma("clang diagnostic push") \
308 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
309 	const __typeof__(_1) _c1 = _1; \
310 	const __typeof__(_2) _c2 = _2; \
311 	const __typeof__(_3) _c3 = _3; \
312 	_os_trace_verify_printf(_l, _c1, _c2, _c3); \
313 	const struct __attribute__((packed)) { \
314 	        __typeof__(_c1) _f1; \
315 	        __typeof__(_c2) _f2; \
316 	        __typeof__(_c3) _f3; \
317 	        uint8_t _s[3]; \
318 	        uint8_t _cnt; \
319 	} _buf = { \
320 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
321 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
322 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
323 	        ._cnt = 3, \
324 	}; \
325 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
326 	__asm__(""); /* avoid tailcall */ \
327 	_Pragma("clang diagnostic pop") \
328 })
329 
330 #define _os_trace_with_payload_5(_l, _m, _t, _1, _2, _3, _4, _payload) __extension__({ \
331 	_Pragma("clang diagnostic push") \
332 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
333 	const __typeof__(_1) _c1 = _1; \
334 	const __typeof__(_2) _c2 = _2; \
335 	const __typeof__(_3) _c3 = _3; \
336 	const __typeof__(_4) _c4 = _4; \
337 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4); \
338 	const struct __attribute__((packed)) { \
339 	        __typeof__(_c1) _f1; \
340 	        __typeof__(_c2) _f2; \
341 	        __typeof__(_c3) _f3; \
342 	        __typeof__(_c4) _f4; \
343 	        uint8_t _s[4]; \
344 	        uint8_t _cnt; \
345 	} _buf = { \
346 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
347 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
348 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
349 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
350 	        ._cnt = 4, \
351 	}; \
352 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
353 	__asm__(""); /* avoid tailcall */ \
354 	_Pragma("clang diagnostic pop") \
355 })
356 
357 #define _os_trace_with_payload_6(_l, _m, _t, _1, _2, _3, _4, _5, _payload) __extension__({ \
358 	_Pragma("clang diagnostic push") \
359 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
360 	const __typeof__(_1) _c1 = _1; \
361 	const __typeof__(_2) _c2 = _2; \
362 	const __typeof__(_3) _c3 = _3; \
363 	const __typeof__(_4) _c4 = _4; \
364 	const __typeof__(_4) _c5 = _5; \
365 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4, _c5); \
366 	const struct __attribute__((packed)) { \
367 	        __typeof__(_c1) _f1; \
368 	        __typeof__(_c2) _f2; \
369 	        __typeof__(_c3) _f3; \
370 	        __typeof__(_c4) _f4; \
371 	        __typeof__(_c5) _f5; \
372 	        uint8_t _s[5]; \
373 	        uint8_t _cnt; \
374 	} _buf = { \
375 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
376 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
377 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
378 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
379 	        ._f5 = _c5, ._s[4] = sizeof(_c5), \
380 	        ._cnt = 5, \
381 	}; \
382 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
383 	__asm__(""); /* avoid tailcall */ \
384 	_Pragma("clang diagnostic pop") \
385 })
386 
387 #define _os_trace_with_payload_7(_l, _m, _t, _1, _2, _3, _4, _5, _6, _payload) __extension__({ \
388 	_Pragma("clang diagnostic push") \
389 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
390 	const __typeof__(_1) _c1 = _1; \
391 	const __typeof__(_2) _c2 = _2; \
392 	const __typeof__(_3) _c3 = _3; \
393 	const __typeof__(_4) _c4 = _4; \
394 	const __typeof__(_5) _c5 = _5; \
395 	const __typeof__(_6) _c6 = _6; \
396 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4, _c5, _c6); \
397 	const struct __attribute__((packed)) { \
398 	        __typeof__(_c1) _f1; \
399 	        __typeof__(_c2) _f2; \
400 	        __typeof__(_c3) _f3; \
401 	        __typeof__(_c4) _f4; \
402 	        __typeof__(_c5) _f5; \
403 	        __typeof__(_c6) _f6; \
404 	        uint8_t _s[6]; \
405 	        uint8_t _cnt; \
406 	} _buf = { \
407 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
408 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
409 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
410 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
411 	        ._f5 = _c5, ._s[4] = sizeof(_c5), \
412 	        ._f6 = _c6, ._s[5] = sizeof(_c6), \
413 	        ._cnt = 6, \
414 	}; \
415 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
416 	__asm__(""); /* avoid tailcall */ \
417 	_Pragma("clang diagnostic pop") \
418 })
419 
420 #define _os_trace_with_payload_8(_l, _m, _t, _1, _2, _3, _4, _5, _6, _7, _payload) __extension__({ \
421 	_Pragma("clang diagnostic push") \
422 	_Pragma("clang diagnostic ignored \"-Wpacked\"") \
423 	const __typeof__(_1) _c1 = _1; \
424 	const __typeof__(_2) _c2 = _2; \
425 	const __typeof__(_3) _c3 = _3; \
426 	const __typeof__(_4) _c4 = _4; \
427 	const __typeof__(_5) _c5 = _5; \
428 	const __typeof__(_6) _c6 = _6; \
429 	const __typeof__(_7) _c7 = _7; \
430 	_os_trace_verify_printf(_l, _c1, _c2, _c3, _c4, _c5, _c6, _c7); \
431 	const struct __attribute__((packed)) { \
432 	        __typeof__(_c1) _f1; \
433 	        __typeof__(_c2) _f2; \
434 	        __typeof__(_c3) _f3; \
435 	        __typeof__(_c4) _f4; \
436 	        __typeof__(_c5) _f5; \
437 	        __typeof__(_c6) _f6; \
438 	        __typeof__(_c7) _f7; \
439 	        uint8_t _s[7]; \
440 	        uint8_t _cnt; \
441 	} _buf = { \
442 	        ._f1 = _c1, ._s[0] = sizeof(_c1), \
443 	        ._f2 = _c2, ._s[1] = sizeof(_c2), \
444 	        ._f3 = _c3, ._s[2] = sizeof(_c3), \
445 	        ._f4 = _c4, ._s[3] = sizeof(_c4), \
446 	        ._f5 = _c5, ._s[4] = sizeof(_c5), \
447 	        ._f6 = _c6, ._s[5] = sizeof(_c6), \
448 	        ._f7 = _c7, ._s[6] = sizeof(_c7), \
449 	        ._cnt = 7, \
450 	}; \
451 	_os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
452 	__asm__(""); /* avoid tailcall */ \
453 	_Pragma("clang diagnostic pop") \
454 })
455 
456 #define OS_TRACE_CALL(format, _m, _t, ...) __extension__({                              \
457     _Pragma("clang diagnostic push")                                                    \
458     _Pragma("clang diagnostic ignored \"-Wc++98-compat-pedantic\"")                     \
459     OS_CONCAT(_os_trace, OS_COUNT_ARGS(__VA_ARGS__))(format, _m, _t, ##__VA_ARGS__);    \
460     _Pragma("clang diagnostic pop")                                                     \
461 })
462 
463 #else
464 
465 // Use a new layout in Mac OS 10.12+ and iOS 10.0+
466 #define OS_TRACE_CALL(_l, _m, _t, ...) __extension__({                          \
467     uint8_t buf[1024];                                                          \
468     _os_trace_verify_printf(_l, ##__VA_ARGS__);                                 \
469     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, ##__VA_ARGS__);    \
470     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, NULL);             \
471     __asm__(""); /* avoid tailcall */                                           \
472 })
473 
474 #define _os_trace_with_payload_1(_l, _m, _t, _payload) __extension__({  \
475     _os_trace_verify_printf(_l);                                        \
476     _os_trace_internal(&__dso_handle, _t, _m, NULL, 0, _payload);       \
477     __asm__(""); /* avoid tailcall */                                   \
478 })
479 
480 #define _os_trace_with_payload_2(_l, _m, _t, _1, _payload) __extension__({  \
481     _os_trace_verify_printf(_l, _1);                                        \
482     uint8_t buf[1024];                                                      \
483     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, _1);           \
484     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, _payload);     \
485     __asm__(""); /* avoid tailcall */                                       \
486 })
487 
488 #define _os_trace_with_payload_3(_l, _m, _t, _1, _2, _payload) __extension__({  \
489     _os_trace_verify_printf(_l, _1, _2);                                        \
490     uint8_t buf[1024];                                                          \
491     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, _1, _2);           \
492     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, _payload);         \
493     __asm__(""); /* avoid tailcall */                                           \
494 })
495 
496 #define _os_trace_with_payload_4(_l, _m, _t, _1, _2, _3, _payload) __extension__({  \
497     _os_trace_verify_printf(_l, _1, _2, _3);                                        \
498     uint8_t buf[1024];                                                              \
499     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, _1, _2, _3);           \
500     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, _payload);             \
501     __asm__(""); /* avoid tailcall */                                               \
502 })
503 
504 #define _os_trace_with_payload_5(_l, _m, _t, _1, _2, _3, _4, _payload) __extension__({  \
505     _os_trace_verify_printf(_l, _1, _2, _3, _4);                                        \
506     uint8_t buf[1024];                                                                  \
507     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, _1, _2, _3, _4);           \
508     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, _payload);                 \
509     __asm__(""); /* avoid tailcall */                                                   \
510 })
511 
512 #define _os_trace_with_payload_6(_l, _m, _t, _1, _2, _3, _4, _5, _payload) __extension__({  \
513     _os_trace_verify_printf(_l, _1, _2, _3, _4, _5);                                        \
514     uint8_t buf[1024];                                                                      \
515     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, _1, _2, _3, _4, _5);           \
516     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, _payload);                     \
517     __asm__(""); /* avoid tailcall */                                                       \
518 })
519 
520 #define _os_trace_with_payload_7(_l, _m, _t, _1, _2, _3, _4, _5, _6, _payload) __extension__({  \
521     _os_trace_verify_printf(_l, _1, _2, _3, _4, _5, _6);                                        \
522     uint8_t buf[1024];                                                                          \
523     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, _1, _2, _3, _4, _5, _6);           \
524     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, _payload);                         \
525     __asm__(""); /* avoid tailcall */                                                           \
526 })
527 
528 #define _os_trace_with_payload_8(_l, _m, _t, _1, _2, _3, _4, _5, _6, _7, _payload) __extension__({  \
529     _os_trace_verify_printf(_l, _1, _2, _3, _4, _5, _6, _7);                                        \
530     uint8_t buf[1024];                                                                              \
531     size_t buf_size = _os_trace_encode(buf, sizeof(buf), _m, _1, _2, _3, _4, _5, _6, _7);           \
532     _os_trace_internal(&__dso_handle, _t, _m, buf, buf_size, _payload);                             \
533     __asm__(""); /* avoid tailcall */                                                               \
534 })
535 
536 #endif /* if Mac OS >= 10.12 or iPhone OS >= 10.0 */
537 
538 /*!
539  *
540  * @abstract
541  * Hashtags in trace messages
542  *
543  * @discussion
544  * Developers are encouraged to include hashtags in log messages, regardless of what API you use.
545  * A hashtag is composed of a hash (#) symbol, followed by at least three non-whitespace characters,
546  * terminated by whitespace or the end of the message. Hashtags may not begin with a number.
547  *
548  * Below is the list of predefined tags:
549  *   #System     - Message in the context of a system process.
550  *   #User       - Message in the context of a user process.
551  *   #Developer  - Message in the context of software development. For example, deprecated APIs and debugging messages.
552  *   #Attention  - Message that should be investigated by a system administrator, because it may be a sign of a larger issue.
553  *     For example, errors from a hard drive controller that typically occur when the drive is about to fail.
554  *   #Critical   - Message in the context of a critical event or critical failure.
555  *   #Error      - Message that is a noncritical error.
556  *   #Comment    - Message that is a comment.
557  *   #Marker     - Message that marks a change to divide the messages around it into those before and those after the change.
558  *   #Clue       - Message containing extra key/value pairs with additional information to help reconstruct the context.
559  *   #Security   - Message related to security concerns.
560  *   #Filesystem - Message describing a file system related event.
561  *   #Network    - Message describing a network-related event.
562  *   #Hardware   - Message describing a hardware-related event.
563  *   #CPU        - Message describing CPU related event, e.g., initiating heavy work load
564  *   #State      - Message describing state changed, e.g., global state, preference, etc.
565  *   #Graphics   - Message describing significant graphics event
566  *   #Disk       - Message describing disk activity
567  *
568  */
569 
570 #pragma mark - Other defines
571 
572 /*!
573  * @define OS_TRACE_TYPE_RELEASE
574  * Trace messages to be captured on a typical user install.  These should be
575  * limited to things which improve diagnosis of a failure/crash/hang. Trace
576  * buffers are generally smaller on a production system.
577  */
578 #define OS_TRACE_TYPE_RELEASE (1u << 0)
579 
580 /*!
581  * @define OS_TRACE_TYPE_DEBUG
582  * Trace messages to be captured while debugger or other development tool is
583  * attached to the originator.
584  */
585 #define OS_TRACE_TYPE_DEBUG (1u << 1)
586 
587 /*!
588  * @define OS_TRACE_TYPE_INFO
589  * Trace messages that are captured when a debugger is attached, system or
590  * Application mode has been increased to include additional information.
591  */
592 #define OS_TRACE_TYPE_INFO (1u << 2)
593 
594 /*!
595  * @define OS_TRACE_TYPE_ERROR
596  * Trace the message as an error and force a collection as a failure may be
597  * imminent.
598  */
599 #define OS_TRACE_TYPE_ERROR ((1u << 6) | (1u << 0))
600 
601 /*!
602  * @define OS_TRACE_TYPE_FAULT
603  * Trace the message as a fatal error which forces a collection and a diagnostic
604  * to be initiated.
605  */
606 #define OS_TRACE_TYPE_FAULT ((1u << 7) | (1u << 6) | (1u << 0))
607 
608 /*!
609  * @typedef os_trace_payload_t
610  * A block that populates an xpc_object_t of type XPC_TYPE_DICTIONARY to represent
611  * complex data. This block will only be invoked under conditions where tools
612  * have attached to the process. The payload can be used to send arbitrary data
613  * via the trace call. Tools may use the data to validate state for integration
614  * tests or provide other introspection services. No assumptions are made about
615  * the format or structure of the data.
616  */
617 typedef void (^os_trace_payload_t)(xpc_object_t xdict);
618 
619 #pragma mark - function declarations
620 
621 /*!
622  * @function os_trace
623  *
624  * @abstract
625  * Always inserts a trace message into a buffer pool for later decoding.
626  *
627  * @discussion
628  * Trace message that will be recorded on a typical user install. These should
629  * be limited to things which help diagnose a failure during postmortem
630  * analysis. Trace buffers are generally smaller on a production system.
631  *
632  * @param format
633  * A printf-style format string to generate a human-readable log message when
634  * the trace line is decoded.  Only scalar types are supported, attempts
635  * to pass arbitrary strings will store a pointer that is unresolvable and
636  * will generate an error during decode.
637  *
638  *		os_trace("network event: %ld, last seen: %ld, avg: %g", event_id, last_seen, avg);
639  */
640 #define os_trace(format, ...) __extension__({                                           \
641     _Static_assert(__builtin_constant_p(format), "format must be a constant string");   \
642     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;      \
643    OS_TRACE_CALL(format, _m, OS_TRACE_TYPE_RELEASE, ##__VA_ARGS__);                     \
644 })
645 
646 
647 #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0) \
648         || (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && __WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_3_0) \
649         || (defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED >= __TVOS_10_0) \
650         || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_12)
651 
652 /*!
653  * @function os_trace_info
654  *
655  * @abstract
656  * Optionally inserts a trace message containing additional information into a
657  * buffer pool for later decoding.
658  *
659  * @discussion
660  * Trace messages that will be captured when additional information is needed
661  * and are not captured by default.  They will only be captured if the
662  * system/process/activity mode has been increased or if a Development tool has
663  * been attached to the process.
664  *
665  * @param format
666  * A printf-style format string that represents a human-readable message when
667  * the trace line is decoded.  Only scalar types are supported, attempts
668  * to pass arbitrary strings will store a pointer that is unresolvable and
669  * will generate an error during decode.
670  *
671  *		os_trace_info("network interface status %ld", status);
672  */
673 #define os_trace_info(format, ...) __extension__({                                      \
674     _Static_assert(__builtin_constant_p(format), "format must be a constant string");   \
675     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;      \
676    OS_TRACE_CALL(format, _m, OS_TRACE_TYPE_INFO, ##__VA_ARGS__);                        \
677 })
678 
679 #endif
680 
681 /*!
682  * @function os_trace_debug
683  *
684  * @abstract
685  * Insert debug trace message into a buffer pool for later decoding.
686  *
687  * @discussion
688  * Debug trace message to be recorded while debugger or other development tool is
689  * attached to the originator.  This is transported interprocess to help
690  * diagnose the entire call chain including external helpers.
691  *
692  * @param format
693  * A printf-style format string that represents a human-readable message when
694  * the trace line is decoded.  Only scalar types are supported, attempts
695  * to pass arbitrary strings will store a pointer that is unresolvable and
696  * will generate an error during decode.
697  *
698  *		os_trace_debug("network interface status %ld", status);
699  */
700 #define os_trace_debug(format, ...) __extension__({                                     \
701     _Static_assert(__builtin_constant_p(format), "format must be a constant string");   \
702     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;      \
703    OS_TRACE_CALL(format, _m, OS_TRACE_TYPE_DEBUG, ##__VA_ARGS__);                       \
704 })
705 
706 /*!
707  * @function os_trace_info_enabled
708  *
709  * @abstract
710  * Avoid unnecessary work for a trace point by checking if additional information
711  * is enabled.
712  *
713  * @discussion
714  * Avoid unnecessary work for a trace point by checking if additional information
715  * is enabled. Generally trace points should not involve expensive operations, but some
716  * circumstances warrant it.  Use this function to avoid doing the work unless
717  * debug level trace messages are requested.
718  *
719  *	if (os_trace_info_enabled()) {
720  *		os_trace_info("value = %d, average = %d",
721  *                            [[dict objectForKey: @"myKey"] intValue],
722  *			      (int) [self getAverage: dict]);
723  *	}
724  *
725  * @result
726  * Returns true if development mode is enabled.
727  */
728 __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0)
729 OS_EXPORT OS_NOTHROW OS_WARN_RESULT
730 bool
731 os_trace_info_enabled(void);
732 
733 /*!
734  * @function os_trace_debug_enabled
735  *
736  * @abstract
737  * Avoid unnecessary work for a trace point by checking if debug level is enabled.
738  *
739  * @discussion
740  * Avoid unnecessary work for a trace point by checking if debug level is enabled.
741  * Generally trace points should not involve expensive operations, but some
742  * circumstances warrant it.  Use this function to avoid doing the work unless
743  * debug level trace messages are requested.
744  *
745  *	if (os_trace_debug_enabled()) {
746  *		os_trace_debug("value = %d, average = %d",
747  *				[[dict objectForKey: @"myKey"] intValue],
748  *				(int) [self getAverage: dict]);
749  *	}
750  *
751  * @result
752  * Returns true if debug mode is enabled.
753  */
754 __OSX_AVAILABLE(10.10) __IOS_AVAILABLE(8.0) __WATCHOS_AVAILABLE(1.0) __TVOS_AVAILABLE(9.0)
755 OS_EXPORT OS_NOTHROW OS_WARN_RESULT
756 bool
757 os_trace_debug_enabled(void);
758 
759 /*!
760  * @function os_trace_error
761  *
762  * @abstract
763  * Trace the message as an error and force a collection of the trace buffer as a
764  * failure may be imminent.
765  *
766  * @discussion
767  * Trace the message as an error and force a collection of the trace buffer as a
768  * failure may be imminent.
769  *
770  * @param format
771  * A printf-style format string to generate a human-readable log message when
772  * the trace line is decoded.  Only scalar types are supported, attempts
773  * to pass arbitrary strings will store a pointer that is unresolvable and
774  * will generate an error during decode.
775  *
776  *		os_trace_error("socket %d connection timeout %ld", fd, secs);
777  */
778 #define os_trace_error(format, ...) __extension__({                                     \
779     _Static_assert(__builtin_constant_p(format), "format must be a constant string");   \
780     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;      \
781    OS_TRACE_CALL(format, _m, OS_TRACE_TYPE_ERROR, ##__VA_ARGS__);                       \
782 })
783 
784 /*!
785  * @function os_trace_fault
786  *
787  * @abstract
788  * Trace the message as a fault which forces a collection of the trace buffer
789  * and diagnostic of the activity.
790  *
791  * @discussion
792  * Trace the message as a fault which forces a collection of the trace buffer
793  * and diagnostic of the activity.
794  *
795  * @param format
796  * A printf-style format string to generate a human-readable log message when
797  * the trace line is decoded.  Only scalar types are supported, attempts
798  * to pass arbitrary strings will store a pointer that is unresolvable and
799  * will generate an error during decode.
800  *
801  *		os_trace_fault("failed to lookup uid %d - aborting", uid);
802  */
803 #define os_trace_fault(format, ...) __extension__({                                     \
804     _Static_assert(__builtin_constant_p(format), "format must be a constant string");   \
805     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;      \
806     OS_TRACE_CALL(format, _m, OS_TRACE_TYPE_FAULT, ##__VA_ARGS__);                      \
807 })
808 
809 #if __has_include(<xpc/xpc.h>)
810 /*!
811  * @function os_trace_with_payload
812  *
813  * @abstract
814  * Add a trace entry containing the provided values and call the block if
815  * appropriate.
816  *
817  * @discussion
818  * Will insert a trace entry into a limited ring buffer for an activity or
819  * process.  Trace points are for recording interesting data that would improve
820  * diagnosis of unexpected crashes, failures and hangs.  The block will only be
821  * called under the required conditions.
822  *
823  * @param trace_msg
824  * A printf-style format string to generate a human-readable log message when
825  * the trace line is decoded.  Only scalar types are supported. Attempts
826  * to pass arbitrary strings will store a pointer that is unresolvable and
827  * will generate an error during decode.
828  *
829  * The final parameter must be a block of type os_trace_payload_t.
830  *
831  *   os_trace_with_payload("network event %ld", event, ^(xpc_object_t xdict) {
832  *
833  *		// validate the network interface and address where what was expected
834  *		xpc_dictionary_set_string(xdict, "network", ifp->ifa_name);
835  *		xpc_dictionary_set_string(xdict, "ip_address", _get_address(ifp));
836  *   });
837  */
838 #define os_trace_with_payload(format, ...) __extension__({                                                              \
839     _Static_assert(__builtin_constant_p(format), "format must be a constant string");                                   \
840     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;                                      \
841     OS_CONCAT(_os_trace_with_payload, OS_COUNT_ARGS(__VA_ARGS__))(format, _m, OS_TRACE_TYPE_RELEASE, ##__VA_ARGS__);    \
842 })
843 
844 #define os_trace_info_with_payload(format, ...) __extension__({                                                     \
845     _Static_assert(__builtin_constant_p(format), "format must be a constant string");                               \
846     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;                                  \
847     OS_CONCAT(_os_trace_with_payload, OS_COUNT_ARGS(__VA_ARGS__))(format, _m, OS_TRACE_TYPE_INFO, ##__VA_ARGS__);   \
848 })
849 
850 #define os_trace_debug_with_payload(format, ...) __extension__({                                                    \
851     _Static_assert(__builtin_constant_p(format), "format must be a constant string");                               \
852     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;                                  \
853     OS_CONCAT(_os_trace_with_payload, OS_COUNT_ARGS(__VA_ARGS__))(format, _m, OS_TRACE_TYPE_DEBUG, ##__VA_ARGS__);  \
854 })
855 
856 #define os_trace_error_with_payload(format, ...) __extension__({                                                    \
857     _Static_assert(__builtin_constant_p(format), "format must be a constant string");                               \
858     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;                                  \
859     OS_CONCAT(_os_trace_with_payload, OS_COUNT_ARGS(__VA_ARGS__))(format, _m, OS_TRACE_TYPE_ERROR, ##__VA_ARGS__);  \
860 })
861 
862 #define os_trace_fault_with_payload(format, ...) __extension__({                                                    \
863     _Static_assert(__builtin_constant_p(format), "format must be a constant string");                               \
864     __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = format;                                  \
865     OS_CONCAT(_os_trace_with_payload, OS_COUNT_ARGS(__VA_ARGS__))(format, _m, OS_TRACE_TYPE_FAULT, ##__VA_ARGS__);  \
866 })
867 
868 #endif // __has_include(<xpc/xpc.h>)
869 
870 // TODO: change this once we have compiler support
871 __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0)
872 OS_EXPORT OS_NOTHROW
873 size_t
874 _os_trace_encode(uint8_t *buf, size_t buf_size, const char *format, ...);
875 
876 __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0)
877 OS_EXPORT OS_NOTHROW
878 void
879 _os_trace_internal(void *dso, uint8_t type, const char *format, const uint8_t *buf, size_t buf_size, os_trace_payload_t payload);
880 
881 /*!
882  * @function _os_trace_with_buffer
883  *
884  * @abstract
885  * Internal function to support pre-encoded buffer.
886  */
887 __OSX_AVAILABLE(10.10) __IOS_AVAILABLE(8.0) __WATCHOS_AVAILABLE(1.0) __TVOS_AVAILABLE(9.0)
888 OS_EXPORT OS_NOTHROW
889 void
890 _os_trace_with_buffer(void *dso, const char *message, uint8_t type, const void *buffer, size_t buffer_size, os_trace_payload_t payload);
891 
892 __END_DECLS
893 
894 #endif // __OS_TRACE_H__
895