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