]>
Commit | Line | Data |
---|---|---|
6465356a A |
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> | |
6465356a | 37 | #include <errno.h> |
23e20b00 A |
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__ */ | |
6465356a | 52 | |
5f125488 A |
53 | |
54 | /* os_crash() is like os_hardware_trap(), except you get to pass in a crash | |
55 | * message, and it can be redirected to a callback function using | |
56 | * os_set_crash_callback() */ | |
57 | #define os_crash(msg) \ | |
58 | ({ \ | |
59 | _os_crash(msg); \ | |
60 | os_hardware_trap(); \ | |
61 | }) | |
62 | ||
6465356a A |
63 | /* This is useful for clients who wish for the messages generated by assumes() |
64 | * failures to go somewhere other than (or in addition to) the system log. If | |
65 | * you don't wish for the message to be logged to the system log, then return | |
66 | * true (to indicate that the message has been handled). If you want the default | |
67 | * behavior, return false. | |
68 | */ | |
69 | typedef bool (*os_redirect_t)(const char *); | |
70 | struct _os_redirect_assumes_s { | |
71 | os_redirect_t redirect; | |
72 | }; | |
73 | ||
74 | #define OS_ASSUMES_REDIRECT_SEG "__DATA" | |
75 | #define OS_ASSUMES_REDIRECT_SECT "__os_assumes_log" | |
76 | ||
77 | #define os_redirect_assumes(func) \ | |
78 | __attribute__((__used__)) \ | |
79 | __attribute__((__section__(OS_ASSUMES_REDIRECT_SEG "," OS_ASSUMES_REDIRECT_SECT))) \ | |
80 | static struct _os_redirect_assumes_s _os_redirect_##func = { \ | |
81 | .redirect = &func, \ | |
82 | }; | |
83 | ||
5f125488 A |
84 | |
85 | typedef void (*os_crash_callback_t) (const char *); | |
86 | ||
87 | /* private. use os_get_crash_callback and os_set_crash_callback */ | |
88 | extern os_crash_callback_t _os_crash_callback; | |
89 | ||
90 | static inline os_crash_callback_t | |
91 | os_get_crash_callback() { | |
92 | return _os_crash_callback; | |
93 | } | |
94 | ||
95 | static inline void | |
96 | os_set_crash_callback(os_crash_callback_t callback) { | |
97 | _os_crash_callback = callback; | |
98 | } | |
99 | ||
6465356a A |
100 | /* The asl_message argument is a _SIMPLE_STRING that, when given to _simple_asl_send(), will |
101 | * direct the message to the MessageTracer diagnostic messages store rather than | |
102 | * the default system log store. | |
103 | */ | |
104 | typedef bool (*os_log_callout_t)(_SIMPLE_STRING asl_message, void *ctx, const char *); | |
105 | ||
6465356a | 106 | #include <CrashReporterClient.h> |
23e20b00 | 107 | #define os_set_crash_message(arg) CRSetCrashLogMessage(arg) |
6465356a A |
108 | |
109 | #define os_assumes(e) __extension__({ \ | |
110 | __typeof__(e) _e = os_fastpath(e); \ | |
111 | if (!_e) { \ | |
112 | if (os_constant(e)) { \ | |
113 | __OS_COMPILETIME_ASSERT__(e); \ | |
114 | } \ | |
115 | _os_assumes_log((uint64_t)(uintptr_t)_e); \ | |
116 | _os_avoid_tail_call(); \ | |
117 | } \ | |
118 | _e; \ | |
119 | }) | |
120 | ||
121 | #define os_assumes_zero(e) __extension__({ \ | |
122 | __typeof__(e) _e = os_slowpath(e); \ | |
123 | if (_e) { \ | |
124 | if (os_constant(e)) { \ | |
974e3884 | 125 | __OS_COMPILETIME_ASSERT__(!(e)); \ |
6465356a A |
126 | } \ |
127 | _os_assumes_log((uint64_t)(uintptr_t)_e); \ | |
128 | _os_avoid_tail_call(); \ | |
129 | } \ | |
130 | _e; \ | |
131 | }) | |
132 | ||
133 | /* This variant is for use with old-style POSIX APIs that return -1 on failure | |
134 | * and set errno. If the return code is -1, the value logged will be as though | |
135 | * os_assumes_zero(errno) was used. It encapsulates the following pattern: | |
136 | * | |
137 | * int tubes[2]; | |
138 | * if (pipe(tubes) == -1) { | |
139 | * (void)os_assumes_zero(errno); | |
140 | * } | |
141 | */ | |
142 | #define posix_assumes_zero(e) __extension__({ \ | |
143 | __typeof__(e) _e = os_slowpath(e); \ | |
144 | if (_e == (typeof(e))-1) { \ | |
145 | _os_assumes_log((uint64_t)(uintptr_t)errno); \ | |
146 | _os_avoid_tail_call(); \ | |
147 | } \ | |
148 | _e; \ | |
149 | }) | |
150 | ||
151 | #define os_assert(e) __extension__({ \ | |
152 | __typeof__(e) _e = os_fastpath(e); \ | |
153 | if (!_e) { \ | |
154 | if (os_constant(e)) { \ | |
155 | __OS_COMPILETIME_ASSERT__(e); \ | |
156 | } \ | |
157 | \ | |
158 | char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \ | |
5f125488 | 159 | os_crash(_fail_message); \ |
6465356a A |
160 | free(_fail_message); \ |
161 | } \ | |
162 | }) | |
163 | ||
164 | #define os_assert_zero(e) __extension__({ \ | |
165 | __typeof__(e) _e = os_slowpath(e); \ | |
166 | if (_e) { \ | |
167 | if (os_constant(e)) { \ | |
974e3884 | 168 | __OS_COMPILETIME_ASSERT__(!(e)); \ |
6465356a A |
169 | } \ |
170 | \ | |
171 | char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \ | |
5f125488 | 172 | os_crash(_fail_message); \ |
6465356a A |
173 | free(_fail_message); \ |
174 | } \ | |
175 | }) | |
176 | ||
177 | #define posix_assert_zero(e) __extension__({ \ | |
178 | __typeof__(e) _e = os_slowpath(e); \ | |
179 | if (_e == (__typeof__(e))-1) { \ | |
180 | char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)errno); \ | |
5f125488 | 181 | os_crash(_fail_message); \ |
6465356a A |
182 | free(_fail_message); \ |
183 | } \ | |
184 | }) | |
185 | ||
186 | /* These are for defining your own assumes()-like wrapper calls so that you can | |
187 | * log additional information, such as the about-PID, sender, etc. They're | |
188 | * generally not useful for direct inclusion in your code. | |
189 | */ | |
190 | #define os_assumes_ctx(f, ctx, e) __extension__({ \ | |
191 | __typeof__(e) _e = os_fastpath(e); \ | |
192 | if (!_e) { \ | |
193 | if (os_constant(e)) { \ | |
194 | __OS_COMPILETIME_ASSERT__(e); \ | |
195 | } \ | |
196 | _os_assumes_log_ctx(f, ctx, (uintptr_t)_e); \ | |
197 | _os_avoid_tail_call(); \ | |
198 | } \ | |
199 | _e; \ | |
200 | }) | |
201 | ||
202 | #define os_assumes_zero_ctx(f, ctx, e) __extension__({ \ | |
203 | __typeof__(e) _e = os_slowpath(e); \ | |
204 | if (_e) { \ | |
205 | if (os_constant(e)) { \ | |
974e3884 | 206 | __OS_COMPILETIME_ASSERT__(!(e)); \ |
6465356a A |
207 | } \ |
208 | _os_assumes_log_ctx((f), (ctx), (uintptr_t)_e); \ | |
209 | _os_avoid_tail_call(); \ | |
210 | } \ | |
211 | _e; \ | |
212 | }) | |
213 | ||
214 | #define posix_assumes_zero_ctx(f, ctx, e) __extension__({ \ | |
215 | __typeof__(e) _e = os_slowpath(e); \ | |
216 | if (_e == (__typeof__(e))-1) { \ | |
217 | _os_assumes_log_ctx((f), (ctx), (uintptr_t)errno); \ | |
218 | _os_avoid_tail_call(); \ | |
219 | } \ | |
220 | _e; \ | |
221 | }) | |
222 | ||
223 | #define os_assert_ctx(f, ctx, e) __extension__({ \ | |
224 | __typeof__(e) _e = os_fastpath(e); \ | |
225 | if (!_e) { \ | |
226 | if (os_constant(e)) { \ | |
227 | __OS_COMPILETIME_ASSERT__(e); \ | |
228 | } \ | |
5f125488 | 229 | \ |
6465356a | 230 | char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \ |
5f125488 | 231 | os_crash(_fail_message); \ |
6465356a A |
232 | free(_fail_message); \ |
233 | } \ | |
234 | }) | |
235 | ||
236 | #define os_assert_zero_ctx(f, ctx, e) __extension__({ \ | |
237 | __typeof__(e) _e = os_slowpath(e); \ | |
238 | if (_e) { \ | |
239 | if (os_constant(e)) { \ | |
974e3884 | 240 | __OS_COMPILETIME_ASSERT__(!(e)); \ |
6465356a A |
241 | } \ |
242 | \ | |
243 | char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \ | |
5f125488 | 244 | os_crash(_fail_message); \ |
6465356a A |
245 | free(_fail_message); \ |
246 | } \ | |
247 | }) | |
248 | ||
249 | #define posix_assert_zero_ctx(f, ctx, e) __extension__({ \ | |
250 | __typeof__(e) _e = os_slowpath(e); \ | |
251 | if (_e == (__typeof__(e))-1) { \ | |
252 | char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)errno); \ | |
5f125488 | 253 | os_crash(_fail_message); \ |
6465356a A |
254 | free(_fail_message); \ |
255 | } \ | |
256 | }) | |
257 | ||
5f125488 A |
258 | __OSX_AVAILABLE_STARTING(__MAC_10_11, __IPHONE_9_0) |
259 | extern void | |
260 | _os_crash(const char *); | |
261 | ||
6465356a A |
262 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) |
263 | extern void | |
264 | _os_assumes_log(uint64_t code); | |
265 | ||
266 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
267 | extern char * | |
268 | _os_assert_log(uint64_t code); | |
269 | ||
270 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
271 | extern void | |
272 | _os_assumes_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code); | |
273 | ||
274 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
275 | extern char * | |
276 | _os_assert_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code); | |
277 | ||
278 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0) | |
279 | extern void | |
280 | _os_avoid_tail_call(void); | |
281 | ||
282 | __END_DECLS | |
283 | ||
284 | #endif /* __OS_ASSUMES_H__ */ |