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