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 */
59typedef bool (*os_redirect_t)(const char *);
60struct _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 */
78typedef 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)
239extern void
240_os_assumes_log(uint64_t code);
241
242__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
243extern char *
244_os_assert_log(uint64_t code);
245
246__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_6_0)
247extern 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)
251extern 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)
255extern void
256_os_avoid_tail_call(void);
257
258__END_DECLS
259
260#endif /* __OS_ASSUMES_H__ */
261