2 * Copyright (c) 2011, 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <TargetConditionals.h>
25 #include <uuid/uuid.h>
26 #include <sys/types.h>
27 #include <sys/sysctl.h>
28 #include <mach-o/loader.h>
29 #include <mach-o/fat.h>
30 #include <mach-o/getsect.h>
32 #include <sys/types.h>
33 #include <sys/reason.h>
41 #include "os/assumes.h"
43 #if !TARGET_OS_DRIVERKIT
45 #include <os/debug_private.h>
47 #include <os/log_private.h>
48 #include <os/reason_private.h>
50 #define _os_debug_log_error_str(...)
51 // placeholder to disable usage of dlfcn.h
52 typedef struct dl_info
{
56 #if __has_include(<CrashReporterClient.h>)
57 #include <CrashReporterClient.h>
58 #define os_set_crash_message(arg) CRSetCrashLogMessage(arg)
60 #define os_set_crash_message(arg)
63 #define OSX_ASSUMES_LOG_REDIRECT_SECT_NAME "__osx_log_func"
64 #define os_atomic_cmpxchg(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
66 #if !TARGET_OS_DRIVERKIT
68 _os_basename(const char *p
)
70 return ((strrchr(p
, '/') ? : p
- 1) + 1);
75 _os_get_build(char *build
, size_t sz
)
77 /* Get the build every time. We used to cache it, but if PID 1 experiences
78 * an assumes() failure before the build has been set, that would mean that
79 * all future failures would get bad build info. So we fetch it every time.
80 * Since assumes() failures are on the slow path anyway, not a huge deal.
82 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
85 int r
= sysctl(mib
, 2, build
, &sz
, NULL
, 0);
86 if (r
== 0 && sz
== 1) {
87 (void)strlcpy(build
, "99Z999", oldsz
);
89 #if TARGET_IPHONE_SIMULATOR
90 char *simVersion
= getenv("SIMULATOR_RUNTIME_BUILD_VERSION");
92 strlcat(build
, " ", oldsz
);
93 strlcat(build
, simVersion
, oldsz
);
98 #if !TARGET_OS_DRIVERKIT
100 _os_get_image_uuid(void *hdr
, uuid_t uuid
)
103 struct mach_header_64
*hdr32or64
= (struct mach_header_64
*)hdr
;
105 struct mach_header
*hdr32or64
= (struct mach_header
*)hdr
;
106 #endif /* __LP64__ */
109 size_t next
= sizeof(*hdr32or64
);
110 struct load_command
*cur
= NULL
;
111 for (i
= 0; i
< hdr32or64
->ncmds
; i
++) {
112 cur
= (struct load_command
*)((uintptr_t)hdr32or64
+ next
);
113 if (cur
->cmd
== LC_UUID
) {
114 struct uuid_command
*cmd
= (struct uuid_command
*)cur
;
115 uuid_copy(uuid
, cmd
->uuid
);
119 next
+= cur
->cmdsize
;
122 if (i
== hdr32or64
->ncmds
) {
129 _os_abort_on_assumes(void)
134 if (getenv("OS_ASSUMES_FATAL")) {
138 if (getenv("OS_ASSUMES_FATAL_PID1")) {
147 typedef struct mach_header_64 os_mach_header
;
149 typedef struct mach_header os_mach_header
;
153 _os_find_log_redirect_func(os_mach_header
*hdr
)
155 os_redirect_t result
= NULL
;
157 #if !TARGET_OS_DRIVERKIT
159 unsigned long size
= 0;
160 uint8_t *data
= getsectiondata(hdr
, OS_ASSUMES_REDIRECT_SEG
, OS_ASSUMES_REDIRECT_SECT
, &size
);
162 data
= getsectiondata(hdr
, "__TEXT", OSX_ASSUMES_LOG_REDIRECT_SECT_NAME
, &size
);
164 if (data
&& size
< sizeof(name
) - 2) {
165 (void)strlcpy(name
, (const char *)data
, size
+ 1);
166 result
= dlsym(RTLD_DEFAULT
, name
);
168 } else if (size
== sizeof(struct _os_redirect_assumes_s
)) {
169 struct _os_redirect_assumes_s
*redirect
= (struct _os_redirect_assumes_s
*)data
;
170 result
= redirect
->redirect
;
178 _os_log_redirect(void *hdr
, const char *msg
)
182 os_redirect_t redirect_func
= _os_find_log_redirect_func(hdr
);
184 result
= redirect_func(msg
);
190 __attribute__((always_inline
))
192 _os_construct_message(uint64_t code
, _SIMPLE_STRING asl_message
, Dl_info
*info
, char *buff
, size_t sz
)
194 const char *image_name
= NULL
;
195 uintptr_t offset
= 0;
196 uuid_string_t uuid_str
;
198 #if !TARGET_OS_DRIVERKIT
199 void *ret
= __builtin_return_address(0);
200 if (dladdr(ret
, info
)) {
202 _os_get_image_uuid(info
->dli_fbase
, uuid
);
204 uuid_unparse(uuid
, uuid_str
);
205 image_name
= _os_basename(info
->dli_fname
);
207 offset
= ret
- info
->dli_fbase
;
210 info
->dli_fbase
= NULL
;
214 (void)snprintf(sig
, sizeof(sig
), "%s:%lu", uuid_str
, offset
);
217 (void)snprintf(result
, sizeof(result
), "0x%llx", code
);
220 size_t bsz
= sizeof(build
);
221 _os_get_build(build
, bsz
);
223 (void)snprintf(buff
, sz
, "assertion failed: %s: %s + %lu [%s]: %s", build
, image_name
, offset
, uuid_str
, result
);
225 _simple_asl_msg_set(asl_message
, "com.apple.message.domain", "com.apple.assumes.failure");
226 _simple_asl_msg_set(asl_message
, "com.apple.message.signature", sig
);
227 _simple_asl_msg_set(asl_message
, "com.apple.message.signature2", result
);
228 _simple_asl_msg_set(asl_message
, "com.apple.message.signature3", image_name
);
229 _simple_asl_msg_set(asl_message
, "com.apple.message.summarize", "YES");
232 #pragma mark Internal Implementations
234 os_crash_callback_t _os_crash_callback
= NULL
;
236 __attribute__((always_inline
))
238 _os_crash_impl(const char *message
) {
239 os_set_crash_message(message
);
240 #if !TARGET_OS_DRIVERKIT
241 if (!_os_crash_callback
) {
242 _os_crash_callback
= dlsym(RTLD_MAIN_ONLY
, "os_crash_function");
244 if (_os_crash_callback
) {
245 _os_crash_callback(message
);
250 #if !TARGET_OS_DRIVERKIT
251 __attribute__((always_inline
))
253 _os_crash_fmt_impl(os_log_pack_t pack
, size_t pack_size
)
256 * We put just the format string into the CrashReporter buffer so that we
257 * can get at least that on customer builds.
259 const char *message
= pack
->olp_format
;
260 _os_crash_impl(message
);
262 char *(*_os_log_pack_send_and_compose
)(os_log_pack_t
, os_log_t
,
263 os_log_type_t
, char *, size_t) = NULL
;
264 _os_log_pack_send_and_compose
= dlsym(RTLD_DEFAULT
, "os_log_pack_send_and_compose");
265 if (!_os_log_pack_send_and_compose
) return false;
267 os_log_t __os_log_default
= NULL
;
268 __os_log_default
= dlsym(RTLD_DEFAULT
, "_os_log_default");
269 if (!__os_log_default
) return false;
271 char *composed
= _os_log_pack_send_and_compose(pack
, __os_log_default
,
272 OS_LOG_TYPE_ERROR
, NULL
, 0);
274 abort_with_payload(OS_REASON_LIBSYSTEM
, OS_REASON_LIBSYSTEM_CODE_FAULT
, pack
, pack_size
, composed
, 0);
278 __attribute__((always_inline
))
280 _os_assumes_log_impl(uint64_t code
)
282 char message
[256] = "";
284 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
287 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
288 if (!_os_log_redirect(info
.dli_fbase
, message
)) {
289 _os_debug_log_error_str(message
);
290 _simple_asl_msg_set(asl_message
, "Level", "Error");
291 _simple_asl_msg_set(asl_message
, "Message", "");
292 _simple_asl_send(asl_message
);
295 _simple_sfree(asl_message
);
298 if (_os_abort_on_assumes()) {
303 __attribute__((always_inline
))
305 _os_assert_log_impl(uint64_t code
)
309 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
313 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
314 if (!_os_log_redirect(info
.dli_fbase
, message
)) {
315 _os_debug_log_error_str(message
);
316 _simple_asl_msg_set(asl_message
, "Level", "Error");
317 _simple_asl_msg_set(asl_message
, "Message", "");
318 _simple_asl_send(asl_message
);
321 _simple_sfree(asl_message
);
322 result
= strdup(message
);
328 __attribute__((always_inline
))
330 _os_assumes_log_ctx_impl(os_log_callout_t callout
, void *ctx
, uint64_t code
)
332 char message
[256] = "";
334 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
337 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
339 (void)callout(asl_message
, ctx
, message
);
340 _simple_sfree(asl_message
);
343 if (_os_abort_on_assumes()) {
348 __attribute__((always_inline
))
350 _os_assert_log_ctx_impl(os_log_callout_t callout
, void *ctx
, uint64_t code
)
354 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
358 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
360 (void)callout(asl_message
, ctx
, message
);
361 _simple_sfree(asl_message
);
362 result
= strdup(message
);
367 #pragma mark Public Interfaces
368 void _os_crash(const char *message
)
370 _os_crash_impl(message
);
373 #if !TARGET_OS_DRIVERKIT
374 void _os_crash_fmt(os_log_pack_t pack
, size_t pack_size
)
376 _os_crash_fmt_impl(pack
, pack_size
);
381 _os_assumes_log(uint64_t code
)
383 _os_assumes_log_impl(code
);
387 _os_assert_log(uint64_t code
)
389 return _os_assert_log_impl(code
);
393 _os_assumes_log_ctx(os_log_callout_t callout
, void *ctx
, uint64_t code
)
395 _os_assumes_log_ctx_impl(callout
, ctx
, code
);
399 _os_assert_log_ctx(os_log_callout_t callout
, void *ctx
, uint64_t code
)
401 return _os_assert_log_ctx_impl(callout
, ctx
, code
);
405 _os_avoid_tail_call(void)