1 #include <dispatch/dispatch.h>
4 #include <sys/sysctl.h>
5 #include <mach-o/loader.h>
6 #include <mach-o/fat.h>
7 #include <mach-o/arch.h>
8 #include <mach-o/getsect.h>
10 #include <sys/types.h>
19 #define OSX_ASSUME_LOG_REDIRECT_SECT_NAME "__osx_log_func"
20 #define osx_atomic_cmpxchg(p, o, n) __sync_bool_compare_and_swap((p), (o), (n))
22 static bool _osx_should_abort_on_assumes
= false;
25 _osx_basename(const char *p
)
27 return ((strrchr(p
, '/') ? : p
- 1) + 1);
31 _osx_get_build(char *build
, size_t sz
)
33 /* Get the build every time. We used to cache it, but if PID 1 experiences
34 * an assumes() failure before the build has been set, that would mean that
35 * all future failures would get bad build info. So we fetch it every time.
36 * Since assumes() failures are on the slow path anyway, not a huge deal.
38 int mib
[] = { CTL_KERN
, KERN_OSVERSION
};
41 int r
= sysctl(mib
, 2, build
, &sz
, NULL
, 0);
42 if (r
== 0 && sz
== 1) {
43 (void)strlcpy(build
, "99Z999", oldsz
);
48 _osx_get_image_uuid(void *hdr
, uuid_t uuid
)
51 struct mach_header_64
*hdr32or64
= (struct mach_header_64
*)hdr
;
53 struct mach_header
*hdr32or64
= (struct mach_header
*)hdr
;
57 size_t next
= sizeof(*hdr32or64
);
58 struct load_command
*cur
= NULL
;
59 for (i
= 0; i
< hdr32or64
->ncmds
; i
++) {
60 cur
= (struct load_command
*)((uintptr_t)hdr32or64
+ next
);
61 if (cur
->cmd
== LC_UUID
) {
62 struct uuid_command
*cmd
= (struct uuid_command
*)cur
;
63 uuid_copy(uuid
, cmd
->uuid
);
70 if (i
== hdr32or64
->ncmds
) {
76 _osx_abort_on_assumes_once(void)
78 /* Embedded boot-args can get pretty long. Let's just hope this is big
82 size_t len
= sizeof(bootargs
) - 1;
84 if (sysctlbyname("kern.bootargs", bootargs
, &len
, NULL
, 0) == 0) {
85 if (strnstr(bootargs
, "-osx_assumes_fatal", len
)) {
86 _osx_should_abort_on_assumes
= true;
92 _osx_abort_on_assumes(void)
94 static pthread_once_t once
= PTHREAD_ONCE_INIT
;
98 if (getenv("OSX_ASSUMES_FATAL")) {
101 pthread_once(&once
, _osx_abort_on_assumes_once
);
102 result
= _osx_should_abort_on_assumes
;
105 if (getenv("OSX_ASSUMES_FATAL_PID1")) {
114 static osx_redirect_t
115 _osx_find_log_redirect_func(struct mach_header_64
*hdr
)
117 osx_redirect_t result
= NULL
;
120 unsigned long size
= 0;
121 uint8_t *data
= getsectiondata(hdr
, "__TEXT", OSX_ASSUME_LOG_REDIRECT_SECT_NAME
, &size
);
122 if (data
&& size
< sizeof(name
) - 2) {
123 /* Ensure NUL termination. */
124 (void)strlcpy(name
, (const char *)data
, size
+ 1);
125 result
= dlsym(RTLD_DEFAULT
, name
);
131 static osx_redirect_t
132 _osx_find_log_redirect_func(struct mach_header
*hdr
)
134 osx_redirect_t result
= NULL
;
137 unsigned long size
= 0;
138 uint8_t *data
= getsectiondata(hdr
, "__TEXT", OSX_ASSUME_LOG_REDIRECT_SECT_NAME
, &size
);
139 if (data
&& size
< sizeof(name
) - 2) {
140 (void)strlcpy(name
, (const char *)data
, size
+ 1);
141 result
= dlsym(RTLD_DEFAULT
, name
);
149 _osx_log_redirect(void *hdr
, const char *msg
)
153 osx_redirect_t redirect_func
= _osx_find_log_redirect_func(hdr
);
155 result
= redirect_func(msg
);
161 __attribute__((always_inline
))
163 _osx_construct_message(const char *prefix
, uint64_t code
, aslmsg asl_message
, Dl_info
*info
, char *buff
, size_t sz
)
165 const char *image_name
= NULL
;
166 uintptr_t offset
= 0;
167 uuid_string_t uuid_str
;
169 void *ret
= __builtin_return_address(0);
170 if (dladdr(ret
, info
)) {
172 _osx_get_image_uuid(info
->dli_fbase
, uuid
);
174 uuid_unparse(uuid
, uuid_str
);
175 image_name
= _osx_basename(info
->dli_fname
);
177 offset
= ret
- info
->dli_fbase
;
181 (void)snprintf(name
, sizeof(name
), "com.apple.assumes.%s", image_name
);
184 (void)snprintf(sig
, sizeof(sig
), "%s:%lu", uuid_str
, offset
);
187 (void)snprintf(result
, sizeof(result
), "0x%llx", code
);
190 size_t bsz
= sizeof(build
);
191 _osx_get_build(build
, bsz
);
193 (void)snprintf(buff
, sz
, "%s: %s: %s + %lu [%s]: %s", prefix
, build
, image_name
, offset
, uuid_str
, result
);
195 (void)asl_set(asl_message
, "com.apple.message.domain", name
);
196 (void)asl_set(asl_message
, "com.apple.message.signature", sig
);
197 (void)asl_set(asl_message
, "com.apple.message.value", result
);
201 _osx_assumes_log(uint64_t code
)
203 aslmsg asl_message
= asl_new(ASL_TYPE_MSG
);
207 _osx_construct_message("Bug", code
, asl_message
, &info
, message
, sizeof(message
));
208 if (!_osx_log_redirect(info
.dli_fbase
, message
)) {
209 /* MessageTracer messages aren't logged to the regular syslog store,
210 * so we log the message without any MessageTracer attributes so
211 * that we can see it in our regular syslog.
213 (void)asl_log(NULL
, NULL
, ASL_LEVEL_ERR
, "%s", message
);
214 (void)asl_log(NULL
, asl_message
, ASL_LEVEL_ERR
, "%s", message
);
217 asl_free(asl_message
);
220 if (_osx_abort_on_assumes()) {
226 _osx_assert_log(uint64_t code
)
230 aslmsg asl_message
= asl_new(ASL_TYPE_MSG
);
234 _osx_construct_message("Fatal bug", code
, asl_message
, &info
, message
, sizeof(message
));
235 if (!_osx_log_redirect(info
.dli_fbase
, message
)) {
236 (void)asl_log(NULL
, NULL
, ASL_LEVEL_ERR
, "%s", message
);
237 (void)asl_log(NULL
, asl_message
, ASL_LEVEL_ERR
, "%s", message
);
240 asl_free(asl_message
);
241 result
= strdup(message
);
244 #if LIBC_NO_LIBCRASHREPORTERCLIENT
245 /* There is no crash report information facility on embedded, which is
246 * really regrettable. Fortunately, all we need to capture is the value
247 * which tripped up the assertion. We can just stuff that into the thread's
251 (void)pthread_getname_np(pthread_self(), name
, sizeof(name
));
254 if (strlen(name
) == 0) {
255 (void)snprintf(newname
, sizeof(newname
), "[Fatal bug: 0x%llx]", code
);
257 (void)snprintf(newname
, sizeof(newname
), "%s [Fatal bug: 0x%llx]", name
, code
);
260 (void)pthread_setname_np(newname
);
267 _osx_assumes_log_ctx(osx_log_callout_t callout
, void *ctx
, uint64_t code
)
269 aslmsg asl_message
= asl_new(ASL_TYPE_MSG
);
273 _osx_construct_message("Bug", code
, asl_message
, &info
, message
, sizeof(message
));
275 (void)callout(asl_message
, ctx
, message
);
276 asl_free(asl_message
);
279 if (_osx_abort_on_assumes()) {
285 _osx_assert_log_ctx(osx_log_callout_t callout
, void *ctx
, uint64_t code
)
289 aslmsg asl_message
= asl_new(ASL_TYPE_MSG
);
293 _osx_construct_message("Fatal bug", code
, asl_message
, &info
, message
, sizeof(message
));
295 (void)callout(asl_message
, ctx
, message
);
296 asl_free(asl_message
);
297 result
= strdup(message
);
302 _osx_avoid_tail_call(void)