Libc-1439.40.11.tar.gz
[apple/libc.git] / os / assumes.c
CommitLineData
6465356a
A
1/*
2 * Copyright (c) 2011, 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
23e20b00 24#include <TargetConditionals.h>
6465356a
A
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>
6465356a
A
30#include <mach-o/getsect.h>
31#include <pthread.h>
32#include <sys/types.h>
b061a43b 33#include <sys/reason.h>
507116e3 34#include <unistd.h>
6465356a
A
35#include <execinfo.h>
36#include <stdio.h>
6465356a
A
37#include <_simple.h>
38#include <errno.h>
39#include <pthread.h>
40#include <string.h>
41#include "os/assumes.h"
507116e3
A
42
43#if !TARGET_OS_DRIVERKIT
44#include <dlfcn.h>
23e20b00 45#include <os/debug_private.h>
b061a43b
A
46#include <os/log.h>
47#include <os/log_private.h>
48#include <os/reason_private.h>
507116e3
A
49#else
50#define _os_debug_log_error_str(...)
51// placeholder to disable usage of dlfcn.h
52typedef struct dl_info {
53 void *dli_fbase;
54} Dl_info;
55#endif
56#if __has_include(<CrashReporterClient.h>)
b061a43b
A
57#include <CrashReporterClient.h>
58#define os_set_crash_message(arg) CRSetCrashLogMessage(arg)
507116e3
A
59#else
60#define os_set_crash_message(arg)
61#endif
6465356a
A
62
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))
65
507116e3 66#if !TARGET_OS_DRIVERKIT
6465356a
A
67static const char *
68_os_basename(const char *p)
69{
70 return ((strrchr(p, '/') ? : p - 1) + 1);
71}
507116e3 72#endif
6465356a
A
73
74static void
75_os_get_build(char *build, size_t sz)
76{
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.
81 */
82 int mib[] = { CTL_KERN, KERN_OSVERSION };
83
84 size_t oldsz = sz;
85 int r = sysctl(mib, 2, build, &sz, NULL, 0);
86 if (r == 0 && sz == 1) {
87 (void)strlcpy(build, "99Z999", oldsz);
88 }
23e20b00
A
89#if TARGET_IPHONE_SIMULATOR
90 char *simVersion = getenv("SIMULATOR_RUNTIME_BUILD_VERSION");
91 if (simVersion) {
92 strlcat(build, " ", oldsz);
93 strlcat(build, simVersion, oldsz);
94 }
95#endif
6465356a
A
96}
97
507116e3 98#if !TARGET_OS_DRIVERKIT
6465356a
A
99static void
100_os_get_image_uuid(void *hdr, uuid_t uuid)
101{
102#if __LP64__
103 struct mach_header_64 *hdr32or64 = (struct mach_header_64 *)hdr;
104#else
105 struct mach_header *hdr32or64 = (struct mach_header *)hdr;
106#endif /* __LP64__ */
107
108 size_t i = 0;
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);
116 break;
117 }
118
119 next += cur->cmdsize;
120 }
121
122 if (i == hdr32or64->ncmds) {
123 uuid_clear(uuid);
124 }
125}
507116e3 126#endif
6465356a 127
6465356a
A
128static bool
129_os_abort_on_assumes(void)
130{
6465356a
A
131 bool result = false;
132
133 if (getpid() != 1) {
134 if (getenv("OS_ASSUMES_FATAL")) {
135 result = true;
6465356a
A
136 }
137 } else {
138 if (getenv("OS_ASSUMES_FATAL_PID1")) {
139 result = true;
140 }
141 }
142
143 return result;
144}
145
146#if __LP64__
147typedef struct mach_header_64 os_mach_header;
148#else
149typedef struct mach_header os_mach_header;
150#endif
151
152static os_redirect_t
153_os_find_log_redirect_func(os_mach_header *hdr)
154{
155 os_redirect_t result = NULL;
156
507116e3 157#if !TARGET_OS_DRIVERKIT
6465356a
A
158 char name[128];
159 unsigned long size = 0;
160 uint8_t *data = getsectiondata(hdr, OS_ASSUMES_REDIRECT_SEG, OS_ASSUMES_REDIRECT_SECT, &size);
161 if (!data) {
162 data = getsectiondata(hdr, "__TEXT", OSX_ASSUMES_LOG_REDIRECT_SECT_NAME, &size);
163
164 if (data && size < sizeof(name) - 2) {
165 (void)strlcpy(name, (const char *)data, size + 1);
166 result = dlsym(RTLD_DEFAULT, name);
167 }
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;
171 }
507116e3 172#endif
6465356a
A
173
174 return result;
175}
176
177static bool
178_os_log_redirect(void *hdr, const char *msg)
179{
180 bool result = false;
181
182 os_redirect_t redirect_func = _os_find_log_redirect_func(hdr);
183 if (redirect_func) {
184 result = redirect_func(msg);
185 }
186
187 return result;
188}
189
190__attribute__((always_inline))
191static void
192_os_construct_message(uint64_t code, _SIMPLE_STRING asl_message, Dl_info *info, char *buff, size_t sz)
193{
194 const char *image_name = NULL;
195 uintptr_t offset = 0;
196 uuid_string_t uuid_str;
197
507116e3 198#if !TARGET_OS_DRIVERKIT
6465356a
A
199 void *ret = __builtin_return_address(0);
200 if (dladdr(ret, info)) {
201 uuid_t uuid;
202 _os_get_image_uuid(info->dli_fbase, uuid);
203
204 uuid_unparse(uuid, uuid_str);
205 image_name = _os_basename(info->dli_fname);
206
207 offset = ret - info->dli_fbase;
208 }
507116e3
A
209#else
210 info->dli_fbase = NULL;
211#endif
6465356a
A
212
213 char sig[64];
214 (void)snprintf(sig, sizeof(sig), "%s:%lu", uuid_str, offset);
215
216 char result[24];
217 (void)snprintf(result, sizeof(result), "0x%llx", code);
218
23e20b00 219 char build[32];
6465356a
A
220 size_t bsz = sizeof(build);
221 _os_get_build(build, bsz);
222
223 (void)snprintf(buff, sz, "assertion failed: %s: %s + %lu [%s]: %s", build, image_name, offset, uuid_str, result);
224
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");
230}
231
232#pragma mark Internal Implementations
5f125488
A
233
234os_crash_callback_t _os_crash_callback = NULL;
235
236__attribute__((always_inline))
237static inline void
238_os_crash_impl(const char *message) {
239 os_set_crash_message(message);
507116e3 240#if !TARGET_OS_DRIVERKIT
5f125488
A
241 if (!_os_crash_callback) {
242 _os_crash_callback = dlsym(RTLD_MAIN_ONLY, "os_crash_function");
243 }
244 if (_os_crash_callback) {
245 _os_crash_callback(message);
246 }
507116e3 247#endif
5f125488
A
248}
249
507116e3 250#if !TARGET_OS_DRIVERKIT
b061a43b
A
251__attribute__((always_inline))
252static inline bool
253_os_crash_fmt_impl(os_log_pack_t pack, size_t pack_size)
254{
255 /*
256 * We put just the format string into the CrashReporter buffer so that we
257 * can get at least that on customer builds.
258 */
259 const char *message = pack->olp_format;
260 _os_crash_impl(message);
261
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;
266
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;
270
271 char *composed = _os_log_pack_send_and_compose(pack, __os_log_default,
70ad1dc8 272 OS_LOG_TYPE_ERROR, NULL, 0);
b061a43b
A
273
274 abort_with_payload(OS_REASON_LIBSYSTEM, OS_REASON_LIBSYSTEM_CODE_FAULT, pack, pack_size, composed, 0);
275}
507116e3 276#endif
b061a43b 277
6465356a
A
278__attribute__((always_inline))
279static inline void
280_os_assumes_log_impl(uint64_t code)
281{
5f125488
A
282 char message[256] = "";
283
6465356a
A
284 _SIMPLE_STRING asl_message = _simple_asl_msg_new();
285 if (asl_message) {
286 Dl_info info;
6465356a
A
287 _os_construct_message(code, asl_message, &info, message, sizeof(message));
288 if (!_os_log_redirect(info.dli_fbase, message)) {
23e20b00 289 _os_debug_log_error_str(message);
6465356a
A
290 _simple_asl_msg_set(asl_message, "Level", "Error");
291 _simple_asl_msg_set(asl_message, "Message", "");
292 _simple_asl_send(asl_message);
293 }
294
295 _simple_sfree(asl_message);
296 }
297
298 if (_os_abort_on_assumes()) {
5f125488 299 os_crash(message);
6465356a
A
300 }
301}
302
303__attribute__((always_inline))
304static inline char *
305_os_assert_log_impl(uint64_t code)
306{
307 char *result = NULL;
308
309 _SIMPLE_STRING asl_message = _simple_asl_msg_new();
310 if (asl_message) {
311 Dl_info info;
312 char message[256];
313 _os_construct_message(code, asl_message, &info, message, sizeof(message));
314 if (!_os_log_redirect(info.dli_fbase, message)) {
23e20b00 315 _os_debug_log_error_str(message);
6465356a
A
316 _simple_asl_msg_set(asl_message, "Level", "Error");
317 _simple_asl_msg_set(asl_message, "Message", "");
318 _simple_asl_send(asl_message);
319 }
320
321 _simple_sfree(asl_message);
322 result = strdup(message);
323 }
324
6465356a
A
325 return result;
326}
327
328__attribute__((always_inline))
329static inline void
330_os_assumes_log_ctx_impl(os_log_callout_t callout, void *ctx, uint64_t code)
331{
5f125488
A
332 char message[256] = "";
333
6465356a
A
334 _SIMPLE_STRING asl_message = _simple_asl_msg_new();
335 if (asl_message) {
336 Dl_info info;
6465356a
A
337 _os_construct_message(code, asl_message, &info, message, sizeof(message));
338
339 (void)callout(asl_message, ctx, message);
340 _simple_sfree(asl_message);
341 }
342
343 if (_os_abort_on_assumes()) {
5f125488 344 os_crash(message);
6465356a
A
345 }
346}
347
348__attribute__((always_inline))
349static inline char *
350_os_assert_log_ctx_impl(os_log_callout_t callout, void *ctx, uint64_t code)
351{
352 char *result = NULL;
353
354 _SIMPLE_STRING asl_message = _simple_asl_msg_new();
355 if (asl_message) {
356 Dl_info info;
357 char message[256];
358 _os_construct_message(code, asl_message, &info, message, sizeof(message));
359
360 (void)callout(asl_message, ctx, message);
361 _simple_sfree(asl_message);
362 result = strdup(message);
363 }
364 return result;
365}
366
367#pragma mark Public Interfaces
5f125488
A
368void _os_crash(const char *message)
369{
370 _os_crash_impl(message);
371}
372
507116e3 373#if !TARGET_OS_DRIVERKIT
b061a43b
A
374void _os_crash_fmt(os_log_pack_t pack, size_t pack_size)
375{
376 _os_crash_fmt_impl(pack, pack_size);
377}
507116e3 378#endif
b061a43b 379
6465356a
A
380void
381_os_assumes_log(uint64_t code)
382{
383 _os_assumes_log_impl(code);
384}
385
386char *
387_os_assert_log(uint64_t code)
388{
389 return _os_assert_log_impl(code);
390}
391
392void
393_os_assumes_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code)
394{
395 _os_assumes_log_ctx_impl(callout, ctx, code);
396}
397
398char *
399_os_assert_log_ctx(os_log_callout_t callout, void *ctx, uint64_t code)
400{
401 return _os_assert_log_ctx_impl(callout, ctx, code);
402}
403
404void
405_os_avoid_tail_call(void)
406{
407 // no-op
408}