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 <dispatch/dispatch.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/arch.h>
31 #include <mach-o/getsect.h>
33 #include <sys/types.h>
41 #include "os/assumes.h"
42 #include "gen/assumes.h"
45 #define OSX_ASSUMES_LOG_REDIRECT_SECT_NAME "__osx_log_func"
46 #define os_atomic_cmpxchg(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
48 static bool _os_should_abort_on_assumes
= false;
51 _os_basename(const char *p
)
53 return ((strrchr(p
, '/') ? : p
- 1) + 1);
57 _os_get_build(char *build
, size_t sz
)
59 /* Get the build every time. We used to cache it, but if PID 1 experiences
60 * an assumes() failure before the build has been set, that would mean that
61 * all future failures would get bad build info. So we fetch it every time.
62 * Since assumes() failures are on the slow path anyway, not a huge deal.
64 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
67 int r
= sysctl(mib
, 2, build
, &sz
, NULL
, 0);
68 if (r
== 0 && sz
== 1) {
69 (void)strlcpy(build
, "99Z999", oldsz
);
74 _os_get_image_uuid(void *hdr
, uuid_t uuid
)
77 struct mach_header_64
*hdr32or64
= (struct mach_header_64
*)hdr
;
79 struct mach_header
*hdr32or64
= (struct mach_header
*)hdr
;
83 size_t next
= sizeof(*hdr32or64
);
84 struct load_command
*cur
= NULL
;
85 for (i
= 0; i
< hdr32or64
->ncmds
; i
++) {
86 cur
= (struct load_command
*)((uintptr_t)hdr32or64
+ next
);
87 if (cur
->cmd
== LC_UUID
) {
88 struct uuid_command
*cmd
= (struct uuid_command
*)cur
;
89 uuid_copy(uuid
, cmd
->uuid
);
96 if (i
== hdr32or64
->ncmds
) {
102 _os_abort_on_assumes_once(void)
104 /* Embedded boot-args can get pretty long. Let's just hope this is big
108 size_t len
= sizeof(bootargs
) - 1;
110 if (sysctlbyname("kern.bootargs", bootargs
, &len
, NULL
, 0) == 0) {
111 if (strnstr(bootargs
, "-os_assumes_fatal", len
)) {
112 _os_should_abort_on_assumes
= true;
118 _os_abort_on_assumes(void)
120 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
124 if (getenv("OS_ASSUMES_FATAL")) {
127 pthread_once(&once
, _os_abort_on_assumes_once
);
128 result
= _os_should_abort_on_assumes
;
131 if (getenv("OS_ASSUMES_FATAL_PID1")) {
140 typedef struct mach_header_64 os_mach_header
;
142 typedef struct mach_header os_mach_header
;
146 _os_find_log_redirect_func(os_mach_header
*hdr
)
148 os_redirect_t result
= NULL
;
151 unsigned long size
= 0;
152 uint8_t *data
= getsectiondata(hdr
, OS_ASSUMES_REDIRECT_SEG
, OS_ASSUMES_REDIRECT_SECT
, &size
);
154 data
= getsectiondata(hdr
, "__TEXT", OSX_ASSUMES_LOG_REDIRECT_SECT_NAME
, &size
);
156 if (data
&& size
< sizeof(name
) - 2) {
157 (void)strlcpy(name
, (const char *)data
, size
+ 1);
158 result
= dlsym(RTLD_DEFAULT
, name
);
160 } else if (size
== sizeof(struct _os_redirect_assumes_s
)) {
161 struct _os_redirect_assumes_s
*redirect
= (struct _os_redirect_assumes_s
*)data
;
162 result
= redirect
->redirect
;
169 _os_log_redirect(void *hdr
, const char *msg
)
173 os_redirect_t redirect_func
= _os_find_log_redirect_func(hdr
);
175 result
= redirect_func(msg
);
181 __attribute__((always_inline
))
183 _os_construct_message(uint64_t code
, _SIMPLE_STRING asl_message
, Dl_info
*info
, char *buff
, size_t sz
)
185 const char *image_name
= NULL
;
186 uintptr_t offset
= 0;
187 uuid_string_t uuid_str
;
189 void *ret
= __builtin_return_address(0);
190 if (dladdr(ret
, info
)) {
192 _os_get_image_uuid(info
->dli_fbase
, uuid
);
194 uuid_unparse(uuid
, uuid_str
);
195 image_name
= _os_basename(info
->dli_fname
);
197 offset
= ret
- info
->dli_fbase
;
201 (void)snprintf(sig
, sizeof(sig
), "%s:%lu", uuid_str
, offset
);
204 (void)snprintf(result
, sizeof(result
), "0x%llx", code
);
207 size_t bsz
= sizeof(build
);
208 _os_get_build(build
, bsz
);
210 (void)snprintf(buff
, sz
, "assertion failed: %s: %s + %lu [%s]: %s", build
, image_name
, offset
, uuid_str
, result
);
212 _simple_asl_msg_set(asl_message
, "com.apple.message.domain", "com.apple.assumes.failure");
213 _simple_asl_msg_set(asl_message
, "com.apple.message.signature", sig
);
214 _simple_asl_msg_set(asl_message
, "com.apple.message.signature2", result
);
215 _simple_asl_msg_set(asl_message
, "com.apple.message.signature3", image_name
);
216 _simple_asl_msg_set(asl_message
, "com.apple.message.summarize", "YES");
219 #pragma mark Internal Implementations
220 __attribute__((always_inline
))
222 _os_assumes_log_impl(uint64_t code
)
224 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
228 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
229 if (!_os_log_redirect(info
.dli_fbase
, message
)) {
230 _os_trace_error_str(message
);
231 _simple_asl_msg_set(asl_message
, "Level", "Error");
232 _simple_asl_msg_set(asl_message
, "Message", "");
233 _simple_asl_send(asl_message
);
236 _simple_sfree(asl_message
);
239 if (_os_abort_on_assumes()) {
244 __attribute__((always_inline
))
246 _os_assert_log_impl(uint64_t code
)
250 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
254 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
255 if (!_os_log_redirect(info
.dli_fbase
, message
)) {
256 _os_trace_error_str(message
);
257 _simple_asl_msg_set(asl_message
, "Level", "Error");
258 _simple_asl_msg_set(asl_message
, "Message", "");
259 _simple_asl_send(asl_message
);
262 _simple_sfree(asl_message
);
263 result
= strdup(message
);
266 #if LIBC_NO_LIBCRASHREPORTERCLIENT
267 /* There is no crash report information facility on embedded, which is
268 * really regrettable. Fortunately, all we need to capture is the value
269 * which tripped up the assertion. We can just stuff that into the thread's
273 (void)pthread_getname_np(pthread_self(), name
, sizeof(name
));
276 if (strlen(name
) == 0) {
277 (void)snprintf(newname
, sizeof(newname
), "[Fatal bug: 0x%llx]", code
);
279 (void)snprintf(newname
, sizeof(newname
), "%s [Fatal bug: 0x%llx]", name
, code
);
282 (void)pthread_setname_np(newname
);
288 __attribute__((always_inline
))
290 _os_assumes_log_ctx_impl(os_log_callout_t callout
, void *ctx
, uint64_t code
)
292 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
296 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
298 (void)callout(asl_message
, ctx
, message
);
299 _simple_sfree(asl_message
);
302 if (_os_abort_on_assumes()) {
307 __attribute__((always_inline
))
309 _os_assert_log_ctx_impl(os_log_callout_t callout
, void *ctx
, uint64_t code
)
313 _SIMPLE_STRING asl_message
= _simple_asl_msg_new();
317 _os_construct_message(code
, asl_message
, &info
, message
, sizeof(message
));
319 (void)callout(asl_message
, ctx
, message
);
320 _simple_sfree(asl_message
);
321 result
= strdup(message
);
326 #pragma mark Public Interfaces
328 _os_assumes_log(uint64_t code
)
330 _os_assumes_log_impl(code
);
334 _os_assert_log(uint64_t code
)
336 return _os_assert_log_impl(code
);
340 _os_assumes_log_ctx(os_log_callout_t callout
, void *ctx
, uint64_t code
)
342 _os_assumes_log_ctx_impl(callout
, ctx
, code
);
346 _os_assert_log_ctx(os_log_callout_t callout
, void *ctx
, uint64_t code
)
348 return _os_assert_log_ctx_impl(callout
, ctx
, code
);
352 _os_avoid_tail_call(void)
359 _osx_assumes_log(uint64_t code
)
361 _os_assumes_log(code
);
365 _osx_assert_log(uint64_t code
)
367 return _os_assert_log_impl(code
);
371 _osx_assumes_log_ctx(osx_log_callout_t callout
, void *ctx
, uint64_t code
)
373 _os_assumes_log_ctx_impl(callout
, ctx
, code
);
377 _osx_assert_log_ctx(osx_log_callout_t callout
, void *ctx
, uint64_t code
)
379 return _os_assert_log_ctx_impl(callout
, ctx
, code
);
383 _osx_avoid_tail_call(void)
385 _os_avoid_tail_call();