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