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