]> git.saurik.com Git - apple/xnu.git/blame - libkern/os/trace.h
xnu-6153.61.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@
0a7de745 5 *
39037602
A
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.
0a7de745 12 *
39037602
A
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.
0a7de745 20 *
39037602
A
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
0a7de745
A
49_os_trace_verify_printf(const char *msg, ...)
50__attribute__((format(printf, 1, 2)))
39037602
A
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 */
0a7de745
A
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)
39037602
A
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__({ \
0a7de745
A
73 _Pragma("clang diagnostic push") \
74 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
75 const __typeof__(_1) _c1 = _1; \
76 _os_trace_verify_printf(_l, _c1); \
77 const struct __attribute__((packed)) { \
0a7de745
A
78 __typeof__(_c1) _f1; \
79 uint8_t _s[1]; \
80 uint8_t _cnt; \
39037602 81 } _buf = { \
0a7de745
A
82 ._f1 = _c1, ._s[0] = sizeof(_c1), \
83 ._cnt = 1, \
39037602
A
84 }; \
85 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
86 __asm__(""); /* avoid tailcall */ \
0a7de745 87 _Pragma("clang diagnostic pop") \
39037602
A
88})
89
90#define _os_trace_2(_l, _m, _t, _1, _2) __extension__({ \
0a7de745
A
91 _Pragma("clang diagnostic push") \
92 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
97 __typeof__(_c1) _f1; \
98 __typeof__(_c2) _f2; \
99 uint8_t _s[2]; \
100 uint8_t _cnt; \
39037602 101 } _buf = { \
0a7de745
A
102 ._f1 = _c1, ._s[0] = sizeof(_c1), \
103 ._f2 = _c2, ._s[1] = sizeof(_c2), \
104 ._cnt = 2, \
39037602
A
105 }; \
106 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
107 __asm__(""); /* avoid tailcall */ \
0a7de745 108 _Pragma("clang diagnostic pop") \
39037602
A
109})
110
111#define _os_trace_3(_l, _m, _t, _1, _2, _3) __extension__({ \
0a7de745
A
112 _Pragma("clang diagnostic push") \
113 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
119 __typeof__(_c1) _f1; \
120 __typeof__(_c2) _f2; \
121 __typeof__(_c3) _f3; \
122 uint8_t _s[3]; \
123 uint8_t _cnt; \
39037602 124 } _buf = { \
0a7de745
A
125 ._f1 = _c1, ._s[0] = sizeof(_c1), \
126 ._f2 = _c2, ._s[1] = sizeof(_c2), \
127 ._f3 = _c3, ._s[2] = sizeof(_c3), \
128 ._cnt = 3, \
39037602
A
129 }; \
130 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
131 __asm__(""); /* avoid tailcall */ \
0a7de745 132 _Pragma("clang diagnostic pop") \
39037602
A
133})
134
135#define _os_trace_4(_l, _m, _t, _1, _2, _3, _4) __extension__({ \
0a7de745
A
136 _Pragma("clang diagnostic push") \
137 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 150 } _buf = { \
0a7de745
A
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, \
39037602
A
156 }; \
157 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
158 __asm__(""); /* avoid tailcall */ \
0a7de745 159 _Pragma("clang diagnostic pop") \
39037602
A
160})
161
162#define _os_trace_5(_l, _m, _t, _1, _2, _3, _4, _5) __extension__({ \
0a7de745
A
163 _Pragma("clang diagnostic push") \
164 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 179 } _buf = { \
0a7de745
A
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, \
39037602
A
186 }; \
187 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
188 __asm__(""); /* avoid tailcall */ \
0a7de745 189 _Pragma("clang diagnostic pop") \
39037602
A
190})
191
192#define _os_trace_6(_l, _m, _t, _1, _2, _3, _4, _5, _6) __extension__({ \
0a7de745
A
193 _Pragma("clang diagnostic push") \
194 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 211 } _buf = { \
0a7de745
A
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, \
39037602
A
219 }; \
220 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
221 __asm__(""); /* avoid tailcall */ \
0a7de745 222 _Pragma("clang diagnostic pop") \
39037602
A
223})
224
225#define _os_trace_7(_l, _m, _t, _1, _2, _3, _4, _5, _6, _7) __extension__({ \
0a7de745
A
226 _Pragma("clang diagnostic push") \
227 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 246 } _buf = { \
0a7de745
A
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, \
39037602
A
255 }; \
256 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
257 __asm__(""); /* avoid tailcall */ \
0a7de745 258 _Pragma("clang diagnostic pop") \
39037602
A
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__({ \
0a7de745
A
268 _Pragma("clang diagnostic push") \
269 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
270 const __typeof__(_1) _c1 = _1; \
271 _os_trace_verify_printf(_l, _c1); \
272 const struct __attribute__((packed)) { \
0a7de745
A
273 __typeof__(_c1) _f1; \
274 uint8_t _s[1]; \
275 uint8_t _cnt; \
39037602 276 } _buf = { \
0a7de745
A
277 ._f1 = _c1, ._s[0] = sizeof(_c1), \
278 ._cnt = 1, \
39037602
A
279 }; \
280 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
281 __asm__(""); /* avoid tailcall */ \
0a7de745 282 _Pragma("clang diagnostic pop") \
39037602
A
283})
284
285#define _os_trace_with_payload_3(_l, _m, _t, _1, _2, _payload) __extension__({ \
0a7de745
A
286 _Pragma("clang diagnostic push") \
287 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
292 __typeof__(_c1) _f1; \
293 __typeof__(_c2) _f2; \
294 uint8_t _s[2]; \
295 uint8_t _cnt; \
39037602 296 } _buf = { \
0a7de745
A
297 ._f1 = _c1, ._s[0] = sizeof(_c1), \
298 ._f2 = _c2, ._s[1] = sizeof(_c2), \
299 ._cnt = 2, \
39037602
A
300 }; \
301 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
302 __asm__(""); /* avoid tailcall */ \
0a7de745 303 _Pragma("clang diagnostic pop") \
39037602
A
304})
305
306#define _os_trace_with_payload_4(_l, _m, _t, _1, _2, _3, _payload) __extension__({ \
0a7de745
A
307 _Pragma("clang diagnostic push") \
308 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
314 __typeof__(_c1) _f1; \
315 __typeof__(_c2) _f2; \
316 __typeof__(_c3) _f3; \
317 uint8_t _s[3]; \
318 uint8_t _cnt; \
39037602 319 } _buf = { \
0a7de745
A
320 ._f1 = _c1, ._s[0] = sizeof(_c1), \
321 ._f2 = _c2, ._s[1] = sizeof(_c2), \
322 ._f3 = _c3, ._s[2] = sizeof(_c3), \
323 ._cnt = 3, \
39037602
A
324 }; \
325 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
326 __asm__(""); /* avoid tailcall */ \
0a7de745 327 _Pragma("clang diagnostic pop") \
39037602
A
328})
329
330#define _os_trace_with_payload_5(_l, _m, _t, _1, _2, _3, _4, _payload) __extension__({ \
0a7de745
A
331 _Pragma("clang diagnostic push") \
332 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 345 } _buf = { \
0a7de745
A
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, \
39037602
A
351 }; \
352 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
353 __asm__(""); /* avoid tailcall */ \
0a7de745 354 _Pragma("clang diagnostic pop") \
39037602
A
355})
356
357#define _os_trace_with_payload_6(_l, _m, _t, _1, _2, _3, _4, _5, _payload) __extension__({ \
0a7de745
A
358 _Pragma("clang diagnostic push") \
359 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 374 } _buf = { \
0a7de745
A
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, \
39037602
A
381 }; \
382 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
383 __asm__(""); /* avoid tailcall */ \
0a7de745 384 _Pragma("clang diagnostic pop") \
39037602
A
385})
386
387#define _os_trace_with_payload_7(_l, _m, _t, _1, _2, _3, _4, _5, _6, _payload) __extension__({ \
0a7de745
A
388 _Pragma("clang diagnostic push") \
389 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 406 } _buf = { \
0a7de745
A
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, \
39037602
A
414 }; \
415 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
416 __asm__(""); /* avoid tailcall */ \
0a7de745 417 _Pragma("clang diagnostic pop") \
39037602
A
418})
419
420#define _os_trace_with_payload_8(_l, _m, _t, _1, _2, _3, _4, _5, _6, _7, _payload) __extension__({ \
0a7de745
A
421 _Pragma("clang diagnostic push") \
422 _Pragma("clang diagnostic ignored \"-Wpacked\"") \
39037602
A
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)) { \
0a7de745
A
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; \
39037602 441 } _buf = { \
0a7de745
A
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, \
39037602
A
450 }; \
451 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
452 __asm__(""); /* avoid tailcall */ \
0a7de745 453 _Pragma("clang diagnostic pop") \
39037602
A
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
0a7de745
A
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
39037602
A
615 * the format or structure of the data.
616 */
617typedef 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
0a7de745
A
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)
39037602
A
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)
729OS_EXPORT OS_NOTHROW OS_WARN_RESULT
730bool
731os_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)
755OS_EXPORT OS_NOTHROW OS_WARN_RESULT
756bool
757os_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)
872OS_EXPORT OS_NOTHROW
873size_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)
877OS_EXPORT OS_NOTHROW
878void
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)
888OS_EXPORT OS_NOTHROW
889void
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__