1//===-- sanitizer_mac.cpp -------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is shared between various sanitizers' runtime libraries and
10// implements OSX-specific functions.
11//===----------------------------------------------------------------------===//
12
13#include "sanitizer_platform.h"
14#if SANITIZER_APPLE
15# include "interception/interception.h"
16# include "sanitizer_mac.h"
17
18// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
19// the clients will most certainly use 64-bit ones as well.
20# ifndef _DARWIN_USE_64_BIT_INODE
21# define _DARWIN_USE_64_BIT_INODE 1
22# endif
23# include <stdio.h>
24
25// Start searching for available memory region past PAGEZERO, which is
26// 4KB on 32-bit and 4GB on 64-bit.
27# define GAP_SEARCH_START_ADDRESS \
28 ((SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000)
29
30# include "sanitizer_allocator_internal.h"
31# include "sanitizer_common.h"
32# include "sanitizer_file.h"
33# include "sanitizer_flags.h"
34# include "sanitizer_interface_internal.h"
35# include "sanitizer_internal_defs.h"
36# include "sanitizer_libc.h"
37# include "sanitizer_platform_limits_posix.h"
38# include "sanitizer_procmaps.h"
39# include "sanitizer_ptrauth.h"
40
41# if !SANITIZER_IOS
42# include <crt_externs.h> // for _NSGetEnviron
43# else
44extern char **environ;
45# endif
46
47// Integrate with CrashReporter library if available
48# if defined(__has_include) && __has_include(<CrashReporterClient.h>)
49# define HAVE_CRASHREPORTERCLIENT_H 1
50# include <CrashReporterClient.h>
51# else
52# define HAVE_CRASHREPORTERCLIENT_H 0
53# endif
54
55# if !SANITIZER_IOS
56# include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron
57# else
58extern "C" {
59extern char ***_NSGetArgv(void);
60}
61# endif
62
63# include <asl.h>
64# include <dlfcn.h> // for dladdr()
65# include <errno.h>
66# include <fcntl.h>
67# include <inttypes.h>
68# include <libkern/OSAtomic.h>
69# include <mach-o/dyld.h>
70# include <mach/mach.h>
71# include <mach/mach_error.h>
72# include <mach/mach_time.h>
73# include <mach/vm_statistics.h>
74# include <malloc/malloc.h>
75# include <os/log.h>
76# include <pthread.h>
77# include <pthread/introspection.h>
78# include <sched.h>
79# include <signal.h>
80# include <spawn.h>
81# include <stdlib.h>
82# include <sys/ioctl.h>
83# include <sys/mman.h>
84# include <sys/resource.h>
85# include <sys/stat.h>
86# include <sys/sysctl.h>
87# include <sys/types.h>
88# include <sys/wait.h>
89# include <unistd.h>
90# include <util.h>
91
92// From <crt_externs.h>, but we don't have that file on iOS.
93extern "C" {
94 extern char ***_NSGetArgv(void);
95 extern char ***_NSGetEnviron(void);
96}
97
98// From <mach/mach_vm.h>, but we don't have that file on iOS.
99extern "C" {
100extern kern_return_t mach_vm_region_recurse(vm_map_t target_task,
101 mach_vm_address_t* address,
102 mach_vm_size_t* size,
103 natural_t* nesting_depth,
104 vm_region_recurse_info_t info,
105 mach_msg_type_number_t* infoCnt);
106
107extern const void* _dyld_get_shared_cache_range(size_t* length);
108}
109
110# if !SANITIZER_GO
111// Weak symbol no-op when TSan is not linked
112SANITIZER_WEAK_ATTRIBUTE extern void __tsan_set_in_internal_write_call(
113 bool value) {}
114# endif
115
116namespace __sanitizer {
117
118#include "sanitizer_syscall_generic.inc"
119
120// Direct syscalls, don't call libmalloc hooks (but not available on 10.6).
121extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes,
122 off_t off) SANITIZER_WEAK_ATTRIBUTE;
123extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE;
124
125// ---------------------- sanitizer_libc.h
126
127// From <mach/vm_statistics.h>, but not on older OSs.
128#ifndef VM_MEMORY_SANITIZER
129#define VM_MEMORY_SANITIZER 99
130#endif
131# ifndef VM_MEMORY_DEBUG
132# define VM_MEMORY_DEBUG 108
133# endif
134
135// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of
136// giant memory regions (i.e. shadow memory regions).
137#define kXnuFastMmapFd 0x4
138static size_t kXnuFastMmapThreshold = 2 << 30; // 2 GB
139static bool use_xnu_fast_mmap = false;
140bool debug_region_activated = false;
141
142uptr internal_mmap(void* addr_hint, size_t length, int prot, int flags, int fd,
143 u64 offset) {
144 bool use_debug_vm = false;
145 if (fd == -1) {
146 use_debug_vm = (debug_region_activated &&
147 (uptr)addr_hint >= DARWIN_DEBUG_MEMORY_START);
148 fd = VM_MAKE_TAG(use_debug_vm ? VM_MEMORY_DEBUG : VM_MEMORY_SANITIZER);
149 if (length >= kXnuFastMmapThreshold) {
150 if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd;
151 }
152 }
153
154 auto mmap_fn = (&__mmap ? __mmap : mmap);
155 uptr addr = (uptr)mmap_fn(addr_hint, length, prot, flags, fd, offset);
156
157 if (addr == (uptr)MAP_FAILED)
158 return (uptr)MAP_FAILED;
159
160 // If mmap succeeded, check that the return value is within
161 // the expected range.
162 if (use_debug_vm) {
163 // Allocations from the debug region should be >= DARWIN_DEBUG_MEMORY_START
164 if (addr < DARWIN_DEBUG_MEMORY_START) {
165 Report(
166 "FATAL: Unsupported VM layout. mmap returned %p, Expected debug "
167 "memory >= %p\n",
168 addr, DARWIN_DEBUG_MEMORY_START);
169 Die();
170 }
171 } else {
172 // Allocations NOT from the debug region should be inside the range given by
173 // SANITIZER_MMAP_BEGIN and SANITIZER_MMAP_RANGE_SIZE
174 if (addr < SANITIZER_MMAP_BEGIN ||
175 addr + length > SANITIZER_MMAP_BEGIN + SANITIZER_MMAP_RANGE_SIZE) {
176 Report(
177 "FATAL: Unsupported VM layout. mmap returned %p, expected [%p, %p]\n",
178 addr, SANITIZER_MMAP_BEGIN,
179 SANITIZER_MMAP_BEGIN + SANITIZER_MMAP_RANGE_SIZE);
180 Die();
181 }
182 }
183
184 return addr;
185}
186
187uptr internal_munmap(void *addr, uptr length) {
188 if (&__munmap) return __munmap(addr, length);
189 return munmap(addr, length);
190}
191
192uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
193 void *new_address) {
194 CHECK(false && "internal_mremap is unimplemented on Mac");
195 return 0;
196}
197
198int internal_mprotect(void *addr, uptr length, int prot) {
199 return mprotect(addr, length, prot);
200}
201
202int internal_madvise(uptr addr, uptr length, int advice) {
203 return madvise((void *)addr, length, advice);
204}
205
206uptr internal_close(fd_t fd) {
207 return close(fd);
208}
209
210uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
211 return -1; // Not supported.
212}
213
214uptr internal_open(const char *filename, int flags) {
215 return open(filename, flags);
216}
217
218uptr internal_open(const char *filename, int flags, u32 mode) {
219 return open(filename, flags, mode);
220}
221
222uptr internal_read(fd_t fd, void *buf, uptr count) {
223 return read(fd, buf, count);
224}
225
226uptr internal_write(fd_t fd, const void *buf, uptr count) {
227# if SANITIZER_GO
228 return write(fd, buf, count);
229# else
230 // We need to disable interceptors when writing in TSan
231 __tsan_set_in_internal_write_call(true);
232 uptr res = write(fd, buf, count);
233 __tsan_set_in_internal_write_call(false);
234 return res;
235# endif
236}
237
238uptr internal_stat(const char *path, void *buf) {
239 return stat(path, (struct stat *)buf);
240}
241
242uptr internal_lstat(const char *path, void *buf) {
243 return lstat(path, (struct stat *)buf);
244}
245
246uptr internal_fstat(fd_t fd, void *buf) {
247 return fstat(fd, (struct stat *)buf);
248}
249
250uptr internal_filesize(fd_t fd) {
251 struct stat st;
252 if (internal_fstat(fd, &st))
253 return -1;
254 return (uptr)st.st_size;
255}
256
257uptr internal_dup(int oldfd) {
258 return dup(oldfd);
259}
260
261uptr internal_dup2(int oldfd, int newfd) {
262 return dup2(oldfd, newfd);
263}
264
265uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
266 return readlink(path, buf, bufsize);
267}
268
269uptr internal_unlink(const char *path) {
270 return unlink(path);
271}
272
273uptr internal_sched_yield() {
274 return sched_yield();
275}
276
277void internal__exit(int exitcode) {
278 _exit(exitcode);
279}
280
281void internal_usleep(u64 useconds) { usleep(useconds); }
282
283uptr internal_getpid() {
284 return getpid();
285}
286
287int internal_dlinfo(void *handle, int request, void *p) {
288 UNIMPLEMENTED();
289}
290
291int internal_sigaction(int signum, const void *act, void *oldact) {
292 return sigaction(signum,
293 (const struct sigaction *)act, (struct sigaction *)oldact);
294}
295
296void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }
297
298uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
299 __sanitizer_sigset_t *oldset) {
300 // Don't use sigprocmask here, because it affects all threads.
301 return pthread_sigmask(how, set, oldset);
302}
303
304// Doesn't call pthread_atfork() handlers (but not available on 10.6).
305extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE;
306
307int internal_fork() {
308 if (&__fork)
309 return __fork();
310 return fork();
311}
312
313int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
314 uptr *oldlenp, const void *newp, uptr newlen) {
315 return sysctl(const_cast<int *>(name), namelen, oldp, (size_t *)oldlenp,
316 const_cast<void *>(newp), (size_t)newlen);
317}
318
319int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
320 const void *newp, uptr newlen) {
321 return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast<void *>(newp),
322 (size_t)newlen);
323}
324
325bool internal_spawn(const char* argv[], const char* envp[], pid_t* pid,
326 fd_t fd_stdin, fd_t fd_stdout) {
327 // NOTE: Caller ensures that fd_stdin and fd_stdout are not 0, 1, or 2, since
328 // this can break communication.
329 //
330 // NOTE: Caller is responsible for closing fd_stdin after the process has
331 // died.
332
333 int res;
334 auto fd_closer = at_scope_exit([&] {
335 // NOTE: We intentionally do not close fd_stdin since this can
336 // cause us to receive a fatal SIGPIPE if the process dies.
337 internal_close(fd_stdout);
338 });
339
340 // File descriptor actions
341 posix_spawn_file_actions_t acts;
342 res = posix_spawn_file_actions_init(&acts);
343 if (res != 0)
344 return false;
345
346 auto acts_cleanup = at_scope_exit([&] {
347 posix_spawn_file_actions_destroy(&acts);
348 });
349
350 res = posix_spawn_file_actions_adddup2(&acts, fd_stdin, STDIN_FILENO) ||
351 posix_spawn_file_actions_adddup2(&acts, fd_stdout, STDOUT_FILENO) ||
352 posix_spawn_file_actions_addclose(&acts, fd_stdin) ||
353 posix_spawn_file_actions_addclose(&acts, fd_stdout);
354 if (res != 0)
355 return false;
356
357 // Spawn attributes
358 posix_spawnattr_t attrs;
359 res = posix_spawnattr_init(&attrs);
360 if (res != 0)
361 return false;
362
363 auto attrs_cleanup = at_scope_exit([&] {
364 posix_spawnattr_destroy(&attrs);
365 });
366
367 // In the spawned process, close all file descriptors that are not explicitly
368 // described by the file actions object. This is Darwin-specific extension.
369 res = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_CLOEXEC_DEFAULT);
370 if (res != 0)
371 return false;
372
373 // posix_spawn
374 char **argv_casted = const_cast<char **>(argv);
375 char **envp_casted = const_cast<char **>(envp);
376 res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted);
377 if (res != 0)
378 return false;
379
380 return true;
381}
382
383uptr internal_rename(const char *oldpath, const char *newpath) {
384 return rename(oldpath, newpath);
385}
386
387uptr internal_ftruncate(fd_t fd, uptr size) {
388 return ftruncate(fd, size);
389}
390
391uptr internal_execve(const char *filename, char *const argv[],
392 char *const envp[]) {
393 return execve(filename, argv, envp);
394}
395
396uptr internal_waitpid(int pid, int *status, int options) {
397 return waitpid(pid, status, options);
398}
399
400kern_return_t internal_mach_vm_region_recurse(vm_map_t target_task,
401 mach_vm_address_t* address,
402 mach_vm_size_t* size,
403 natural_t* nesting_depth,
404 vm_region_recurse_info_t info,
405 mach_msg_type_number_t* infoCnt) {
406 kern_return_t kr = mach_vm_region_recurse(target_task, address, size,
407 nesting_depth, info, infoCnt);
408 if (kr == KERN_DENIED) {
409 Report(
410 "FATAL: mach_vm_region_recurse returned KERN_DENIED when checking "
411 "whether an address is mapped.\n");
412 Report("HINT: Is mach_vm_region_recurse allowed by sandbox?\n");
413 Die();
414 }
415 return kr;
416}
417
418// ----------------- sanitizer_common.h
419bool FileExists(const char *filename) {
420 if (ShouldMockFailureToOpen(filename))
421 return false;
422 struct stat st;
423 if (stat(filename, &st))
424 return false;
425 // Sanity check: filename is a regular file.
426 return S_ISREG(st.st_mode);
427}
428
429bool DirExists(const char *path) {
430 struct stat st;
431 if (stat(path, &st))
432 return false;
433 return S_ISDIR(st.st_mode);
434}
435
436ThreadID GetTid() {
437 ThreadID tid;
438 pthread_threadid_np(nullptr, &tid);
439 return tid;
440}
441
442void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
443 uptr *stack_bottom) {
444 CHECK(stack_top);
445 CHECK(stack_bottom);
446 uptr stacksize = pthread_get_stacksize_np(pthread_self());
447 // pthread_get_stacksize_np() returns an incorrect stack size for the main
448 // thread on Mavericks. See
449 // https://github.com/google/sanitizers/issues/261
450 if ((GetMacosAlignedVersion() >= MacosVersion(10, 9)) && at_initialization &&
451 stacksize == (1 << 19)) {
452 struct rlimit rl;
453 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
454 // Most often rl.rlim_cur will be the desired 8M.
455 if (rl.rlim_cur < kMaxThreadStackSize) {
456 stacksize = rl.rlim_cur;
457 } else {
458 stacksize = kMaxThreadStackSize;
459 }
460 }
461 void *stackaddr = pthread_get_stackaddr_np(pthread_self());
462 *stack_top = (uptr)stackaddr;
463 *stack_bottom = *stack_top - stacksize;
464}
465
466char **GetEnviron() {
467#if !SANITIZER_IOS
468 char ***env_ptr = _NSGetEnviron();
469 if (!env_ptr) {
470 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
471 "called after libSystem_initializer().\n");
472 CHECK(env_ptr);
473 }
474 char **environ = *env_ptr;
475#endif
476 CHECK(environ);
477 return environ;
478}
479
480const char *GetEnv(const char *name) {
481 char **env = GetEnviron();
482 uptr name_len = internal_strlen(name);
483 while (*env != 0) {
484 uptr len = internal_strlen(*env);
485 if (len > name_len) {
486 const char *p = *env;
487 if (!internal_memcmp(p, name, name_len) &&
488 p[name_len] == '=') { // Match.
489 return *env + name_len + 1; // String starting after =.
490 }
491 }
492 env++;
493 }
494 return 0;
495}
496
497uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
498 CHECK_LE(kMaxPathLength, buf_len);
499
500 // On OS X the executable path is saved to the stack by dyld. Reading it
501 // from there is much faster than calling dladdr, especially for large
502 // binaries with symbols.
503 InternalMmapVector<char> exe_path(kMaxPathLength);
504 uint32_t size = exe_path.size();
505 if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
506 realpath(exe_path.data(), buf) != 0) {
507 return internal_strlen(buf);
508 }
509 return 0;
510}
511
512uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
513 return ReadBinaryName(buf, buf_len);
514}
515
516void ReExec() {
517 UNIMPLEMENTED();
518}
519
520void CheckASLR() {
521 // Do nothing
522}
523
524void CheckMPROTECT() {
525 // Do nothing
526}
527
528uptr GetPageSize() {
529 return sysconf(_SC_PAGESIZE);
530}
531
532extern "C" unsigned malloc_num_zones;
533extern "C" malloc_zone_t **malloc_zones;
534malloc_zone_t sanitizer_zone;
535
536// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If
537// libmalloc tries to set up a different zone as malloc_zones[0], it will call
538// mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and
539// make sure we are still the first (default) zone.
540void MprotectMallocZones(void *addr, int prot) {
541 if (addr == malloc_zones && prot == PROT_READ) {
542 if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) {
543 for (unsigned i = 1; i < malloc_num_zones; i++) {
544 if (malloc_zones[i] == &sanitizer_zone) {
545 // Swap malloc_zones[0] and malloc_zones[i].
546 malloc_zones[i] = malloc_zones[0];
547 malloc_zones[0] = &sanitizer_zone;
548 break;
549 }
550 }
551 }
552 }
553}
554
555void FutexWait(atomic_uint32_t *p, u32 cmp) {
556 // FIXME: implement actual blocking.
557 sched_yield();
558}
559
560void FutexWake(atomic_uint32_t *p, u32 count) {}
561
562u64 NanoTime() {
563 timeval tv;
564 internal_memset(&tv, 0, sizeof(tv));
565 gettimeofday(&tv, 0);
566 return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
567}
568
569// This needs to be called during initialization to avoid being racy.
570u64 MonotonicNanoTime() {
571 static mach_timebase_info_data_t timebase_info;
572 if (timebase_info.denom == 0) mach_timebase_info(&timebase_info);
573 return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom;
574}
575
576uptr GetTlsSize() {
577 return 0;
578}
579
580uptr TlsBaseAddr() {
581 uptr segbase = 0;
582#if defined(__x86_64__)
583 asm("movq %%gs:0,%0" : "=r"(segbase));
584#elif defined(__i386__)
585 asm("movl %%gs:0,%0" : "=r"(segbase));
586#elif defined(__aarch64__)
587 asm("mrs %x0, tpidrro_el0" : "=r"(segbase));
588 segbase &= 0x07ul; // clearing lower bits, cpu id stored there
589#endif
590 return segbase;
591}
592
593// The size of the tls on darwin does not appear to be well documented,
594// however the vm memory map suggests that it is 1024 uptrs in size,
595// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386.
596uptr TlsSize() {
597#if defined(__x86_64__) || defined(__i386__)
598 return 1024 * sizeof(uptr);
599#else
600 return 0;
601#endif
602}
603
604void GetThreadStackAndTls(bool main, uptr *stk_begin, uptr *stk_end,
605 uptr *tls_begin, uptr *tls_end) {
606# if !SANITIZER_GO
607 GetThreadStackTopAndBottom(main, stk_end, stk_begin);
608 *tls_begin = TlsBaseAddr();
609 *tls_end = *tls_begin + TlsSize();
610# else
611 *stk_begin = 0;
612 *stk_end = 0;
613 *tls_begin = 0;
614 *tls_end = 0;
615# endif
616}
617
618void ListOfModules::init() {
619 clearOrInit();
620 MemoryMappingLayout memory_mapping(false);
621 memory_mapping.DumpListOfModules(&modules_);
622}
623
624void ListOfModules::fallbackInit() { clear(); }
625
626static HandleSignalMode GetHandleSignalModeImpl(int signum) {
627 switch (signum) {
628 case SIGABRT:
629 return common_flags()->handle_abort;
630 case SIGILL:
631 return common_flags()->handle_sigill;
632 case SIGTRAP:
633 return common_flags()->handle_sigtrap;
634 case SIGFPE:
635 return common_flags()->handle_sigfpe;
636 case SIGSEGV:
637 return common_flags()->handle_segv;
638 case SIGBUS:
639 return common_flags()->handle_sigbus;
640 }
641 return kHandleSignalNo;
642}
643
644HandleSignalMode GetHandleSignalMode(int signum) {
645 // Handling fatal signals on watchOS and tvOS devices is disallowed.
646 if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))
647 return kHandleSignalNo;
648 HandleSignalMode result = GetHandleSignalModeImpl(signum);
649 if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)
650 return kHandleSignalExclusive;
651 return result;
652}
653
654// Offset example:
655// XNU 17 -- macOS 10.13 -- iOS 11 -- tvOS 11 -- watchOS 4
656constexpr u16 GetOSMajorKernelOffset() {
657 if (TARGET_OS_OSX) return 4;
658 if (TARGET_OS_IOS || TARGET_OS_TV) return 6;
659 if (TARGET_OS_WATCH) return 13;
660}
661
662using VersStr = char[64];
663
664static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
665 u16 kernel_major = GetDarwinKernelVersion().major;
666 u16 offset = GetOSMajorKernelOffset();
667 CHECK_GE(kernel_major, offset);
668 u16 os_major = kernel_major - offset;
669
670 const char *format = "%d.0";
671 if (kernel_major >= 27) {
672 // with kernel major 27 <=> OSes 27.0, OS versions are aligned with kernel
673 os_major = kernel_major;
674 } else if (kernel_major >= 25) {
675 // with kernel_major 25 <=> OSes 26.0, OS versions are aligned
676 os_major = kernel_major + 1;
677 } else if (TARGET_OS_OSX) {
678 if (os_major >= 16) { // macOS 11+
679 os_major -= 5;
680 } else { // macOS 10.15 and below
681 format = "10.%d";
682 }
683 }
684 return internal_snprintf(vers, sizeof(VersStr), format, os_major);
685}
686
687static void GetOSVersion(VersStr vers) {
688 uptr len = sizeof(VersStr);
689 if (SANITIZER_IOSSIM) {
690 const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION");
691 if (!vers_env) {
692 Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env "
693 "var is not set.\n");
694 Die();
695 }
696 len = internal_strlcpy(vers, vers_env, len);
697 } else {
698 int res =
699 internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
700
701 // XNU 17 (macOS 10.13) and below do not provide the sysctl
702 // `kern.osproductversion` entry (res != 0).
703 bool no_os_version = res != 0;
704
705 // For launchd, sanitizer initialization runs before sysctl is setup
706 // (res == 0 && len != strlen(vers), vers is not a valid version). However,
707 // the kernel version `kern.osrelease` is available.
708 bool launchd = (res == 0 && internal_strlen(vers) < 3);
709 if (launchd) CHECK_EQ(internal_getpid(), 1);
710
711 if (no_os_version || launchd) {
712 len = ApproximateOSVersionViaKernelVersion(vers);
713 }
714 }
715 CHECK_LT(len, sizeof(VersStr));
716}
717
718void ParseVersion(const char *vers, u16 *major, u16 *minor) {
719 // Format: <major>.<minor>[.<patch>]\0
720 CHECK_GE(internal_strlen(vers), 3);
721 const char *p = vers;
722 *major = internal_simple_strtoll(p, &p, /*base=*/10);
723 CHECK_EQ(*p, '.');
724 p += 1;
725 *minor = internal_simple_strtoll(p, &p, /*base=*/10);
726}
727
728// Aligned versions example:
729// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6
730static void MapToMacos(u16 *major, u16 *minor) {
731 if (TARGET_OS_OSX)
732 return;
733
734 // All supported platforms (including DriverKit) have
735 // aligned version numbers in macOS 27+
736 if (*major >= 27)
737 return;
738
739# if TARGET_OS_DRIVERKIT
740 // Driverkit 25.0+ aligns with macOS 26+
741 if (*major >= 25) {
742 *major += 1;
743 return;
744 }
745# else
746 // macOS 26 and later have aligned version strings.
747 if (*major >= 26)
748 return;
749# endif
750
751 // Below are mappings for pre-macOS-25-aligned releases
752 if (TARGET_OS_IOS || TARGET_OS_TV)
753 *major += 2;
754 else if (TARGET_OS_WATCH)
755 *major += 9;
756 else
757 UNREACHABLE("unsupported platform");
758
759 if (*major >= 16) { // macOS 11+
760 *major -= 5;
761 } else { // macOS 10.15 and below
762 *minor = *major;
763 *major = 10;
764 }
765}
766
767static MacosVersion GetMacosAlignedVersionInternal() {
768 VersStr vers = {};
769 GetOSVersion(vers);
770
771 u16 major, minor;
772 ParseVersion(vers, &major, &minor);
773 MapToMacos(&major, &minor);
774
775 return MacosVersion(major, minor);
776}
777
778static_assert(sizeof(MacosVersion) == sizeof(atomic_uint32_t::Type),
779 "MacosVersion cache size");
780static atomic_uint32_t cached_macos_version;
781
782MacosVersion GetMacosAlignedVersion() {
783 atomic_uint32_t::Type result =
784 atomic_load(&cached_macos_version, memory_order_acquire);
785 if (!result) {
786 MacosVersion version = GetMacosAlignedVersionInternal();
787 result = *reinterpret_cast<atomic_uint32_t::Type *>(&version);
788 atomic_store(&cached_macos_version, result, memory_order_release);
789 }
790 return *reinterpret_cast<MacosVersion *>(&result);
791}
792
793DarwinKernelVersion GetDarwinKernelVersion() {
794 VersStr vers = {};
795 uptr len = sizeof(VersStr);
796 int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
797 CHECK_EQ(res, 0);
798 CHECK_LT(len, sizeof(VersStr));
799
800 u16 major, minor;
801 ParseVersion(vers, &major, &minor);
802
803 return DarwinKernelVersion(major, minor);
804}
805
806uptr GetRSS() {
807 struct task_basic_info info;
808 unsigned count = TASK_BASIC_INFO_COUNT;
809 kern_return_t result =
810 task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count);
811 if (UNLIKELY(result != KERN_SUCCESS)) {
812 Report("Cannot get task info. Error: %d\n", result);
813 Die();
814 }
815 return info.resident_size;
816}
817
818void *internal_start_thread(void *(*func)(void *arg), void *arg) {
819 // Start the thread with signals blocked, otherwise it can steal user signals.
820 __sanitizer_sigset_t set, old;
821 internal_sigfillset(&set);
822 internal_sigprocmask(SIG_SETMASK, &set, &old);
823 pthread_t th;
824 pthread_create(&th, 0, func, arg);
825 internal_sigprocmask(SIG_SETMASK, &old, 0);
826 return th;
827}
828
829void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); }
830
831#if !SANITIZER_GO
832static Mutex syslog_lock;
833# endif
834
835# if SANITIZER_DRIVERKIT
836# define SANITIZER_OS_LOG os_log
837# else
838# define SANITIZER_OS_LOG os_log_error
839# endif
840
841void WriteOneLineToSyslog(const char *s) {
842#if !SANITIZER_GO
843 syslog_lock.CheckLocked();
844 if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
845 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s", s);
846 } else {
847#pragma clang diagnostic push
848// as_log is deprecated.
849#pragma clang diagnostic ignored "-Wdeprecated-declarations"
850 asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
851#pragma clang diagnostic pop
852 }
853#endif
854}
855
856// buffer to store crash report application information
857static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};
858static Mutex crashreporter_info_mutex;
859
860extern "C" {
861
862#if HAVE_CRASHREPORTERCLIENT_H
863// Available in CRASHREPORTER_ANNOTATIONS_VERSION 5+
864# ifdef CRASHREPORTER_ANNOTATIONS_INITIALIZER
865CRASHREPORTER_ANNOTATIONS_INITIALIZER()
866# else
867// Support for older CrashRerporter annotiations
868CRASH_REPORTER_CLIENT_HIDDEN
869struct crashreporter_annotations_t gCRAnnotations
870 __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
871 CRASHREPORTER_ANNOTATIONS_VERSION,
872 0,
873 0,
874 0,
875 0,
876 0,
877 0,
878# if CRASHREPORTER_ANNOTATIONS_VERSION > 4
879 0,
880# endif
881};
882# endif
883# else
884// Revert to previous crash reporter API if client header is not available
885static const char *__crashreporter_info__ __attribute__((__used__)) =
886 &crashreporter_info_buff[0];
887asm(".desc ___crashreporter_info__, 0x10");
888#endif // HAVE_CRASHREPORTERCLIENT_H
889
890} // extern "C"
891
892static void CRAppendCrashLogMessage(const char *msg) {
893 Lock l(&crashreporter_info_mutex);
894 internal_strlcat(crashreporter_info_buff, msg,
895 sizeof(crashreporter_info_buff));
896#if HAVE_CRASHREPORTERCLIENT_H
897 (void)CRSetCrashLogMessage(crashreporter_info_buff);
898#endif
899}
900
901void LogMessageOnPrintf(const char *str) {
902 // Log all printf output to CrashLog.
903 if (common_flags()->abort_on_error)
904 CRAppendCrashLogMessage(str);
905}
906
907void LogFullErrorReport(const char *buffer) {
908# if !SANITIZER_GO
909 // When logging with os_log_error this will make it into the crash log.
910 if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
911 sizeof("AddressSanitizer") - 1) == 0)
912 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Address Sanitizer reported a failure.");
913 else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
914 sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
915 SANITIZER_OS_LOG(OS_LOG_DEFAULT,
916 "Undefined Behavior Sanitizer reported a failure.");
917 else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
918 sizeof("ThreadSanitizer") - 1) == 0)
919 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure.");
920 else
921 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Sanitizer tool reported a failure.");
922
923 if (common_flags()->log_to_syslog)
924 SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Consult syslog for more information.");
925
926 // Log to syslog.
927 // The logging on OS X may call pthread_create so we need the threading
928 // environment to be fully initialized. Also, this should never be called when
929 // holding the thread registry lock since that may result in a deadlock. If
930 // the reporting thread holds the thread registry mutex, and asl_log waits
931 // for GCD to dispatch a new thread, the process will deadlock, because the
932 // pthread_create wrapper needs to acquire the lock as well.
933 Lock l(&syslog_lock);
934 if (common_flags()->log_to_syslog)
935 WriteToSyslog(buffer);
936
937 // The report is added to CrashLog as part of logging all of Printf output.
938# endif // !SANITIZER_GO
939}
940
941SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
942#if defined(__x86_64__) || defined(__i386__)
943 ucontext_t *ucontext = static_cast<ucontext_t*>(context);
944 return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? Write : Read;
945#elif defined(__arm64__)
946 ucontext_t *ucontext = static_cast<ucontext_t*>(context);
947 return ucontext->uc_mcontext->__es.__esr & 0x40 /*ISS_DA_WNR*/ ? Write : Read;
948#else
949 return Unknown;
950#endif
951}
952
953bool SignalContext::IsTrueFaultingAddress() const {
954 auto si = static_cast<const siginfo_t *>(siginfo);
955 // "Real" SIGSEGV codes (e.g., SEGV_MAPERR, SEGV_MAPERR) are non-zero.
956 return si->si_signo == SIGSEGV && si->si_code != 0;
957}
958
959#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
960 #define AARCH64_GET_REG(r) \
961 (uptr)ptrauth_strip( \
962 (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0)
963#else
964 #define AARCH64_GET_REG(r) (uptr)ucontext->uc_mcontext->__ss.__##r
965#endif
966
967static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
968 ucontext_t *ucontext = (ucontext_t*)context;
969# if defined(__aarch64__)
970 *pc = AARCH64_GET_REG(pc);
971 *bp = AARCH64_GET_REG(fp);
972 *sp = AARCH64_GET_REG(sp);
973# elif defined(__x86_64__)
974 *pc = ucontext->uc_mcontext->__ss.__rip;
975 *bp = ucontext->uc_mcontext->__ss.__rbp;
976 *sp = ucontext->uc_mcontext->__ss.__rsp;
977# elif defined(__arm__)
978 *pc = ucontext->uc_mcontext->__ss.__pc;
979 *bp = ucontext->uc_mcontext->__ss.__r[7];
980 *sp = ucontext->uc_mcontext->__ss.__sp;
981# elif defined(__i386__)
982 *pc = ucontext->uc_mcontext->__ss.__eip;
983 *bp = ucontext->uc_mcontext->__ss.__ebp;
984 *sp = ucontext->uc_mcontext->__ss.__esp;
985# else
986# error "Unknown architecture"
987# endif
988}
989
990void SignalContext::InitPcSpBp() {
991 addr = (uptr)ptrauth_strip((void *)addr, 0);
992 GetPcSpBp(context, &pc, &sp, &bp);
993}
994
995// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers
996// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+).
997static void DisableMmapExcGuardExceptions() {
998 using task_exc_guard_behavior_t = uint32_t;
999 using task_set_exc_guard_behavior_t =
1000 kern_return_t(task_t task, task_exc_guard_behavior_t behavior);
1001 auto *set_behavior = (task_set_exc_guard_behavior_t *)dlsym(
1002 RTLD_DEFAULT, "task_set_exc_guard_behavior");
1003 if (set_behavior == nullptr) return;
1004 const task_exc_guard_behavior_t task_exc_guard_none = 0;
1005 kern_return_t res = set_behavior(mach_task_self(), task_exc_guard_none);
1006 if (res != KERN_SUCCESS) {
1007 Report(
1008 "WARN: task_set_exc_guard_behavior returned %d (%s), "
1009 "mmap may fail unexpectedly.\n",
1010 res, mach_error_string(res));
1011 if (res == KERN_DENIED)
1012 Report(
1013 "HINT: Check that task_set_exc_guard_behavior is allowed by "
1014 "sandbox.\n");
1015 }
1016}
1017
1018static void VerifyInterceptorsWorking();
1019static void StripEnv();
1020
1021void InitializePlatformEarly() {
1022 // Only use xnu_fast_mmap when on x86_64 and the kernel supports it.
1023 use_xnu_fast_mmap =
1024#if defined(__x86_64__)
1025 GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5);
1026#else
1027 false;
1028#endif
1029 if (GetDarwinKernelVersion() >= DarwinKernelVersion(19, 0))
1030 DisableMmapExcGuardExceptions();
1031
1032# if !SANITIZER_GO
1033 MonotonicNanoTime(); // Call to initialize mach_timebase_info
1034 VerifyInterceptorsWorking();
1035 StripEnv();
1036# endif
1037}
1038
1039#if !SANITIZER_GO
1040static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
1041LowLevelAllocator allocator_for_env;
1042
1043static bool ShouldCheckInterceptors() {
1044 // Restrict "interceptors working?" check
1045 const char *sanitizer_names[] = {"AddressSanitizer", "ThreadSanitizer",
1046 "RealtimeSanitizer"};
1047 size_t count = sizeof(sanitizer_names) / sizeof(sanitizer_names[0]);
1048 for (size_t i = 0; i < count; i++) {
1049 if (internal_strcmp(sanitizer_names[i], SanitizerToolName) == 0)
1050 return true;
1051 }
1052 return false;
1053}
1054
1055static void VerifyInterceptorsWorking() {
1056 if (!common_flags()->verify_interceptors || !ShouldCheckInterceptors())
1057 return;
1058
1059 // Verify that interceptors really work. We'll use dlsym to locate
1060 // "puts", if interceptors are working, it should really point to
1061 // "wrap_puts" within our own dylib.
1062 Dl_info info_puts, info_runtime;
1063 RAW_CHECK(dladdr(dlsym(RTLD_DEFAULT, "puts"), &info_puts));
1064 RAW_CHECK(dladdr((void *)&VerifyInterceptorsWorking, &info_runtime));
1065 if (internal_strcmp(info_puts.dli_fname, info_runtime.dli_fname) != 0) {
1066 Report(
1067 "ERROR: Interceptors are not working. This may be because %s is "
1068 "loaded too late (e.g. via dlopen). Please launch the executable "
1069 "with:\n%s=%s\n",
1070 SanitizerToolName, kDyldInsertLibraries, info_runtime.dli_fname);
1071 RAW_CHECK("interceptors not installed" && 0);
1072 }
1073}
1074
1075// Change the value of the env var |name|, leaking the original value.
1076// If |name_value| is NULL, the variable is deleted from the environment,
1077// otherwise the corresponding "NAME=value" string is replaced with
1078// |name_value|.
1079static void LeakyResetEnv(const char *name, const char *name_value) {
1080 char **env = GetEnviron();
1081 uptr name_len = internal_strlen(name);
1082 while (*env != 0) {
1083 uptr len = internal_strlen(*env);
1084 if (len > name_len) {
1085 const char *p = *env;
1086 if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') {
1087 // Match.
1088 if (name_value) {
1089 // Replace the old value with the new one.
1090 *env = const_cast<char*>(name_value);
1091 } else {
1092 // Shift the subsequent pointers back.
1093 char **del = env;
1094 do {
1095 del[0] = del[1];
1096 } while (*del++);
1097 }
1098 }
1099 }
1100 env++;
1101 }
1102}
1103
1104static void StripEnv() {
1105 if (!common_flags()->strip_env)
1106 return;
1107
1108 char *dyld_insert_libraries =
1109 const_cast<char *>(GetEnv(kDyldInsertLibraries));
1110 if (!dyld_insert_libraries)
1111 return;
1112
1113 Dl_info info;
1114 RAW_CHECK(dladdr((void *)&StripEnv, &info));
1115 const char *dylib_name = StripModuleName(info.dli_fname);
1116 bool lib_is_in_env = internal_strstr(dyld_insert_libraries, dylib_name);
1117 if (!lib_is_in_env)
1118 return;
1119
1120 // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove
1121 // the dylib from the environment variable, because interceptors are installed
1122 // and we don't want our children to inherit the variable.
1123
1124 uptr old_env_len = internal_strlen(dyld_insert_libraries);
1125 uptr dylib_name_len = internal_strlen(dylib_name);
1126 uptr env_name_len = internal_strlen(kDyldInsertLibraries);
1127 // Allocate memory to hold the previous env var name, its value, the '='
1128 // sign and the '\0' char.
1129 char *new_env = (char*)allocator_for_env.Allocate(
1130 old_env_len + 2 + env_name_len);
1131 RAW_CHECK(new_env);
1132 internal_memset(new_env, '\0', old_env_len + 2 + env_name_len);
1133 internal_strncpy(new_env, kDyldInsertLibraries, env_name_len);
1134 new_env[env_name_len] = '=';
1135 char *new_env_pos = new_env + env_name_len + 1;
1136
1137 // Iterate over colon-separated pieces of |dyld_insert_libraries|.
1138 char *piece_start = dyld_insert_libraries;
1139 char *piece_end = NULL;
1140 char *old_env_end = dyld_insert_libraries + old_env_len;
1141 do {
1142 if (piece_start[0] == ':') piece_start++;
1143 piece_end = internal_strchr(piece_start, ':');
1144 if (!piece_end) piece_end = dyld_insert_libraries + old_env_len;
1145 if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break;
1146 uptr piece_len = piece_end - piece_start;
1147
1148 char *filename_start =
1149 (char *)internal_memrchr(piece_start, '/', piece_len);
1150 uptr filename_len = piece_len;
1151 if (filename_start) {
1152 filename_start += 1;
1153 filename_len = piece_len - (filename_start - piece_start);
1154 } else {
1155 filename_start = piece_start;
1156 }
1157
1158 // If the current piece isn't the runtime library name,
1159 // append it to new_env.
1160 if ((dylib_name_len != filename_len) ||
1161 (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) {
1162 if (new_env_pos != new_env + env_name_len + 1) {
1163 new_env_pos[0] = ':';
1164 new_env_pos++;
1165 }
1166 internal_strncpy(new_env_pos, piece_start, piece_len);
1167 new_env_pos += piece_len;
1168 }
1169 // Move on to the next piece.
1170 piece_start = piece_end;
1171 } while (piece_start < old_env_end);
1172
1173 // Can't use setenv() here, because it requires the allocator to be
1174 // initialized.
1175 // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in
1176 // a separate function called after InitializeAllocator().
1177 if (new_env_pos == new_env + env_name_len + 1) new_env = NULL;
1178 LeakyResetEnv(kDyldInsertLibraries, new_env);
1179}
1180#endif // SANITIZER_GO
1181
1182// Prints out a consolidated memory map: contiguous regions
1183// are merged together.
1184static void PrintVmmap() {
1185 const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;
1186 mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;
1187 kern_return_t kr = KERN_SUCCESS;
1188
1189 Report("Memory map:\n");
1190 mach_vm_address_t last = 0;
1191 mach_vm_address_t lastsz = 0;
1192
1193 while (1) {
1194 mach_vm_size_t vmsize = 0;
1195 natural_t depth = 0;
1196 vm_region_submap_short_info_data_64_t vminfo;
1197 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
1198 kr = internal_mach_vm_region_recurse(mach_task_self(), &address, &vmsize,
1199 &depth, (vm_region_info_t)&vminfo,
1200 &count);
1201
1202 if (kr == KERN_SUCCESS && address < max_vm_address) {
1203 if (last + lastsz == address) {
1204 // This region is contiguous with the last; merge together.
1205 lastsz += vmsize;
1206 } else {
1207 if (lastsz)
1208 Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last,
1209 (void*)(last + lastsz), lastsz);
1210
1211 last = address;
1212 lastsz = vmsize;
1213 }
1214 address += vmsize;
1215 } else {
1216 // We've reached the end of the memory map. Print the last remaining
1217 // region, if there is one.
1218 if (lastsz)
1219 Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", (void*)last,
1220 (void*)(last + lastsz), lastsz);
1221
1222 break;
1223 }
1224 }
1225}
1226
1227static void ReportShadowAllocFail(uptr shadow_size_bytes, uptr alignment) {
1228 Report(
1229 "FATAL: Failed to allocate shadow memory. Tried to allocate %p bytes "
1230 "(alignment=%p).\n",
1231 (void*)shadow_size_bytes, (void*)alignment);
1232 PrintVmmap();
1233}
1234
1235char **GetArgv() {
1236 return *_NSGetArgv();
1237}
1238
1239// These platforms definitely support task_info.
1240# if SANITIZER_IOS || SANITIZER_DRIVERKIT || SANITIZER_OSX
1241
1242// The task_vm_info struct is normally provided by the macOS SDK, but we need
1243// fields only available in 10.12+. Declare the struct manually to be able to
1244// build against older SDKs.
1245struct __sanitizer_task_vm_info {
1246 mach_vm_size_t virtual_size;
1247 integer_t region_count;
1248 integer_t page_size;
1249 mach_vm_size_t resident_size;
1250 mach_vm_size_t resident_size_peak;
1251 mach_vm_size_t device;
1252 mach_vm_size_t device_peak;
1253 mach_vm_size_t internal;
1254 mach_vm_size_t internal_peak;
1255 mach_vm_size_t external;
1256 mach_vm_size_t external_peak;
1257 mach_vm_size_t reusable;
1258 mach_vm_size_t reusable_peak;
1259 mach_vm_size_t purgeable_volatile_pmap;
1260 mach_vm_size_t purgeable_volatile_resident;
1261 mach_vm_size_t purgeable_volatile_virtual;
1262 mach_vm_size_t compressed;
1263 mach_vm_size_t compressed_peak;
1264 mach_vm_size_t compressed_lifetime;
1265 mach_vm_size_t phys_footprint;
1266 mach_vm_address_t min_address;
1267 mach_vm_address_t max_address;
1268};
1269#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \
1270 (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t)))
1271
1272static uptr GetTaskInfoMaxAddress() {
1273 __sanitizer_task_vm_info vm_info = {} /* zero initialize */;
1274 mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT;
1275 int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count);
1276 return err ? 0 : vm_info.max_address;
1277}
1278
1279# endif
1280
1281# if SANITIZER_IOSDEVICE || SANITIZER_DRIVERKIT
1282
1283uptr GetMaxUserVirtualAddress() {
1284 static uptr max_vm = GetTaskInfoMaxAddress();
1285 if (max_vm != 0) {
1286 return max_vm - 1;
1287 }
1288
1289 // xnu cannot provide vm address limit
1290# if SANITIZER_WORDSIZE == 32
1291 constexpr uptr fallback_max_vm = 0xffe00000 - 1;
1292# else
1293 constexpr uptr fallback_max_vm = 0x200000000 - 1;
1294# endif
1295 static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,
1296 "Max virtual address must be less than mmap range size.");
1297 return fallback_max_vm;
1298}
1299
1300# else // !(SANITIZER_IOSDEVICE || SANITIZER_DRIVERKIT)
1301
1302uptr GetMaxUserVirtualAddress() {
1303# if SANITIZER_WORDSIZE == 64
1304 constexpr uptr max_vm = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
1305# else // SANITIZER_WORDSIZE == 32
1306 static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");
1307 constexpr uptr max_vm = (1ULL << 32) - 1; // 0xffffffff;
1308# endif
1309 static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,
1310 "Max virtual address must be less than mmap range size.");
1311 return max_vm;
1312}
1313# endif
1314
1315bool ActivateDebugMemory() {
1316# if SANITIZER_EMBEDDED_VM_LAYOUT
1317 // On embedded devices, the debug region should be higher than the range
1318 // normally returned by mmap.
1319 static_assert(DARWIN_DEBUG_MEMORY_START >=
1320 SANITIZER_MMAP_BEGIN + SANITIZER_MMAP_RANGE_SIZE);
1321
1322 uptr cur_max = GetTaskInfoMaxAddress();
1323 // The "old layout" is used when the OS version is less than 27.0 or
1324 // when the max_offset is <= 448G (even in 27.0, not all processes
1325 // must use the new layout)
1326 if (cur_max <= DARWIN_DEBUG_MEMORY_VMOFFSET_FLOOR ||
1327 GetMacosAlignedVersion() < DARWIN_DEBUG_MEMORY_VERSION_FLOOR) {
1328 VReport(2, "Falling back to old layout cur_max=%p\n", (void*)cur_max);
1329 return false;
1330 }
1331
1332 // Now, we prepare to activate the "debug range". This expands the
1333 // max vm offset from ~512G to ~8TB, but doesn't change the space
1334 // available to applications. First, we check that the max vm offset
1335 // is not already expanded...
1336
1337 // Max address above the debug range is unexpected. It could suggest that
1338 // another tool has already activated the debug memory region, but that
1339 // would be unexpected as we are supposed to run early in process launch.
1340 // Since we do not guarantee compatbility with other tools, bail out here.
1341 if (cur_max > DARWIN_DEBUG_MEMORY_START) {
1342 Report(
1343 "FATAL: Unexpected VM layout. max addr = %p, expected <= %p. Is "
1344 "another tool using debug memory?",
1345 (void*)cur_max, DARWIN_DEBUG_MEMORY_START);
1346 Die();
1347 }
1348
1349 VReport(2, "Using debug memory range cur_max=%p\n", (void*)cur_max);
1350 uint32_t enabled = 1;
1351 int ret = sysctlbyname("vm.debug_range_enabled", NULL, NULL, &enabled,
1352 sizeof(enabled));
1353 uptr new_max = GetTaskInfoMaxAddress();
1354
1355 if (ret != 0 || new_max <= DARWIN_DEBUG_MEMORY_START) {
1356 // Not being able to activate debug memory is essentially guaranteed to be
1357 // fatal: for ASAN 512GB of VM requires 64G of contiguous shadow, which
1358 // there just isn't space for without debug range. So we do not attempt to
1359 // support that.
1360 Report(
1361 "FATAL: vm.debug_range_enabled sysctl failed to activate (ret=%d).\n",
1362 ret);
1363 Report(
1364 "HINT: Check that the device is in developer mode and that the "
1365 "sysctl is not denied by sandbox.\n");
1366 Die();
1367 }
1368
1369 // Success: The debug range was successfully enabled.
1370 VReport(2, "vm.debug_range_enabled updated successfully, new max=%p\n",
1371 (void*)new_max);
1372 debug_region_activated = true;
1373 return true;
1374
1375# endif // SANITIZER_EMBEDDED_VM_LAYOUT
1376 return false;
1377}
1378
1379bool GetDebugMemoryRange(mach_vm_range* debug_range) {
1380 size_t sz = sizeof(*debug_range);
1381 int ret =
1382 sysctlbyname("vm.vm_map_user_range_debug", debug_range, &sz, NULL, 0);
1383 return ret == 0 && sz == sizeof(*debug_range);
1384}
1385
1386uptr GetMaxVirtualAddress() {
1387 return GetMaxUserVirtualAddress();
1388}
1389
1390uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
1391 uptr min_shadow_base_alignment, uptr &high_mem_end,
1392 uptr granularity) {
1393 const uptr alignment =
1394 Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
1395 const uptr left_padding =
1396 Max<uptr>(granularity, 1ULL << min_shadow_base_alignment);
1397
1398 uptr space_size = shadow_size_bytes;
1399
1400 uptr largest_gap_found = 0;
1401 uptr max_occupied_addr = 0;
1402
1403 // Note that the below call may expand the address space reported by
1404 // GetTaskInfoMaxAddress. The original max_vm is stored in kHighMemEnd (and
1405 // was used to compute shadow_size_bytes.) and also
1406 // GetMaxUserVirtualAddress/GetMaxVirtualAddress use a static variable and
1407 // thus always return the original max.
1408 bool use_debug_vm = ActivateDebugMemory();
1409
1410 VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);
1411 uptr shadow_start = FindAvailableMemoryRange(
1412 space_size, alignment, left_padding, &largest_gap_found,
1413 &max_occupied_addr, use_debug_vm);
1414 // If the shadow doesn't fit, restrict the address space to make it fit.
1415 if (!use_debug_vm && shadow_start == 0) {
1416 VReport(
1417 2,
1418 "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n",
1419 (void *)largest_gap_found, (void *)max_occupied_addr);
1420 uptr new_max_vm = RoundDownTo(largest_gap_found << shadow_scale, alignment);
1421 if (new_max_vm < max_occupied_addr) {
1422 Report("Unable to find a memory range for dynamic shadow.\n");
1423 Report(
1424 "\tspace_size = %p\n\tlargest_gap_found = %p\n\tmax_occupied_addr "
1425 "= %p\n\tnew_max_vm = %p\n",
1426 (void*)space_size, (void*)largest_gap_found, (void*)max_occupied_addr,
1427 (void*)new_max_vm);
1428 ReportShadowAllocFail(shadow_size_bytes, alignment);
1429 CHECK(0 && "cannot place shadow");
1430 }
1431 RestrictMemoryToMaxAddress(new_max_vm);
1432 high_mem_end = new_max_vm - 1;
1433 space_size = (high_mem_end >> shadow_scale);
1434 VReport(2, "FindDynamicShadowStart, space_size = %p\n", (void *)space_size);
1435 shadow_start = FindAvailableMemoryRange(space_size, alignment, left_padding,
1436 nullptr, nullptr,
1437 /* use_debug_vm */ false);
1438 if (shadow_start == 0) {
1439 Report("Unable to find a memory range after restricting VM.\n");
1440 ReportShadowAllocFail(shadow_size_bytes, alignment);
1441 CHECK(0 && "cannot place shadow after restricting vm");
1442 }
1443 }
1444
1445 CHECK_NE((uptr)0, shadow_start);
1446 CHECK(IsAligned(shadow_start, alignment));
1447 return shadow_start;
1448}
1449
1450// Returns a list of ranges which must be covered by shadow memory,
1451// and cannot overlap with any fixed mappings made by a sanitizer.
1452//
1453// NOTE: Ranges must only be page-aligned.
1454//
1455// This list may be empty on macOS < 27.0, which implies no additional
1456// restriction on the placement of shadow.
1457void GetAppRanges(InternalMmapVector<ReservedRange>& ranges) {
1458 if (GetMacosAlignedVersion() < DARWIN_DEBUG_MEMORY_VERSION_FLOOR)
1459 return;
1460
1461# if SANITIZER_EMBEDDED_VM_LAYOUT
1462 // NOTE: Even in iOS 27.0, some embedded devices and processes may not
1463 // use the new layout.
1464 if (GetTaskInfoMaxAddress() <= DARWIN_DEBUG_MEMORY_VMOFFSET_FLOOR)
1465 return;
1466# endif
1467
1468 ranges.reserve(2);
1469# if SANITIZER_WORDSIZE == 64
1470# if SANITIZER_IOSDEVICE
1471
1472 struct mach_vm_range debug_range;
1473 if (!GetDebugMemoryRange(&debug_range)) {
1474 Report("vm.vm_map_user_range_debug sysctl failed. Denied by sandbox?\n");
1475 Die();
1476 }
1477
1478 // Get app ranges
1479 size_t all_ranges_sz = 0;
1480
1481 // Call 1: Get length
1482 int ret = sysctlbyname("vm.all_map_ranges", NULL, &all_ranges_sz, NULL, 0);
1483 if (ret != 0) {
1484 Report("vm.all_map_ranges sysctl failed. Denied by sandbox?\n");
1485 Die();
1486 }
1487
1488 struct mach_vm_range* all_ranges =
1489 (struct mach_vm_range*)InternalAlloc(all_ranges_sz);
1490 // Call 2: Actually get the ranges
1491 ret = sysctlbyname("vm.all_map_ranges", all_ranges, &all_ranges_sz, NULL, 0);
1492 if (ret != 0) {
1493 Report("vm.all_map_ranges sysctl failed. Denied by sandbox?\n");
1494 Die();
1495 }
1496
1497 bool has_gpu_carveout =
1498 MemoryRangeIsKernelReserved(MACH_VM_MIN_GPU_CARVEOUT_ADDRESS_RAW,
1499 MACH_VM_MAX_GPU_CARVEOUT_ADDRESS_RAW);
1500 for (unsigned i = 0; i < (all_ranges_sz / sizeof(all_ranges[0])); i++) {
1501 struct mach_vm_range range = all_ranges[i];
1502 // Skip the debug range: we don't have to cover it with shadow.
1503 if (range.min_address == debug_range.min_address &&
1504 range.max_address == debug_range.max_address)
1505 continue;
1506 // Skip zero-size ranges
1507 if (range.min_address == range.max_address)
1508 continue;
1509
1510 // Split ranges that contain the carveout
1511 if (has_gpu_carveout) {
1512 // Pre-carveout range, if any
1513 if (range.min_address < MACH_VM_MIN_GPU_CARVEOUT_ADDRESS_RAW)
1514 ranges.push_back(
1515 {range.min_address,
1516 Min(range.max_address, MACH_VM_MIN_GPU_CARVEOUT_ADDRESS_RAW)});
1517
1518 // Post-carveout range, if any
1519 if (range.max_address > MACH_VM_MAX_GPU_CARVEOUT_ADDRESS_RAW)
1520 ranges.push_back(
1521 {Max(range.min_address, MACH_VM_MAX_GPU_CARVEOUT_ADDRESS_RAW),
1522 range.max_address});
1523 } else {
1524 ranges.push_back({range.min_address, range.max_address});
1525 }
1526 }
1527
1528 InternalFree(all_ranges);
1529
1530 // Compute the shared cache range
1531 size_t shared_cache_size;
1532 mach_vm_address_t shared_cache_base =
1533 (mach_vm_address_t)_dyld_get_shared_cache_range(&shared_cache_size);
1534
1535 CHECK(shared_cache_base != 0 && "_dyld_get_shared_cache_range returned NULL");
1536 VReport(2, "Shared cache: [%p, %p]\n", (void*)shared_cache_base,
1537 (void*)(shared_cache_base + shared_cache_size));
1538
1539 // Verify that the shared cache range is within one of the known ranges
1540 bool shared_cache_in_range = false;
1541 for (auto& [range_start, range_end] : ranges) {
1542 shared_cache_in_range |=
1543 (shared_cache_base >= range_start &&
1544 shared_cache_base + shared_cache_size <= range_end);
1545 // Note: GetMaxUserVirtualAddress returns the cached, pre-expansion
1546 // maximum (debug memory increases the max_address reported by task_info)
1547 if (range_end - 1 > GetMaxUserVirtualAddress()) {
1548 Report("FATAL: Unsupported VM layout. Range [%p, %p] is above max %p\n",
1549 range_start, range_end, GetMaxUserVirtualAddress());
1550 Die();
1551 }
1552 }
1553
1554 if (!shared_cache_in_range) {
1555 Report(
1556 "FATAL: Unsupported VM layout. Shared cache [%p, %p] is outside of "
1557 "expected range\n",
1558 shared_cache_base, shared_cache_base + shared_cache_size);
1559 Die();
1560 }
1561# else
1562 // The first 512GB are platform-reserved on macOS.
1563 ranges.push_back({0x1000UL, 0x8000000000UL});
1564# endif
1565# endif
1566
1567 VReport(2, "App ranges:\n");
1568 for (auto& [range_start, range_end] : ranges) {
1569 VReport(2, " [%p, %p]\n", range_start, range_end);
1570 }
1571}
1572
1573uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
1574 uptr num_aliases, uptr ring_buffer_size) {
1575 CHECK(false && "HWASan aliasing is unimplemented on Mac");
1576 return 0;
1577}
1578
1579uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
1580 uptr* largest_gap_found, uptr* max_occupied_addr,
1581 bool use_debug_vm) {
1582 mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;
1583 mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;
1584 mach_vm_address_t free_begin = GAP_SEARCH_START_ADDRESS;
1585
1586 // When using the debug VM range, we restrict our search to start at the
1587 // reported beginning of that range
1588 if (use_debug_vm) {
1589 struct mach_vm_range debug_range;
1590 if (!GetDebugMemoryRange(&debug_range)) {
1591 Report("vm_map_user_range_debug sysctl failed. Denied by sandbox?\n");
1592 Die();
1593 }
1594
1595 // When use_debug_vm is true, we want to search up to the end of the debug
1596 // range.
1597 max_vm_address = debug_range.max_address;
1598
1599 VReport(2, "FindAvailableMemoryRange: Debug range is [%p, %p], max_vm=%p\n",
1600 debug_range.min_address, debug_range.max_address,
1601 GetTaskInfoMaxAddress());
1602
1603 // Begin our search at the beginning of the debug range.
1604 address = debug_range.min_address;
1605 free_begin = debug_range.min_address;
1606 }
1607
1608 // Restrict the search to be after any reserved ranges
1609 InternalMmapVector<ReservedRange> app_ranges;
1610 GetAppRanges(app_ranges);
1611
1612 for (auto& [range_start, range_end] : app_ranges) {
1613 address = Max(address, (mach_vm_address_t)range_end);
1614 free_begin = Max(free_begin, (mach_vm_address_t)range_end);
1615 }
1616
1617 kern_return_t kr = KERN_SUCCESS;
1618 if (largest_gap_found) *largest_gap_found = 0;
1619 if (max_occupied_addr) *max_occupied_addr = 0;
1620 while (kr == KERN_SUCCESS) {
1621 mach_vm_size_t vmsize = 0;
1622 natural_t depth = 0;
1623 vm_region_submap_short_info_data_64_t vminfo;
1624 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
1625 kr = internal_mach_vm_region_recurse(mach_task_self(), &address, &vmsize,
1626 &depth, (vm_region_info_t)&vminfo,
1627 &count);
1628
1629 if (kr == KERN_SUCCESS) {
1630 // There are cases where going beyond the processes' max vm does
1631 // not return KERN_INVALID_ADDRESS so we check for going beyond that
1632 // max address as well.
1633 if (address > max_vm_address) {
1634 address = max_vm_address;
1635 kr = -1; // break after this iteration.
1636 } else if (max_occupied_addr) {
1637 *max_occupied_addr = address + vmsize;
1638 }
1639 } else if (kr == KERN_INVALID_ADDRESS) {
1640 // No more regions beyond "address", consider the gap at the end of VM.
1641 address = max_vm_address;
1642
1643 // We will break after this iteration anyway since kr != KERN_SUCCESS
1644 } else {
1645 Report(
1646 "WARNING: mach_vm_region_recurse returned unexpected code %d (%s)\n",
1647 kr, mach_error_string(kr));
1648 DCHECK(false && "mach_vm_region_recurse returned unexpected code");
1649 break; // address is not valid unless KERN_SUCCESS, therefore we must not
1650 // use it.
1651 }
1652
1653 if (free_begin != address) {
1654 // We found a free region [free_begin..address-1].
1655 uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment);
1656 uptr gap_end = RoundDownTo((uptr)Min(address, max_vm_address), alignment);
1657 uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0;
1658 if (size < gap_size) {
1659 return gap_start;
1660 }
1661
1662 if (largest_gap_found && *largest_gap_found < gap_size) {
1663 *largest_gap_found = gap_size;
1664 }
1665 }
1666 // Move to the next region.
1667 address += vmsize;
1668 free_begin = address;
1669 }
1670
1671 // We looked at all free regions and could not find one large enough.
1672 return 0;
1673}
1674
1675// This function (when used during initialization when there is
1676// only a single thread), can be used to verify that a range
1677// of memory hasn't already been mapped, and won't be mapped
1678// later in the shared cache.
1679//
1680// If the syscall mach_vm_region_recurse fails (due to sandbox),
1681// we assume that the memory is not mapped so that execution can continue.
1682//
1683// NOTE: range_end is inclusive
1684//
1685// WARNING: This function must NOT allocate memory, since it is
1686// used in InitializeShadowMemory between where we search for
1687// space for shadow and where we actually allocate it.
1688bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
1689 mach_vm_size_t vmsize = 0;
1690 natural_t depth = 0;
1691 vm_region_submap_short_info_data_64_t vminfo;
1692 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
1693 mach_vm_address_t address = range_start;
1694
1695 // First, check if the range is already mapped.
1696 kern_return_t kr = internal_mach_vm_region_recurse(
1697 mach_task_self(), &address, &vmsize, &depth, (vm_region_info_t)&vminfo,
1698 &count);
1699
1700 if (kr == KERN_SUCCESS && !IntervalsAreSeparate(address, address + vmsize - 1,
1701 range_start, range_end)) {
1702 // Overlaps with already-mapped memory
1703 return false;
1704 }
1705
1706 size_t cacheLength;
1707 uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
1708
1709 if (cacheStart &&
1710 !IntervalsAreSeparate(cacheStart, cacheStart + cacheLength - 1,
1711 range_start, range_end)) {
1712 // Overlaps with shared cache region
1713 return false;
1714 }
1715
1716 // We believe this address is available.
1717 return true;
1718}
1719
1720// Returns true if this range (range_end is exclusive) corresponds exactly
1721// to a kernel-reserved region such as the GPU carveout.
1722bool MemoryRangeIsKernelReserved(uptr range_start, uptr range_end) {
1723 mach_vm_size_t vmsize = 0;
1724 natural_t depth = 0;
1725 vm_region_submap_short_info_data_64_t vminfo;
1726 mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
1727 mach_vm_address_t address = range_start;
1728
1729 // Kernel-reserved ranges (e.g. the GPU carve-out) have max_protection == 0,
1730 // i.e. they are permanently PROT_NONE
1731 kern_return_t kr = internal_mach_vm_region_recurse(
1732 mach_task_self(), &address, &vmsize, &depth, (vm_region_info_t)&vminfo,
1733 &count);
1734
1735 return (kr == KERN_SUCCESS && address == range_start &&
1736 address + vmsize == range_end && vminfo.max_protection == 0);
1737}
1738
1739// FIXME implement on this platform.
1740void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
1741
1742void SignalContext::DumpAllRegisters(void *context) {
1743 Report("Register values:\n");
1744
1745 ucontext_t *ucontext = (ucontext_t*)context;
1746# define DUMPREG64(r) \
1747 Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r);
1748# define DUMPREGA64(r) \
1749 Printf(" %s = 0x%016lx ", #r, AARCH64_GET_REG(r));
1750# define DUMPREG32(r) \
1751 Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r);
1752# define DUMPREG_(r) Printf(" "); DUMPREG(r);
1753# define DUMPREG__(r) Printf(" "); DUMPREG(r);
1754# define DUMPREG___(r) Printf(" "); DUMPREG(r);
1755
1756# if defined(__x86_64__)
1757# define DUMPREG(r) DUMPREG64(r)
1758 DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n");
1759 DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n");
1760 DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n");
1761 DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n");
1762# elif defined(__i386__)
1763# define DUMPREG(r) DUMPREG32(r)
1764 DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n");
1765 DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n");
1766# elif defined(__aarch64__)
1767# define DUMPREG(r) DUMPREG64(r)
1768 DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n");
1769 DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n");
1770 DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n");
1771 DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n");
1772 DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");
1773 DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");
1774 DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");
1775 DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n");
1776# elif defined(__arm__)
1777# define DUMPREG(r) DUMPREG32(r)
1778 DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");
1779 DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n");
1780 DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n");
1781 DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n");
1782# else
1783# error "Unknown architecture"
1784# endif
1785
1786# undef DUMPREG64
1787# undef DUMPREG32
1788# undef DUMPREG_
1789# undef DUMPREG__
1790# undef DUMPREG___
1791# undef DUMPREG
1792}
1793
1794static inline bool CompareBaseAddress(const LoadedModule &a,
1795 const LoadedModule &b) {
1796 return a.base_address() < b.base_address();
1797}
1798
1799void FormatUUID(char *out, uptr size, const u8 *uuid) {
1800 internal_snprintf(out, size,
1801 "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-"
1802 "%02X%02X%02X%02X%02X%02X>",
1803 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
1804 uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
1805 uuid[12], uuid[13], uuid[14], uuid[15]);
1806}
1807
1808void DumpProcessMap() {
1809 Printf("Process module map:\n");
1810 MemoryMappingLayout memory_mapping(false);
1811 InternalMmapVector<LoadedModule> modules;
1812 modules.reserve(128);
1813 memory_mapping.DumpListOfModules(&modules);
1814 Sort(modules.data(), modules.size(), CompareBaseAddress);
1815 for (uptr i = 0; i < modules.size(); ++i) {
1816 char uuid_str[128];
1817 FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid());
1818 Printf("%p-%p %s (%s) %s\n", (void *)modules[i].base_address(),
1819 (void *)modules[i].max_address(), modules[i].full_name(),
1820 ModuleArchToString(modules[i].arch()), uuid_str);
1821 }
1822 Printf("End of module map.\n");
1823}
1824
1825void OnDlOpen(const char* filename, int flag) {
1826 // Do nothing.
1827}
1828
1829bool GetRandom(void *buffer, uptr length, bool blocking) {
1830 if (!buffer || !length || length > 256)
1831 return false;
1832 // arc4random never fails.
1833 REAL(arc4random_buf)(buffer, length);
1834 return true;
1835}
1836
1837u32 GetNumberOfCPUs() {
1838 return (u32)sysconf(_SC_NPROCESSORS_ONLN);
1839}
1840
1841void InitializePlatformCommonFlags(CommonFlags *cf) {}
1842
1843// Pthread introspection hook
1844//
1845// * GCD worker threads are created without a call to pthread_create(), but we
1846// still need to register these threads (with ThreadCreate/Start()).
1847// * We use the "pthread introspection hook" below to observe the creation of
1848// such threads.
1849// * GCD worker threads don't have parent threads and the CREATE event is
1850// delivered in the context of the thread itself. CREATE events for regular
1851// threads, are delivered on the parent. We use this to tell apart which
1852// threads are GCD workers with `thread == pthread_self()`.
1853//
1854static pthread_introspection_hook_t prev_pthread_introspection_hook;
1855static ThreadEventCallbacks thread_event_callbacks;
1856
1857static void sanitizer_pthread_introspection_hook(unsigned int event,
1858 pthread_t thread, void *addr,
1859 size_t size) {
1860 // create -> start -> terminate -> destroy
1861 // * create/destroy are usually (not guaranteed) delivered on the parent and
1862 // track resource allocation/reclamation
1863 // * start/terminate are guaranteed to be delivered in the context of the
1864 // thread and give hooks into "just after (before) thread starts (stops)
1865 // executing"
1866 DCHECK(event >= PTHREAD_INTROSPECTION_THREAD_CREATE &&
1867 event <= PTHREAD_INTROSPECTION_THREAD_DESTROY);
1868
1869 if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) {
1870 bool gcd_worker = (thread == pthread_self());
1871 if (thread_event_callbacks.create)
1872 thread_event_callbacks.create((uptr)thread, gcd_worker);
1873 } else if (event == PTHREAD_INTROSPECTION_THREAD_START) {
1874 CHECK_EQ(thread, pthread_self());
1875 if (thread_event_callbacks.start)
1876 thread_event_callbacks.start((uptr)thread);
1877 }
1878
1879 if (prev_pthread_introspection_hook)
1880 prev_pthread_introspection_hook(event, thread, addr, size);
1881
1882 if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
1883 CHECK_EQ(thread, pthread_self());
1884 if (thread_event_callbacks.terminate)
1885 thread_event_callbacks.terminate((uptr)thread);
1886 } else if (event == PTHREAD_INTROSPECTION_THREAD_DESTROY) {
1887 if (thread_event_callbacks.destroy)
1888 thread_event_callbacks.destroy((uptr)thread);
1889 }
1890}
1891
1892void InstallPthreadIntrospectionHook(const ThreadEventCallbacks &callbacks) {
1893 thread_event_callbacks = callbacks;
1894 prev_pthread_introspection_hook =
1895 pthread_introspection_hook_install(&sanitizer_pthread_introspection_hook);
1896}
1897
1898} // namespace __sanitizer
1899
1900#endif // SANITIZER_APPLE
1901