xref: /trueos/include/os/assumes.h (revision 0f8eb4123024ffec2f2cfcdb493793aea43f0cac)
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 <sys/proc_info.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 
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 
81 #include <CrashReporterClient.h>
82 #define os_set_crash_message(arg) CRSetCrashLogMessage(arg)
83 
84 #define os_assumes(e) __extension__({ \
85 	__typeof__(e) _e = os_fastpath(e); \
86 	if (!_e) { \
87 		if (os_constant(e)) { \
88 			__OS_COMPILETIME_ASSERT__(e); \
89 		} \
90 		_os_assumes_log((uint64_t)(uintptr_t)_e); \
91 		_os_avoid_tail_call(); \
92 	} \
93 	_e; \
94 })
95 
96 #define os_assumes_zero(e) __extension__({ \
97 	__typeof__(e) _e = os_slowpath(e); \
98 	if (_e) { \
99 		if (os_constant(e)) { \
100 			__OS_COMPILETIME_ASSERT__(!e); \
101 		} \
102 		_os_assumes_log((uint64_t)(uintptr_t)_e); \
103 		_os_avoid_tail_call(); \
104 	} \
105 	_e; \
106 })
107 
108 /* This variant is for use with old-style POSIX APIs that return -1 on failure
109  * and set errno. If the return code is -1, the value logged will be as though
110  * os_assumes_zero(errno) was used. It encapsulates the following pattern:
111  *
112  * int tubes[2];
113  * if (pipe(tubes) == -1) {
114  *     (void)os_assumes_zero(errno);
115  * }
116  */
117 #define posix_assumes_zero(e) __extension__({ \
118 	__typeof__(e) _e = os_slowpath(e); \
119 	if (_e == (typeof(e))-1) { \
120 		_os_assumes_log((uint64_t)(uintptr_t)errno); \
121 		_os_avoid_tail_call(); \
122 	} \
123 	_e; \
124 })
125 
126 #define os_assert(e) __extension__({ \
127 	__typeof__(e) _e = os_fastpath(e); \
128 	if (!_e) { \
129 		if (os_constant(e)) { \
130 			__OS_COMPILETIME_ASSERT__(e); \
131 		} \
132 \
133 		char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \
134 		os_set_crash_message(_fail_message); \
135 		os_hardware_trap(); \
136 		free(_fail_message); \
137 	} \
138 })
139 
140 #define os_assert_zero(e) __extension__({ \
141 	__typeof__(e) _e = os_slowpath(e); \
142 	if (_e) { \
143 		if (os_constant(e)) { \
144 			__OS_COMPILETIME_ASSERT__(!e); \
145 		} \
146 \
147 		char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)_e); \
148 		os_set_crash_message(_fail_message); \
149 		os_hardware_trap(); \
150 		free(_fail_message); \
151 	} \
152 })
153 
154 #define posix_assert_zero(e) __extension__({ \
155 	__typeof__(e) _e = os_slowpath(e); \
156 	if (_e == (__typeof__(e))-1) { \
157 		char *_fail_message = _os_assert_log((uint64_t)(uintptr_t)errno); \
158 		os_set_crash_message(_fail_message); \
159 		os_hardware_trap(); \
160 		free(_fail_message); \
161 	} \
162 })
163 
164 /* These are for defining your own assumes()-like wrapper calls so that you can
165  * log additional information, such as the about-PID, sender, etc. They're
166  * generally not useful for direct inclusion in your code.
167  */
168 #define os_assumes_ctx(f, ctx, e) __extension__({ \
169 	__typeof__(e) _e = os_fastpath(e); \
170 	if (!_e) { \
171 		if (os_constant(e)) { \
172 			__OS_COMPILETIME_ASSERT__(e); \
173 		} \
174 		_os_assumes_log_ctx(f, ctx, (uintptr_t)_e); \
175 		_os_avoid_tail_call(); \
176 	} \
177 	_e; \
178 })
179 
180 #define os_assumes_zero_ctx(f, ctx, e) __extension__({ \
181 	__typeof__(e) _e = os_slowpath(e); \
182 	if (_e) { \
183 		if (os_constant(e)) { \
184 			__OS_COMPILETIME_ASSERT__(!e); \
185 		} \
186 		_os_assumes_log_ctx((f), (ctx), (uintptr_t)_e); \
187 		_os_avoid_tail_call(); \
188 	} \
189 	_e; \
190 })
191 
192 #define posix_assumes_zero_ctx(f, ctx, e) __extension__({ \
193 	__typeof__(e) _e = os_slowpath(e); \
194 	if (_e == (__typeof__(e))-1) { \
195 		_os_assumes_log_ctx((f), (ctx), (uintptr_t)errno); \
196 		_os_avoid_tail_call(); \
197 	} \
198 	_e; \
199 })
200 
201 #define os_assert_ctx(f, ctx, e) __extension__({ \
202 	__typeof__(e) _e = os_fastpath(e); \
203 	if (!_e) { \
204 		if (os_constant(e)) { \
205 			__OS_COMPILETIME_ASSERT__(e); \
206 		} \
207 \
208 		char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \
209 		os_set_crash_message(_fail_message); \
210 		os_hardware_trap(); \
211 		free(_fail_message); \
212 	} \
213 })
214 
215 #define os_assert_zero_ctx(f, ctx, e) __extension__({ \
216 	__typeof__(e) _e = os_slowpath(e); \
217 	if (_e) { \
218 		if (os_constant(e)) { \
219 			__OS_COMPILETIME_ASSERT__(!e); \
220 		} \
221 \
222 		char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)_e); \
223 		os_set_crash_message(_fail_message); \
224 		os_hardware_trap(); \
225 		free(_fail_message); \
226 	} \
227 })
228 
229 #define posix_assert_zero_ctx(f, ctx, e) __extension__({ \
230 	__typeof__(e) _e = os_slowpath(e); \
231 	if (_e == (__typeof__(e))-1) { \
232 		char *_fail_message = _os_assert_log_ctx((f), (ctx), (uint64_t)(uintptr_t)errno); \
233 		os_set_crash_message(_fail_message); \
234 		os_hardware_trap(); \
235 		free(_fail_message); \
236 	} \
237 })
238 
239 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
240 extern void
241 _os_assumes_log(uint64_t code);
242 
243 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
244 extern char *
245 _os_assert_log(uint64_t code);
246 
247 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
248 extern void
249 _os_assumes_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code);
250 
251 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
252 extern char *
253 _os_assert_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code);
254 
255 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
256 extern void
257 _os_avoid_tail_call(void);
258 
259 __END_DECLS
260 
261 #endif /* __OS_ASSUMES_H__ */
262