xref: /trueos/include/os/trace.h (revision 0f8eb4123024ffec2f2cfcdb493793aea43f0cac)
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