]> git.saurik.com Git - apple/libc.git/blob - os/assumes.h
b25abbd7f024e411d81c433276274e589f3390f6
[apple/libc.git] / os / assumes.h
1 /* Copyright (c) 2012, 2012 Apple Inc. All rights reserved.
2 *
3 * @APPLE_LICENSE_HEADER_START@
4 *
5 * This file contains Original Code and/or Modifications of Original Code
6 * as defined in and that are subject to the Apple Public Source License
7 * Version 2.0 (the 'License'). You may not use this file except in
8 * compliance with the License. Please obtain a copy of the License at
9 * http://www.opensource.apple.com/apsl/ and read it before using this
10 * file.
11 *
12 * The Original Code and all software distributed under the License are
13 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
17 * Please see the License for the specific language governing rights and
18 * limitations under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #ifndef __OS_ASSUMES_H__
24 #define __OS_ASSUMES_H__
25
26 #include <sys/cdefs.h>
27 #include <stdalign.h>
28
29 __BEGIN_DECLS
30
31 #include <Availability.h>
32 #include <TargetConditionals.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <stdarg.h>
36 #include <stdbool.h>
37 #include <_simple.h>
38 #include <errno.h>
39 #include <os/base_private.h>
40
41 #if __GNUC__
42 #define os_constant(x) __builtin_constant_p((x))
43 #define os_hardware_trap() __asm__ __volatile__ (""); __builtin_trap()
44 #define __OS_COMPILETIME_ASSERT__(e) __extension__({ \
45 char __compile_time_assert__[(e) ? 1 : -1]; \
46 (void)__compile_time_assert__; \
47 })
48 #else /* __GNUC__ */
49 #define os_constant(x) ((long)0)
50 #define os_hardware_trap() abort()
51 #define __OS_COMPILETIME_ASSERT__(e) (e)
52 #endif /* __GNUC__ */
53
54 #pragma mark os_crash
55
56 /*
57 * os_crash() is like os_hardware_trap(), except you get to pass in a crash
58 * message, and it can be redirected to a callback function using
59 * os_set_crash_callback()
60 */
61
62 #define __os_crash_simple(msg) \
63 ({ \
64 _os_crash(msg); \
65 os_hardware_trap(); \
66 })
67
68 #if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE)
69 #include <os/log_private.h>
70
71 #define __os_crash_fmt(...) \
72 ({ \
73 const size_t size = os_log_pack_size(__VA_ARGS__); \
74 uint8_t buf[size] __attribute__((aligned(alignof(os_log_pack_s)))); \
75 os_log_pack_t pack = (os_log_pack_t)&buf; \
76 os_log_pack_fill(pack, size, errno, __VA_ARGS__); \
77 _os_crash_fmt(pack, size); \
78 os_hardware_trap(); \
79 })
80
81 #define __os_crash_N(msg) __os_crash_simple(msg)
82 #define __os_crash_Y(...) __os_crash_fmt(__VA_ARGS__)
83
84 // Returns Y if >1 argument, N if just one argument.
85 #define __thirty_second_argument(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
86 _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, \
87 _26, _27, _28, _29, _30, _31, _32, ...) _32
88 #define __has_more_than_one_argument(...) __thirty_second_argument(__VA_ARGS__, \
89 Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, Y, \
90 Y, Y, Y, Y, Y, Y, Y, N, EXTRA)
91
92 #define __os_crash_invoke(variant, ...) \
93 OS_CONCAT(__os_crash_, variant)(__VA_ARGS__)
94
95 #define os_crash(...) \
96 __os_crash_invoke(__has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
97
98 extern void
99 _os_crash_fmt(os_log_pack_t, size_t);
100
101 #else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
102
103 #define os_crash(msg) __os_crash_simple(msg)
104
105 #endif // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
106
107 /*
108 * An executable can register a callback to be made upon a crash using the
109 * os_set_crash_callback function. If a crash callback is not set, the symbol
110 * `os_crash_function` will be called in the main binary, if it exists.
111 */
112
113 typedef void (*os_crash_callback_t) (const char *);
114
115 /* private: use accessors below */
116 extern os_crash_callback_t _os_crash_callback;
117
118 static inline os_crash_callback_t
119 os_get_crash_callback() {
120 return _os_crash_callback;
121 }
122
123 static inline void
124 os_set_crash_callback(os_crash_callback_t callback) {
125 _os_crash_callback = callback;
126 }
127
128 #pragma mark os_assert
129
130 #if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE)
131
132 #define _os_assert_crash(value, expression) ({ \
133 os_crash("assertion failure: \"" expression "\" -> %lld", value); \
134 })
135
136 #define _os_assert_crash_errno(value, expression) ({ \
137 os_crash("assertion failure: \"" expression "\" -> %{errno}d", value); \
138 })
139
140 #else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
141
142 #define _os_assert_crash(e, ...) ({ \
143 char *_fail_message = _os_assert_log(e); \
144 os_crash(_fail_message); \
145 free(_fail_message); \
146 })
147
148 #define _os_assert_crash_errno(...) _os_assert_crash(__VA_ARGS__)
149
150 #endif // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
151
152 #define __os_assert(e) __extension__({ \
153 __typeof__(e) _e = (e); \
154 if (os_unlikely(!_e)) { \
155 if (os_constant(e)) { __OS_COMPILETIME_ASSERT__((e)); } \
156 _os_assert_crash((uint64_t)(uintptr_t)_e, #e); \
157 } \
158 })
159
160 #define __os_assert_zero(e) __extension__({ \
161 __typeof__(e) _e = (e); \
162 if (os_unlikely(_e)) { \
163 if (os_constant(e)) { __OS_COMPILETIME_ASSERT__(!(e)); } \
164 _os_assert_crash((uint64_t)(uintptr_t)_e, #e); \
165 } \
166 })
167
168 /*
169 * This variant is for use with old-style POSIX APIs that return -1 on failure
170 * and set errno. If the return code is -1, the value logged will be as though
171 * os_assert_zero(errno) was used. It encapsulates the following pattern:
172 *
173 * int tubes[2];
174 * if (pipe(tubes) == -1) {
175 * (void)os_assert_zero(errno);
176 * }
177 */
178 #define __posix_assert_zero(e) __extension__({ \
179 __typeof__(e) _e = (e); \
180 if (os_unlikely(_e == (__typeof__(e))-1)) { \
181 _os_assert_crash_errno(errno, #e); \
182 } \
183 })
184
185 #if defined(OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE)
186
187 #define __os_assert_msg(e, fmt, ...) __extension__({ \
188 __typeof__(e) _e = (e); \
189 if (os_unlikely(!_e)) { \
190 os_crash("assertion failure: " fmt, ##__VA_ARGS__); \
191 } \
192 })
193
194 #define __os_assert_zero_msg(e, fmt, ...) __extension__({ \
195 __typeof__(e) _e = (e); \
196 if (os_unlikely(_e)) { \
197 os_crash("assertion failure (%lld): " fmt, value, ##__VA_ARGS__); \
198 } \
199 })
200
201 #define __posix_assert_zero_msg(e, fmt, ...) __extension__({ \
202 __typeof__(e) _e = (e); \
203 if (os_unlikely(_e == (__typeof__(e))-1)) { \
204 os_crash("assertion failure (%{errno}d): " fmt, errno, ##__VA_ARGS__); \
205 } \
206 })
207
208 #define __os_assert_N(e) __os_assert(e)
209 #define __os_assert_Y(...) __os_assert_msg(__VA_ARGS__)
210 #define __os_assert_zero_N(e) __os_assert_zero(e)
211 #define __os_assert_zero_Y(...) __os_assert_zero_msg(__VA_ARGS__)
212 #define __posix_assert_zero_N(e) __posix_assert_zero(e)
213 #define __posix_assert_zero_Y(...) __posix_assert_zero_msg(__VA_ARGS__)
214
215 #define __os_assert_invoke(function, variant, ...) \
216 OS_CONCAT(function, variant)(__VA_ARGS__)
217
218 #define os_assert(...) \
219 __os_assert_invoke(__os_assert_, \
220 __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
221 #define os_assert_zero(...) \
222 __os_assert_invoke(__os_assert_zero_, \
223 __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
224 #define posix_assert_zero(...) \
225 __os_assert_invoke(__posix_assert_zero_, \
226 __has_more_than_one_argument(__VA_ARGS__), __VA_ARGS__)
227
228 #else // OS_CRASH_ENABLE_EXPERIMENTAL_LIBTRACE
229
230 #define os_assert(e) __os_assert(e)
231 #define os_assert_zero(e) __os_assert_zero(e)
232 #define posix_assert_zero(e) __posix_assert_zero(e)
233
234 #endif
235
236 #pragma mark os_assumes
237
238
239 #define os_assumes(e) __extension__({ \
240 __typeof__(e) _e = os_fastpath(e); \
241 if (!_e) { \
242 if (os_constant(e)) { \
243 __OS_COMPILETIME_ASSERT__(e); \
244 } \
245 _os_assumes_log((uint64_t)(uintptr_t)_e); \
246 _os_avoid_tail_call(); \
247 } \
248 _e; \
249 })
250
251 #define os_assumes_zero(e) __extension__({ \
252 __typeof__(e) _e = os_slowpath(e); \
253 if (_e) { \
254 if (os_constant(e)) { \
255 __OS_COMPILETIME_ASSERT__(!(e)); \
256 } \
257 _os_assumes_log((uint64_t)(uintptr_t)_e); \
258 _os_avoid_tail_call(); \
259 } \
260 _e; \
261 })
262
263 #define posix_assumes_zero(e) __extension__({ \
264 __typeof__(e) _e = os_slowpath(e); \
265 if (_e == (__typeof__(e))-1) { \
266 _os_assumes_log((uint64_t)(uintptr_t)errno); \
267 _os_avoid_tail_call(); \
268 } \
269 _e; \
270 })
271
272 #pragma mark assumes redirection
273
274 /* This is useful for clients who wish for the messages generated by assumes()
275 * failures to go somewhere other than (or in addition to) the system log. If
276 * you don't wish for the message to be logged to the system log, then return
277 * true (to indicate that the message has been handled). If you want the default
278 * behavior, return false.
279 */
280 typedef bool (*os_redirect_t)(const char *);
281 struct _os_redirect_assumes_s {
282 os_redirect_t redirect;
283 };
284
285 #define OS_ASSUMES_REDIRECT_SEG "__DATA"
286 #define OS_ASSUMES_REDIRECT_SECT "__os_assumes_log"
287
288 #define os_redirect_assumes(func) \
289 __attribute__((__used__)) \
290 __attribute__((__section__(OS_ASSUMES_REDIRECT_SEG "," OS_ASSUMES_REDIRECT_SECT))) \
291 static struct _os_redirect_assumes_s _os_redirect_##func = { \
292 .redirect = &func, \
293 };
294
295 #pragma mark _ctx variants
296
297 /*
298 * These are for defining your own assumes()-like wrapper calls so that you can
299 * log additional information, such as the about-PID, sender, etc. They're
300 * generally not useful for direct inclusion in your code.
301 */
302
303 /*
304 * The asl_message argument is a _SIMPLE_STRING that, when given to _simple_asl_send(), will
305 * direct the message to the MessageTracer diagnostic messages store rather than
306 * the default system log store.
307 */
308 typedef bool (*os_log_callout_t)(_SIMPLE_STRING asl_message, void *ctx, const char *);
309
310
311 #define os_assumes_ctx(f, ctx, e) __extension__({ \
312 __typeof__(e) _e = os_fastpath(e); \
313 if (!_e) { \
314 if (os_constant(e)) { \
315 __OS_COMPILETIME_ASSERT__(e); \
316 } \
317 _os_assumes_log_ctx(f, ctx, (uintptr_t)_e); \
318 _os_avoid_tail_call(); \
319 } \
320 _e; \
321 })
322
323 #define os_assumes_zero_ctx(f, ctx, e) __extension__({ \
324 __typeof__(e) _e = os_slowpath(e); \
325 if (_e) { \
326 if (os_constant(e)) { \
327 __OS_COMPILETIME_ASSERT__(!(e)); \
328 } \
329 _os_assumes_log_ctx((f), (ctx), (uintptr_t)_e); \
330 _os_avoid_tail_call(); \
331 } \
332 _e; \
333 })
334
335 #define posix_assumes_zero_ctx(f, ctx, e) __extension__({ \
336 __typeof__(e) _e = os_slowpath(e); \
337 if (_e == (__typeof__(e))-1) { \
338 _os_assumes_log_ctx((f), (ctx), (uintptr_t)errno); \
339 _os_avoid_tail_call(); \
340 } \
341 _e; \
342 })
343
344 #define os_assert_ctx(f, ctx, e) __extension__({ \
345 __typeof__(e) _e = os_fastpath(e); \
346 if (!_e) { \
347 if (os_constant(e)) { \
348 __OS_COMPILETIME_ASSERT__(e); \
349 } \
350 \
351 char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \
352 os_crash(_fail_message); \
353 free(_fail_message); \
354 } \
355 })
356
357 #define os_assert_zero_ctx(f, ctx, e) __extension__({ \
358 __typeof__(e) _e = os_slowpath(e); \
359 if (_e) { \
360 if (os_constant(e)) { \
361 __OS_COMPILETIME_ASSERT__(!(e)); \
362 } \
363 \
364 char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \
365 os_crash(_fail_message); \
366 free(_fail_message); \
367 } \
368 })
369
370 #define posix_assert_zero_ctx(f, ctx, e) __extension__({ \
371 __typeof__(e) _e = os_slowpath(e); \
372 if (_e == (__typeof__(e))-1) { \
373 char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)errno); \
374 os_crash(_fail_message); \
375 free(_fail_message); \
376 } \
377 })
378
379 #pragma mark internal symbols
380
381 __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0)
382 extern void
383 _os_crash(const char *);
384
385 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
386 extern void
387 _os_assumes_log(uint64_t code);
388
389 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
390 extern char *
391 _os_assert_log(uint64_t code);
392
393 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
394 extern void
395 _os_assumes_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code);
396
397 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
398 extern char *
399 _os_assert_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code);
400
401 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
402 extern void
403 _os_avoid_tail_call(void);
404
405 __END_DECLS
406
407 #endif /* __OS_ASSUMES_H__ */