]> git.saurik.com Git - apple/libc.git/blame - os/assumes.h
Libc-1158.1.2.tar.gz
[apple/libc.git] / os / assumes.h
CommitLineData
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 */
69typedef bool (*os_redirect_t)(const char *);
70struct _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
85typedef void (*os_crash_callback_t) (const char *);
86
87/* private. use os_get_crash_callback and os_set_crash_callback */
88extern os_crash_callback_t _os_crash_callback;
89
90static inline os_crash_callback_t
91os_get_crash_callback() {
92 return _os_crash_callback;
93}
94
95static inline void
96os_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 */
104typedef 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)
259extern void
260_os_crash(const char *);
261
6465356a
A
262__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
263extern void
264_os_assumes_log(uint64_t code);
265
266__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
267extern char *
268_os_assert_log(uint64_t code);
269
270__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
271extern 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)
275extern 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)
279extern void
280_os_avoid_tail_call(void);
281
282__END_DECLS
283
284#endif /* __OS_ASSUMES_H__ */