]> git.saurik.com Git - apple/libc.git/blob - os/assumes.h
38083958ba1f48da91e56301c8a1ee291fd7abbc
[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
28 __BEGIN_DECLS
29
30 #include <Availability.h>
31 #include <TargetConditionals.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <stdarg.h>
35 #include <stdbool.h>
36 #include <_simple.h>
37 #include <errno.h>
38 #include <os/base_private.h>
39
40 #if __GNUC__
41 #define os_constant(x) __builtin_constant_p((x))
42 #define os_hardware_trap() __asm__ __volatile__ (""); __builtin_trap()
43 #define __OS_COMPILETIME_ASSERT__(e) __extension__({ \
44 char __compile_time_assert__[(e) ? 1 : -1]; \
45 (void)__compile_time_assert__; \
46 })
47 #else /* __GNUC__ */
48 #define os_constant(x) ((long)0)
49 #define os_hardware_trap() abort()
50 #define __OS_COMPILETIME_ASSERT__(e) (e)
51 #endif /* __GNUC__ */
52
53 /* This is useful for clients who wish for the messages generated by assumes()
54 * failures to go somewhere other than (or in addition to) the system log. If
55 * you don't wish for the message to be logged to the system log, then return
56 * true (to indicate that the message has been handled). If you want the default
57 * behavior, return false.
58 */
59 typedef bool (*os_redirect_t)(const char *);
60 struct _os_redirect_assumes_s {
61 os_redirect_t redirect;
62 };
63
64 #define OS_ASSUMES_REDIRECT_SEG "__DATA"
65 #define OS_ASSUMES_REDIRECT_SECT "__os_assumes_log"
66
67 #define os_redirect_assumes(func) \
68 __attribute__((__used__)) \
69 __attribute__((__section__(OS_ASSUMES_REDIRECT_SEG "," OS_ASSUMES_REDIRECT_SECT))) \
70 static struct _os_redirect_assumes_s _os_redirect_##func = { \
71 .redirect = &func, \
72 };
73
74 /* The asl_message argument is a _SIMPLE_STRING that, when given to _simple_asl_send(), will
75 * direct the message to the MessageTracer diagnostic messages store rather than
76 * the default system log store.
77 */
78 typedef bool (*os_log_callout_t)(_SIMPLE_STRING asl_message, void *ctx, const char *);
79
80 #include <CrashReporterClient.h>
81 #define os_set_crash_message(arg) CRSetCrashLogMessage(arg)
82
83 #define os_assumes(e) __extension__({ \
84 __typeof__(e) _e = os_fastpath(e); \
85 if (!_e) { \
86 if (os_constant(e)) { \
87 __OS_COMPILETIME_ASSERT__(e); \
88 } \
89 _os_assumes_log((uint64_t)(uintptr_t)_e); \
90 _os_avoid_tail_call(); \
91 } \
92 _e; \
93 })
94
95 #define os_assumes_zero(e) __extension__({ \
96 __typeof__(e) _e = os_slowpath(e); \
97 if (_e) { \
98 if (os_constant(e)) { \
99 __OS_COMPILETIME_ASSERT__(!e); \
100 } \
101 _os_assumes_log((uint64_t)(uintptr_t)_e); \
102 _os_avoid_tail_call(); \
103 } \
104 _e; \
105 })
106
107 /* This variant is for use with old-style POSIX APIs that return -1 on failure
108 * and set errno. If the return code is -1, the value logged will be as though
109 * os_assumes_zero(errno) was used. It encapsulates the following pattern:
110 *
111 * int tubes[2];
112 * if (pipe(tubes) == -1) {
113 * (void)os_assumes_zero(errno);
114 * }
115 */
116 #define posix_assumes_zero(e) __extension__({ \
117 __typeof__(e) _e = os_slowpath(e); \
118 if (_e == (typeof(e))-1) { \
119 _os_assumes_log((uint64_t)(uintptr_t)errno); \
120 _os_avoid_tail_call(); \
121 } \
122 _e; \
123 })
124
125 #define os_assert(e) __extension__({ \
126 __typeof__(e) _e = os_fastpath(e); \
127 if (!_e) { \
128 if (os_constant(e)) { \
129 __OS_COMPILETIME_ASSERT__(e); \
130 } \
131 \
132 char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \
133 os_set_crash_message(_fail_message); \
134 os_hardware_trap(); \
135 free(_fail_message); \
136 } \
137 })
138
139 #define os_assert_zero(e) __extension__({ \
140 __typeof__(e) _e = os_slowpath(e); \
141 if (_e) { \
142 if (os_constant(e)) { \
143 __OS_COMPILETIME_ASSERT__(!e); \
144 } \
145 \
146 char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \
147 os_set_crash_message(_fail_message); \
148 os_hardware_trap(); \
149 free(_fail_message); \
150 } \
151 })
152
153 #define posix_assert_zero(e) __extension__({ \
154 __typeof__(e) _e = os_slowpath(e); \
155 if (_e == (__typeof__(e))-1) { \
156 char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)errno); \
157 os_set_crash_message(_fail_message); \
158 os_hardware_trap(); \
159 free(_fail_message); \
160 } \
161 })
162
163 /* These are for defining your own assumes()-like wrapper calls so that you can
164 * log additional information, such as the about-PID, sender, etc. They're
165 * generally not useful for direct inclusion in your code.
166 */
167 #define os_assumes_ctx(f, ctx, e) __extension__({ \
168 __typeof__(e) _e = os_fastpath(e); \
169 if (!_e) { \
170 if (os_constant(e)) { \
171 __OS_COMPILETIME_ASSERT__(e); \
172 } \
173 _os_assumes_log_ctx(f, ctx, (uintptr_t)_e); \
174 _os_avoid_tail_call(); \
175 } \
176 _e; \
177 })
178
179 #define os_assumes_zero_ctx(f, ctx, e) __extension__({ \
180 __typeof__(e) _e = os_slowpath(e); \
181 if (_e) { \
182 if (os_constant(e)) { \
183 __OS_COMPILETIME_ASSERT__(!e); \
184 } \
185 _os_assumes_log_ctx((f), (ctx), (uintptr_t)_e); \
186 _os_avoid_tail_call(); \
187 } \
188 _e; \
189 })
190
191 #define posix_assumes_zero_ctx(f, ctx, e) __extension__({ \
192 __typeof__(e) _e = os_slowpath(e); \
193 if (_e == (__typeof__(e))-1) { \
194 _os_assumes_log_ctx((f), (ctx), (uintptr_t)errno); \
195 _os_avoid_tail_call(); \
196 } \
197 _e; \
198 })
199
200 #define os_assert_ctx(f, ctx, e) __extension__({ \
201 __typeof__(e) _e = os_fastpath(e); \
202 if (!_e) { \
203 if (os_constant(e)) { \
204 __OS_COMPILETIME_ASSERT__(e); \
205 } \
206 \
207 char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \
208 os_set_crash_message(_fail_message); \
209 os_hardware_trap(); \
210 free(_fail_message); \
211 } \
212 })
213
214 #define os_assert_zero_ctx(f, ctx, e) __extension__({ \
215 __typeof__(e) _e = os_slowpath(e); \
216 if (_e) { \
217 if (os_constant(e)) { \
218 __OS_COMPILETIME_ASSERT__(!e); \
219 } \
220 \
221 char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \
222 os_set_crash_message(_fail_message); \
223 os_hardware_trap(); \
224 free(_fail_message); \
225 } \
226 })
227
228 #define posix_assert_zero_ctx(f, ctx, e) __extension__({ \
229 __typeof__(e) _e = os_slowpath(e); \
230 if (_e == (__typeof__(e))-1) { \
231 char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)errno); \
232 os_set_crash_message(_fail_message); \
233 os_hardware_trap(); \
234 free(_fail_message); \
235 } \
236 })
237
238 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
239 extern void
240 _os_assumes_log(uint64_t code);
241
242 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
243 extern char *
244 _os_assert_log(uint64_t code);
245
246 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
247 extern void
248 _os_assumes_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code);
249
250 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
251 extern char *
252 _os_assert_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code);
253
254 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
255 extern void
256 _os_avoid_tail_call(void);
257
258 __END_DECLS
259
260 #endif /* __OS_ASSUMES_H__ */