1 /*
2 * Copyright (c) 2013-2014 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 <inttypes.h>
28 #include <os/base.h>
29 #include <sys/types.h>
30 #include <stdbool.h>
31 #if __has_include(<xpc/xpc.h>)
32 #include <xpc/xpc.h>
33 #else
34 typedef void *xpc_object_t;
35 #endif
36
37 #if !__GNUC__
38 #error "must be GNU C compatible"
39 #endif
40
41 extern void *__dso_handle;
42
43 OS_ALWAYS_INLINE __attribute__((format(printf,1,2)))
_os_trace_verify_printf(const char * msg,...)44 static inline void _os_trace_verify_printf(const char *msg, ...) { (void) msg; }
45
46 #if !defined OS_COUNT_ARGS
47 #define OS_COUNT_ARGS(...) OS_COUNT_ARGS1(,##__VA_ARGS__,_8,_7,_6,_5,_4,_3,_2,_1,_0)
48 #define OS_COUNT_ARGS1(z,a,b,c,d,e,f,g,h,cnt,...) cnt
49 #endif
50
51 #define _os_trace_0(_m, _t) __extension__({ \
52 _os_trace_verify_printf(_m); \
53 _os_trace_with_buffer(&__dso_handle, _m, _t, NULL, 0, NULL); \
54 asm(""); /* avoid tailcall */ \
55 })
56
57 #define _os_trace_1(_m, _t, _1) __extension__({ \
58 const typeof(_1) _c1 = _1; \
59 _os_trace_verify_printf(_m, _c1); \
60 const struct __attribute__((packed)) { \
61 typeof(_c1) _f1; \
62 } _buf = { \
63 ._f1 = _c1, \
64 }; \
65 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
66 asm(""); /* avoid tailcall */ \
67 })
68
69 #define _os_trace_2(_m, _t, _1, _2) __extension__({ \
70 const typeof(_1) _c1 = _1; \
71 const typeof(_2) _c2 = _2; \
72 _os_trace_verify_printf(_m, _c1, _c2); \
73 const struct __attribute__((packed)) { \
74 typeof(_c1) _f1; \
75 typeof(_c2) _f2; \
76 } _buf = { \
77 ._f1 = _c1, \
78 ._f2 = _c2, \
79 }; \
80 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
81 asm(""); /* avoid tailcall */ \
82 })
83
84 #define _os_trace_3(_m, _t, _1, _2, _3) __extension__({ \
85 const typeof(_1) _c1 = _1; \
86 const typeof(_2) _c2 = _2; \
87 const typeof(_3) _c3 = _3; \
88 _os_trace_verify_printf(_m, _c1, _c2, _c3); \
89 const struct __attribute__((packed)) { \
90 typeof(_c1) _f1; \
91 typeof(_c2) _f2; \
92 typeof(_c3) _f3; \
93 } _buf = { \
94 ._f1 = _c1, \
95 ._f2 = _c2, \
96 ._f3 = _c3, \
97 }; \
98 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
99 asm(""); /* avoid tailcall */ \
100 })
101
102 #define _os_trace_4(_m, _t, _1, _2, _3, _4) __extension__({ \
103 const typeof(_1) _c1 = _1; \
104 const typeof(_2) _c2 = _2; \
105 const typeof(_3) _c3 = _3; \
106 const typeof(_4) _c4 = _4; \
107 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4); \
108 const struct __attribute__((packed)) { \
109 typeof(_c1) _f1; \
110 typeof(_c2) _f2; \
111 typeof(_c3) _f3; \
112 typeof(_c4) _f4; \
113 } _buf = { \
114 ._f1 = _c1, \
115 ._f2 = _c2, \
116 ._f3 = _c3, \
117 ._f4 = _c4, \
118 }; \
119 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
120 asm(""); /* avoid tailcall */ \
121 })
122
123 #define _os_trace_5(_m, _t, _1, _2, _3, _4, _5) __extension__({ \
124 const typeof(_1) _c1 = _1; \
125 const typeof(_2) _c2 = _2; \
126 const typeof(_3) _c3 = _3; \
127 const typeof(_4) _c4 = _4; \
128 const typeof(_5) _c5 = _5; \
129 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4, _c5); \
130 const struct __attribute__((packed)) { \
131 typeof(_c1) _f1; \
132 typeof(_c2) _f2; \
133 typeof(_c3) _f3; \
134 typeof(_c4) _f4; \
135 typeof(_c5) _f5; \
136 } _buf = { \
137 ._f1 = _c1, \
138 ._f2 = _c2, \
139 ._f3 = _c3, \
140 ._f4 = _c4, \
141 ._f5 = _c5, \
142 }; \
143 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
144 asm(""); /* avoid tailcall */ \
145 })
146
147 #define _os_trace_6(_m, _t, _1, _2, _3, _4, _5, _6) __extension__({ \
148 const typeof(_1) _c1 = _1; \
149 const typeof(_2) _c2 = _2; \
150 const typeof(_3) _c3 = _3; \
151 const typeof(_4) _c4 = _4; \
152 const typeof(_5) _c5 = _5; \
153 const typeof(_6) _c6 = _6; \
154 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4, _c5, _c6); \
155 const struct __attribute__((packed)) { \
156 typeof(_c1) _f1; \
157 typeof(_c2) _f2; \
158 typeof(_c3) _f3; \
159 typeof(_c4) _f4; \
160 typeof(_c5) _f5; \
161 typeof(_c6) _f6; \
162 } _buf = { \
163 ._f1 = _c1, \
164 ._f2 = _c2, \
165 ._f3 = _c3, \
166 ._f4 = _c4, \
167 ._f5 = _c5, \
168 ._f6 = _c6, \
169 }; \
170 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
171 asm(""); /* avoid tailcall */ \
172 })
173
174 #define _os_trace_7(_m, _t, _1, _2, _3, _4, _5, _6, _7) __extension__({ \
175 const typeof(_1) _c1 = _1; \
176 const typeof(_2) _c2 = _2; \
177 const typeof(_3) _c3 = _3; \
178 const typeof(_4) _c4 = _4; \
179 const typeof(_5) _c5 = _5; \
180 const typeof(_6) _c6 = _6; \
181 const typeof(_7) _c7 = _7; \
182 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4, _c5, _c6, _c7); \
183 const struct __attribute__((packed)) { \
184 typeof(_c1) _f1; \
185 typeof(_c2) _f2; \
186 typeof(_c3) _f3; \
187 typeof(_c4) _f4; \
188 typeof(_c5) _f5; \
189 typeof(_c6) _f6; \
190 typeof(_c7) _f7; \
191 } _buf = { \
192 ._f1 = _c1, \
193 ._f2 = _c2, \
194 ._f3 = _c3, \
195 ._f4 = _c4, \
196 ._f5 = _c5, \
197 ._f6 = _c6, \
198 ._f7 = _c7, \
199 }; \
200 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), NULL); \
201 asm(""); /* avoid tailcall */ \
202 })
203
204 #define _os_trace_with_payload_1(_m, _t, _payload) __extension__({ \
205 _os_trace_with_buffer(&__dso_handle, _m, _t, NULL, 0, _payload); \
206 asm(""); /* avoid tailcall */ \
207 })
208
209 #define _os_trace_with_payload_2(_m, _t, _1, _payload) __extension__({ \
210 const typeof(_1) _c1 = _1; \
211 _os_trace_verify_printf(_m, _c1); \
212 const struct __attribute__((packed)) { \
213 typeof(_c1) _f1; \
214 } _buf = { \
215 ._f1 = _c1, \
216 }; \
217 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
218 asm(""); /* avoid tailcall */ \
219 })
220
221 #define _os_trace_with_payload_3(_m, _t, _1, _2, _payload) __extension__({ \
222 const typeof(_1) _c1 = _1; \
223 const typeof(_2) _c2 = _2; \
224 _os_trace_verify_printf(_m, _c1, _c2); \
225 const struct __attribute__((packed)) { \
226 typeof(_c1) _f1; \
227 typeof(_c2) _f2; \
228 } _buf = { \
229 ._f1 = _c1, \
230 ._f2 = _c2, \
231 }; \
232 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
233 asm(""); /* avoid tailcall */ \
234 })
235
236 #define _os_trace_with_payload_4(_m, _t, _1, _2, _3, _payload) __extension__({ \
237 const typeof(_1) _c1 = _1; \
238 const typeof(_2) _c2 = _2; \
239 const typeof(_3) _c3 = _3; \
240 _os_trace_verify_printf(_m, _c1, _c2, _c3); \
241 const struct __attribute__((packed)) { \
242 typeof(_c1) _f1; \
243 typeof(_c2) _f2; \
244 typeof(_c3) _f3; \
245 } _buf = { \
246 ._f1 = _c1, \
247 ._f2 = _c2, \
248 ._f3 = _c3, \
249 }; \
250 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
251 asm(""); /* avoid tailcall */ \
252 })
253
254 #define _os_trace_with_payload_5(_m, _t, _1, _2, _3, _4, _payload) __extension__({ \
255 const typeof(_1) _c1 = _1; \
256 const typeof(_2) _c2 = _2; \
257 const typeof(_3) _c3 = _3; \
258 const typeof(_4) _c4 = _4; \
259 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4); \
260 const struct __attribute__((packed)) { \
261 typeof(_c1) _f1; \
262 typeof(_c2) _f2; \
263 typeof(_c3) _f3; \
264 typeof(_c4) _f4; \
265 } _buf = { \
266 ._f1 = _c1, \
267 ._f2 = _c2, \
268 ._f3 = _c3, \
269 ._f4 = _c4, \
270 }; \
271 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
272 asm(""); /* avoid tailcall */ \
273 })
274
275 #define _os_trace_with_payload_6(_m, _t, _1, _2, _3, _4, _5, _payload) __extension__({ \
276 const typeof(_1) _c1 = _1; \
277 const typeof(_2) _c2 = _2; \
278 const typeof(_3) _c3 = _3; \
279 const typeof(_4) _c4 = _4; \
280 const typeof(_4) _c5 = _5; \
281 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4, _c5); \
282 const struct __attribute__((packed)) { \
283 typeof(_c1) _f1; \
284 typeof(_c2) _f2; \
285 typeof(_c3) _f3; \
286 typeof(_c4) _f4; \
287 typeof(_c5) _f5; \
288 } _buf = { \
289 ._f1 = _c1, \
290 ._f2 = _c2, \
291 ._f3 = _c3, \
292 ._f4 = _c4, \
293 ._f5 = _c5, \
294 }; \
295 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
296 asm(""); /* avoid tailcall */ \
297 })
298
299 #define _os_trace_with_payload_7(_m, _t, _1, _2, _3, _4, _5, _6, _payload) __extension__({ \
300 const typeof(_1) _c1 = _1; \
301 const typeof(_2) _c2 = _2; \
302 const typeof(_3) _c3 = _3; \
303 const typeof(_4) _c4 = _4; \
304 const typeof(_5) _c5 = _5; \
305 const typeof(_6) _c6 = _6; \
306 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4, _c5, _c6); \
307 const struct __attribute__((packed)) { \
308 typeof(_c1) _f1; \
309 typeof(_c2) _f2; \
310 typeof(_c3) _f3; \
311 typeof(_c4) _f4; \
312 typeof(_c5) _f5; \
313 typeof(_c6) _f6; \
314 } _buf = { \
315 ._f1 = _c1, \
316 ._f2 = _c2, \
317 ._f3 = _c3, \
318 ._f4 = _c4, \
319 ._f5 = _c5, \
320 ._f6 = _c6, \
321 }; \
322 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
323 asm(""); /* avoid tailcall */ \
324 })
325
326 #define _os_trace_with_payload_8(_m, _t, _1, _2, _3, _4, _5, _6, _7, _payload) __extension__({ \
327 const typeof(_1) _c1 = _1; \
328 const typeof(_2) _c2 = _2; \
329 const typeof(_3) _c3 = _3; \
330 const typeof(_4) _c4 = _4; \
331 const typeof(_5) _c5 = _5; \
332 const typeof(_6) _c6 = _6; \
333 const typeof(_7) _c7 = _7; \
334 _os_trace_verify_printf(_m, _c1, _c2, _c3, _c4, _c5, _c6, _c7); \
335 const struct __attribute__((packed)) { \
336 typeof(_c1) _f1; \
337 typeof(_c2) _f2; \
338 typeof(_c3) _f3; \
339 typeof(_c4) _f4; \
340 typeof(_c5) _f5; \
341 typeof(_c6) _f6; \
342 typeof(_c7) _f7; \
343 } _buf = { \
344 ._f1 = _c1, \
345 ._f2 = _c2, \
346 ._f3 = _c3, \
347 ._f4 = _c4, \
348 ._f5 = _c5, \
349 ._f6 = _c6, \
350 ._f7 = _c7, \
351 }; \
352 _os_trace_with_buffer(&__dso_handle, _m, _t, &_buf, sizeof(_buf), _payload); \
353 asm(""); /* avoid tailcall */ \
354 })
355
356 #pragma mark - Other defines
357
358 /*!
359 * @define OS_TRACE_TYPE_RELEASE
360 * Trace messages to be recorded on a typical user install. These should be
361 * limited to things which improve diagnosis of a failure/crash/hang. Trace
362 * buffers are generally smaller on a production system.
363 */
364 #define OS_TRACE_TYPE_RELEASE (1u << 0)
365
366 /*!
367 * @define OS_TRACE_TYPE_DEBUG
368 * Trace messages to be recorded while debugger or other development tool is
369 * attached to the originator. This is transported interprocess.
370 */
371 #define OS_TRACE_TYPE_DEBUG (1u << 1)
372
373 /*!
374 * @define OS_TRACE_TYPE_ERROR
375 * Trace the message as an error and force a collection as a failure may be
376 * imminent.
377 */
378 #define OS_TRACE_TYPE_ERROR ((1u << 6) | (1u << 0))
379
380 /*!
381 * @define OS_TRACE_TYPE_FAULT
382 * Trace the message as a fatal error which forces a collection and a diagnostic
383 * to be initiated.
384 */
385 #define OS_TRACE_TYPE_FAULT ((1u << 7) | (1u << 6) | (1u << 0))
386
387 __BEGIN_DECLS
388
389 /*!
390 * @typedef os_trace_payload_t
391 * A block that populates an xpc_object_t of type XPC_TYPE_DICTIONARY to represent
392 * complex data. This block will only be invoked under conditions where tools
393 * have attached to the process. The payload can be used to send arbitrary data
394 * via the trace call. Tools may use the data to validate state for integration
395 * tests or provide other introspection services. No assumptions are made about
396 * the format or structure of the data.
397 */
398 typedef void (^os_trace_payload_t)(xpc_object_t xdict);
399
400 #pragma mark - function declarations
401
402 /*!
403 * @function os_trace
404 *
405 * @abstract
406 * Insert a trace message into a ring-buffer for later decoding.
407 *
408 * @discussion
409 * Trace message that will be recorded on a typical user install. These should
410 * be limited to things which help diagnose a failure during postmortem
411 * analysis. Trace buffers are generally smaller on a production system.
412 *
413 * @param logmsg
414 * A printf-style format string to generate a human-readable log message when
415 * the trace line is decoded. Only scalar types are supported, attempts
416 * to pass arbitrary strings will store a pointer that is unresolvable and
417 * will generate an error during decode.
418 *
419 * os_trace("network event: %ld, last seen: %ld, avg: %g", event_id, last_seen, avg);
420 */
421 #define os_trace(logmsg, ...) do { \
422 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
423 __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = logmsg; \
424 OS_CONCAT(_os_trace,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_RELEASE, ##__VA_ARGS__); \
425 } while (0)
426
427 /*!
428 * @function os_trace_debug
429 *
430 * @abstract
431 * Insert a trace message into a ring-buffer for later decoding.
432 *
433 * @discussion
434 * Trace message to be recorded while debugger or other development tool is
435 * attached to the originator. This is transported interprocess to help
436 * diagnose the entire call chain including external helpers.
437 *
438 * @param logmsg
439 * A printf-style format string that represents a human-readable message when
440 * the trace line is decoded. Only scalar types are supported, attempts
441 * to pass arbitrary strings will store a pointer that is unresolvable and
442 * will generate an error during decode.
443 *
444 * os_trace_debug("network interface status %ld", status);
445 */
446 #define os_trace_debug(logmsg, ...) do { \
447 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
448 __attribute__((section("__TEXT,__os_trace_debug"))) static const char _m[] = logmsg; \
449 OS_CONCAT(_os_trace,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
450 } while (0)
451
452 /*!
453 * @function os_trace_debug_enabled
454 *
455 * @abstract
456 * Avoid unnecessary work for a trace point by checking if debug level is enabled.
457 *
458 * @discussion
459 * Avoid unnecessary work for a trace point by checking if debug level is enabled.
460 * Generally trace points should not involve expensive operations, but some
461 * circumstances warrant it. Use this function to avoid doing the work unless
462 * debug level trace messages are requested.
463 *
464 * if (os_trace_debug_enabled()) {
465 * os_trace_debug("value = %d, average = %d",
466 * [[dict objectForKey: @"myKey"] intValue],
467 * (int) [self getAverage: dict]);
468 * }
469 *
470 * @result
471 * Returns true if debug mode is enabled.
472 */
473 __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
474 OS_EXPORT OS_NOTHROW OS_WARN_RESULT
475 bool
476 os_trace_debug_enabled(void);
477
478 /*!
479 * @function os_trace_error
480 *
481 * @abstract
482 * Trace the message as an error and force a collection of the trace buffer as a
483 * failure may be imminent.
484 *
485 * @discussion
486 * Trace the message as an error and force a collection of the trace buffer as a
487 * failure may be imminent.
488 *
489 * @param logmsg
490 * A printf-style format string to generate a human-readable log message when
491 * the trace line is decoded. Only scalar types are supported, attempts
492 * to pass arbitrary strings will store a pointer that is unresolvable and
493 * will generate an error during decode.
494 *
495 * os_trace_error("socket %d connection timeout %ld", fd, secs);
496 */
497 #define os_trace_error(logmsg, ...) do { \
498 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
499 __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = logmsg; \
500 OS_CONCAT(_os_trace,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_ERROR, ##__VA_ARGS__); \
501 } while (0)
502
503 /*!
504 * @function os_trace_fault
505 *
506 * @abstract
507 * Trace the message as a fault which forces a collection of the trace buffer
508 * and diagnostic of the activity.
509 *
510 * @discussion
511 * Trace the message as a fault which forces a collection of the trace buffer
512 * and diagnostic of the activity.
513 *
514 * @param logmsg
515 * A printf-style format string to generate a human-readable log message when
516 * the trace line is decoded. Only scalar types are supported, attempts
517 * to pass arbitrary strings will store a pointer that is unresolvable and
518 * will generate an error during decode.
519 *
520 * os_trace_fault("failed to lookup uid %d - aborting", uid);
521 */
522 #define os_trace_fault(logmsg, ...) do { \
523 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
524 __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = logmsg; \
525 OS_CONCAT(_os_trace,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_FAULT, ##__VA_ARGS__); \
526 } while (0)
527
528 #if __has_include(<xpc/xpc.h>)
529 /*!
530 * @function os_trace_with_payload
531 *
532 * @abstract
533 * Add a trace entry containing the provided values and call the block if
534 * appropriate.
535 *
536 * @discussion
537 * Will insert a trace entry into a limited ring buffer for an activity or
538 * process. Trace points are for recording interesting data that would improve
539 * diagnosis of unexpected crashes, failures and hangs. The block will only be
540 * called under the required conditions.
541 *
542 * @param trace_msg
543 * A printf-style format string to generate a human-readable log message when
544 * the trace line is decoded. Only scalar types are supported. Attempts
545 * to pass arbitrary strings will store a pointer that is unresolvable and
546 * will generate an error during decode.
547 *
548 * The final parameter must be a block of type os_trace_payload_t.
549 *
550 * os_trace_with_payload("network event %ld", event, ^(xpc_object_t xdict) {
551 *
552 * // validate the network interface and address where what was expected
553 * xpc_dictionary_set_string(xdict, "network", ifp->ifa_name);
554 * xpc_dictionary_set_string(xdict, "ip_address", _get_address(ifp));
555 * });
556 */
557 #define os_trace_with_payload(logmsg, ...) do { \
558 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
559 __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = logmsg; \
560 OS_CONCAT(_os_trace_with_payload,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_RELEASE, ##__VA_ARGS__); \
561 } while (0)
562
563 #define os_trace_debug_with_payload(logmsg, ...) do { \
564 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
565 __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = logmsg; \
566 OS_CONCAT(_os_trace_with_payload,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_DEBUG, ##__VA_ARGS__); \
567 } while (0)
568
569 #define os_trace_error_with_payload(logmsg, ...) do { \
570 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
571 __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = logmsg; \
572 OS_CONCAT(_os_trace_with_payload,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_ERROR, ##__VA_ARGS__); \
573 } while (0)
574
575 #define os_trace_fault_with_payload(logmsg, ...) do { \
576 __attribute__((unused)) char _verify_const_msg[__builtin_constant_p(logmsg) ? 1 : -1]; \
577 __attribute__((section("__TEXT,__os_trace"))) static const char _m[] = logmsg; \
578 OS_CONCAT(_os_trace_with_payload,OS_COUNT_ARGS(__VA_ARGS__))(_m, OS_TRACE_TYPE_FAULT, ##__VA_ARGS__); \
579 } while (0)
580
581 #endif // __has_include(<xpc/xpc.h>)
582
583 /*!
584 * @function _os_trace_with_buffer
585 *
586 * @abstract
587 * Internal function to support pre-encoded buffer.
588 */
589 __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
590 OS_EXPORT OS_NOTHROW
591 void
592 _os_trace_with_buffer(void *dso, const char *message, uint8_t type, const void *buffer, size_t buffer_size, os_trace_payload_t payload);
593
594 __END_DECLS
595
596 #endif
597