]>
Commit | Line | Data |
---|---|---|
549e2197 | 1 | //===-- sanitizer_mac.cc --------------------------------------------------===// |
2 | // | |
3 | // This file is distributed under the University of Illinois Open Source | |
4 | // License. See LICENSE.TXT for details. | |
5 | // | |
6 | //===----------------------------------------------------------------------===// | |
7 | // | |
7d752f28 | 8 | // This file is shared between various sanitizers' runtime libraries and |
9 | // implements OSX-specific functions. | |
549e2197 | 10 | //===----------------------------------------------------------------------===// |
11 | ||
1e80ce41 | 12 | #include "sanitizer_platform.h" |
13 | #if SANITIZER_MAC | |
23e39437 | 14 | #include "sanitizer_mac.h" |
1e80ce41 | 15 | |
7da89e80 | 16 | // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so |
17 | // the clients will most certainly use 64-bit ones as well. | |
18 | #ifndef _DARWIN_USE_64_BIT_INODE | |
19 | #define _DARWIN_USE_64_BIT_INODE 1 | |
20 | #endif | |
21 | #include <stdio.h> | |
549e2197 | 22 | |
23 | #include "sanitizer_common.h" | |
36093749 | 24 | #include "sanitizer_file.h" |
7d752f28 | 25 | #include "sanitizer_flags.h" |
549e2197 | 26 | #include "sanitizer_internal_defs.h" |
27 | #include "sanitizer_libc.h" | |
1e80ce41 | 28 | #include "sanitizer_placement_new.h" |
5645a48f | 29 | #include "sanitizer_platform_limits_posix.h" |
549e2197 | 30 | #include "sanitizer_procmaps.h" |
31 | ||
5645a48f | 32 | #if !SANITIZER_IOS |
549e2197 | 33 | #include <crt_externs.h> // for _NSGetEnviron |
5645a48f | 34 | #else |
35 | extern char **environ; | |
36 | #endif | |
37 | ||
87ccb23e | 38 | #if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__) |
23e39437 | 39 | #define SANITIZER_OS_TRACE 1 |
40 | #include <os/trace.h> | |
41 | #else | |
42 | #define SANITIZER_OS_TRACE 0 | |
43 | #endif | |
44 | ||
45 | #if !SANITIZER_IOS | |
46 | #include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron | |
47 | #else | |
48 | extern "C" { | |
49 | extern char ***_NSGetArgv(void); | |
50 | } | |
51 | #endif | |
52 | ||
53 | #include <asl.h> | |
54 | #include <dlfcn.h> // for dladdr() | |
5645a48f | 55 | #include <errno.h> |
549e2197 | 56 | #include <fcntl.h> |
5645a48f | 57 | #include <libkern/OSAtomic.h> |
58 | #include <mach-o/dyld.h> | |
59 | #include <mach/mach.h> | |
d2ef4bee | 60 | #include <mach/mach_time.h> |
61b44d84 | 61 | #include <mach/vm_statistics.h> |
d2ef4bee | 62 | #include <malloc/malloc.h> |
549e2197 | 63 | #include <pthread.h> |
64 | #include <sched.h> | |
7d752f28 | 65 | #include <signal.h> |
5645a48f | 66 | #include <stdlib.h> |
549e2197 | 67 | #include <sys/mman.h> |
68 | #include <sys/resource.h> | |
69 | #include <sys/stat.h> | |
7d752f28 | 70 | #include <sys/sysctl.h> |
549e2197 | 71 | #include <sys/types.h> |
23e39437 | 72 | #include <sys/wait.h> |
549e2197 | 73 | #include <unistd.h> |
23e39437 | 74 | #include <util.h> |
75 | ||
76 | // From <crt_externs.h>, but we don't have that file on iOS. | |
77 | extern "C" { | |
78 | extern char ***_NSGetArgv(void); | |
79 | extern char ***_NSGetEnviron(void); | |
80 | } | |
81 | ||
82 | // From <mach/mach_vm.h>, but we don't have that file on iOS. | |
83 | extern "C" { | |
84 | extern kern_return_t mach_vm_region_recurse( | |
85 | vm_map_t target_task, | |
86 | mach_vm_address_t *address, | |
87 | mach_vm_size_t *size, | |
88 | natural_t *nesting_depth, | |
89 | vm_region_recurse_info_t info, | |
90 | mach_msg_type_number_t *infoCnt); | |
91 | } | |
549e2197 | 92 | |
93 | namespace __sanitizer { | |
94 | ||
1e80ce41 | 95 | #include "sanitizer_syscall_generic.inc" |
96 | ||
d2c32615 | 97 | // Direct syscalls, don't call libmalloc hooks (but not available on 10.6). |
23e39437 | 98 | extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes, |
d2c32615 | 99 | off_t off) SANITIZER_WEAK_ATTRIBUTE; |
100 | extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE; | |
23e39437 | 101 | |
549e2197 | 102 | // ---------------------- sanitizer_libc.h |
d2ef4bee | 103 | |
104 | // From <mach/vm_statistics.h>, but not on older OSs. | |
105 | #ifndef VM_MEMORY_SANITIZER | |
106 | #define VM_MEMORY_SANITIZER 99 | |
107 | #endif | |
108 | ||
1e80ce41 | 109 | uptr internal_mmap(void *addr, size_t length, int prot, int flags, |
110 | int fd, u64 offset) { | |
d2ef4bee | 111 | if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER); |
36093749 | 112 | if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); |
d2c32615 | 113 | return (uptr)mmap(addr, length, prot, flags, fd, offset); |
549e2197 | 114 | } |
115 | ||
1e80ce41 | 116 | uptr internal_munmap(void *addr, uptr length) { |
36093749 | 117 | if (&__munmap) return __munmap(addr, length); |
d2c32615 | 118 | return munmap(addr, length); |
549e2197 | 119 | } |
120 | ||
5645a48f | 121 | int internal_mprotect(void *addr, uptr length, int prot) { |
122 | return mprotect(addr, length, prot); | |
123 | } | |
124 | ||
1e80ce41 | 125 | uptr internal_close(fd_t fd) { |
549e2197 | 126 | return close(fd); |
127 | } | |
128 | ||
1e80ce41 | 129 | uptr internal_open(const char *filename, int flags) { |
7da89e80 | 130 | return open(filename, flags); |
131 | } | |
132 | ||
1e80ce41 | 133 | uptr internal_open(const char *filename, int flags, u32 mode) { |
7da89e80 | 134 | return open(filename, flags, mode); |
135 | } | |
136 | ||
549e2197 | 137 | uptr internal_read(fd_t fd, void *buf, uptr count) { |
138 | return read(fd, buf, count); | |
139 | } | |
140 | ||
141 | uptr internal_write(fd_t fd, const void *buf, uptr count) { | |
142 | return write(fd, buf, count); | |
143 | } | |
144 | ||
1e80ce41 | 145 | uptr internal_stat(const char *path, void *buf) { |
7da89e80 | 146 | return stat(path, (struct stat *)buf); |
147 | } | |
148 | ||
1e80ce41 | 149 | uptr internal_lstat(const char *path, void *buf) { |
7da89e80 | 150 | return lstat(path, (struct stat *)buf); |
151 | } | |
152 | ||
1e80ce41 | 153 | uptr internal_fstat(fd_t fd, void *buf) { |
7da89e80 | 154 | return fstat(fd, (struct stat *)buf); |
155 | } | |
156 | ||
549e2197 | 157 | uptr internal_filesize(fd_t fd) { |
158 | struct stat st; | |
7da89e80 | 159 | if (internal_fstat(fd, &st)) |
549e2197 | 160 | return -1; |
161 | return (uptr)st.st_size; | |
162 | } | |
163 | ||
1e80ce41 | 164 | uptr internal_dup2(int oldfd, int newfd) { |
549e2197 | 165 | return dup2(oldfd, newfd); |
166 | } | |
167 | ||
168 | uptr internal_readlink(const char *path, char *buf, uptr bufsize) { | |
169 | return readlink(path, buf, bufsize); | |
170 | } | |
171 | ||
5645a48f | 172 | uptr internal_unlink(const char *path) { |
173 | return unlink(path); | |
174 | } | |
175 | ||
1e80ce41 | 176 | uptr internal_sched_yield() { |
549e2197 | 177 | return sched_yield(); |
178 | } | |
179 | ||
5a59af67 | 180 | void internal__exit(int exitcode) { |
181 | _exit(exitcode); | |
182 | } | |
183 | ||
23e39437 | 184 | unsigned int internal_sleep(unsigned int seconds) { |
185 | return sleep(seconds); | |
186 | } | |
187 | ||
1e80ce41 | 188 | uptr internal_getpid() { |
189 | return getpid(); | |
190 | } | |
191 | ||
7d752f28 | 192 | int internal_sigaction(int signum, const void *act, void *oldact) { |
193 | return sigaction(signum, | |
d2ef4bee | 194 | (const struct sigaction *)act, (struct sigaction *)oldact); |
7d752f28 | 195 | } |
196 | ||
5645a48f | 197 | void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } |
198 | ||
199 | uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, | |
200 | __sanitizer_sigset_t *oldset) { | |
36093749 | 201 | // Don't use sigprocmask here, because it affects all threads. |
202 | return pthread_sigmask(how, set, oldset); | |
5645a48f | 203 | } |
204 | ||
d2c32615 | 205 | // Doesn't call pthread_atfork() handlers (but not available on 10.6). |
206 | extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE; | |
23e39437 | 207 | |
7d752f28 | 208 | int internal_fork() { |
36093749 | 209 | if (&__fork) |
d2c32615 | 210 | return __fork(); |
211 | return fork(); | |
23e39437 | 212 | } |
213 | ||
d2ef4bee | 214 | int internal_sysctl(const int *name, unsigned int namelen, void *oldp, |
215 | uptr *oldlenp, const void *newp, uptr newlen) { | |
216 | return sysctl(const_cast<int *>(name), namelen, oldp, (size_t *)oldlenp, | |
217 | const_cast<void *>(newp), (size_t)newlen); | |
218 | } | |
219 | ||
220 | int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, | |
221 | const void *newp, uptr newlen) { | |
222 | return sysctlbyname(sname, oldp, (size_t *)oldlenp, const_cast<void *>(newp), | |
223 | (size_t)newlen); | |
224 | } | |
225 | ||
23e39437 | 226 | int internal_forkpty(int *amaster) { |
227 | int master, slave; | |
228 | if (openpty(&master, &slave, nullptr, nullptr, nullptr) == -1) return -1; | |
d2c32615 | 229 | int pid = internal_fork(); |
23e39437 | 230 | if (pid == -1) { |
231 | close(master); | |
232 | close(slave); | |
233 | return -1; | |
234 | } | |
235 | if (pid == 0) { | |
236 | close(master); | |
237 | if (login_tty(slave) != 0) { | |
238 | // We already forked, there's not much we can do. Let's quit. | |
239 | Report("login_tty failed (errno %d)\n", errno); | |
240 | internal__exit(1); | |
241 | } | |
242 | } else { | |
243 | *amaster = master; | |
244 | close(slave); | |
245 | } | |
246 | return pid; | |
7d752f28 | 247 | } |
248 | ||
a9586c9c | 249 | uptr internal_rename(const char *oldpath, const char *newpath) { |
250 | return rename(oldpath, newpath); | |
251 | } | |
252 | ||
253 | uptr internal_ftruncate(fd_t fd, uptr size) { | |
254 | return ftruncate(fd, size); | |
255 | } | |
256 | ||
23e39437 | 257 | uptr internal_execve(const char *filename, char *const argv[], |
258 | char *const envp[]) { | |
259 | return execve(filename, argv, envp); | |
260 | } | |
261 | ||
262 | uptr internal_waitpid(int pid, int *status, int options) { | |
263 | return waitpid(pid, status, options); | |
264 | } | |
265 | ||
549e2197 | 266 | // ----------------- sanitizer_common.h |
0d996a11 | 267 | bool FileExists(const char *filename) { |
268 | struct stat st; | |
269 | if (stat(filename, &st)) | |
270 | return false; | |
271 | // Sanity check: filename is a regular file. | |
272 | return S_ISREG(st.st_mode); | |
273 | } | |
274 | ||
36093749 | 275 | tid_t GetTid() { |
276 | tid_t tid; | |
23e39437 | 277 | pthread_threadid_np(nullptr, &tid); |
278 | return tid; | |
549e2197 | 279 | } |
280 | ||
281 | void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, | |
282 | uptr *stack_bottom) { | |
283 | CHECK(stack_top); | |
284 | CHECK(stack_bottom); | |
285 | uptr stacksize = pthread_get_stacksize_np(pthread_self()); | |
7d752f28 | 286 | // pthread_get_stacksize_np() returns an incorrect stack size for the main |
287 | // thread on Mavericks. See | |
23e39437 | 288 | // https://github.com/google/sanitizers/issues/261 |
0328398d | 289 | if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && |
7d752f28 | 290 | stacksize == (1 << 19)) { |
291 | struct rlimit rl; | |
292 | CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); | |
293 | // Most often rl.rlim_cur will be the desired 8M. | |
294 | if (rl.rlim_cur < kMaxThreadStackSize) { | |
295 | stacksize = rl.rlim_cur; | |
296 | } else { | |
297 | stacksize = kMaxThreadStackSize; | |
298 | } | |
299 | } | |
549e2197 | 300 | void *stackaddr = pthread_get_stackaddr_np(pthread_self()); |
301 | *stack_top = (uptr)stackaddr; | |
302 | *stack_bottom = *stack_top - stacksize; | |
303 | } | |
304 | ||
5645a48f | 305 | char **GetEnviron() { |
306 | #if !SANITIZER_IOS | |
549e2197 | 307 | char ***env_ptr = _NSGetEnviron(); |
4fc7b5ac | 308 | if (!env_ptr) { |
309 | Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " | |
310 | "called after libSystem_initializer().\n"); | |
311 | CHECK(env_ptr); | |
312 | } | |
549e2197 | 313 | char **environ = *env_ptr; |
5645a48f | 314 | #endif |
549e2197 | 315 | CHECK(environ); |
5645a48f | 316 | return environ; |
317 | } | |
318 | ||
319 | const char *GetEnv(const char *name) { | |
320 | char **env = GetEnviron(); | |
549e2197 | 321 | uptr name_len = internal_strlen(name); |
5645a48f | 322 | while (*env != 0) { |
323 | uptr len = internal_strlen(*env); | |
549e2197 | 324 | if (len > name_len) { |
5645a48f | 325 | const char *p = *env; |
549e2197 | 326 | if (!internal_memcmp(p, name, name_len) && |
327 | p[name_len] == '=') { // Match. | |
5645a48f | 328 | return *env + name_len + 1; // String starting after =. |
549e2197 | 329 | } |
330 | } | |
5645a48f | 331 | env++; |
549e2197 | 332 | } |
333 | return 0; | |
334 | } | |
335 | ||
5645a48f | 336 | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { |
337 | CHECK_LE(kMaxPathLength, buf_len); | |
338 | ||
339 | // On OS X the executable path is saved to the stack by dyld. Reading it | |
340 | // from there is much faster than calling dladdr, especially for large | |
341 | // binaries with symbols. | |
342 | InternalScopedString exe_path(kMaxPathLength); | |
343 | uint32_t size = exe_path.size(); | |
344 | if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && | |
345 | realpath(exe_path.data(), buf) != 0) { | |
346 | return internal_strlen(buf); | |
347 | } | |
348 | return 0; | |
549e2197 | 349 | } |
350 | ||
5645a48f | 351 | uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { |
352 | return ReadBinaryName(buf, buf_len); | |
f5ed5428 | 353 | } |
354 | ||
5645a48f | 355 | void ReExec() { |
356 | UNIMPLEMENTED(); | |
1e80ce41 | 357 | } |
358 | ||
d2ef4bee | 359 | void CheckASLR() { |
360 | // Do nothing | |
361 | } | |
362 | ||
5645a48f | 363 | uptr GetPageSize() { |
364 | return sysconf(_SC_PAGESIZE); | |
4a2c1ffc | 365 | } |
366 | ||
d2ef4bee | 367 | extern "C" unsigned malloc_num_zones; |
368 | extern "C" malloc_zone_t **malloc_zones; | |
369 | malloc_zone_t sanitizer_zone; | |
370 | ||
371 | // We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If | |
372 | // libmalloc tries to set up a different zone as malloc_zones[0], it will call | |
373 | // mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and | |
374 | // make sure we are still the first (default) zone. | |
375 | void MprotectMallocZones(void *addr, int prot) { | |
376 | if (addr == malloc_zones && prot == PROT_READ) { | |
377 | if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) { | |
378 | for (unsigned i = 1; i < malloc_num_zones; i++) { | |
379 | if (malloc_zones[i] == &sanitizer_zone) { | |
380 | // Swap malloc_zones[0] and malloc_zones[i]. | |
381 | malloc_zones[i] = malloc_zones[0]; | |
382 | malloc_zones[0] = &sanitizer_zone; | |
383 | break; | |
384 | } | |
385 | } | |
386 | } | |
387 | } | |
388 | } | |
389 | ||
1e80ce41 | 390 | BlockingMutex::BlockingMutex() { |
391 | internal_memset(this, 0, sizeof(*this)); | |
392 | } | |
393 | ||
4a2c1ffc | 394 | void BlockingMutex::Lock() { |
395 | CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); | |
1e80ce41 | 396 | CHECK_EQ(OS_SPINLOCK_INIT, 0); |
36093749 | 397 | CHECK_EQ(owner_, 0); |
4a2c1ffc | 398 | OSSpinLockLock((OSSpinLock*)&opaque_storage_); |
4a2c1ffc | 399 | } |
400 | ||
401 | void BlockingMutex::Unlock() { | |
4a2c1ffc | 402 | OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); |
403 | } | |
404 | ||
1e80ce41 | 405 | void BlockingMutex::CheckLocked() { |
36093749 | 406 | CHECK_NE(*(OSSpinLock*)&opaque_storage_, 0); |
1e80ce41 | 407 | } |
408 | ||
409 | u64 NanoTime() { | |
d2ef4bee | 410 | timeval tv; |
411 | internal_memset(&tv, 0, sizeof(tv)); | |
412 | gettimeofday(&tv, 0); | |
413 | return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; | |
414 | } | |
415 | ||
416 | // This needs to be called during initialization to avoid being racy. | |
417 | u64 MonotonicNanoTime() { | |
418 | static mach_timebase_info_data_t timebase_info; | |
419 | if (timebase_info.denom == 0) mach_timebase_info(&timebase_info); | |
420 | return (mach_absolute_time() * timebase_info.numer) / timebase_info.denom; | |
1e80ce41 | 421 | } |
422 | ||
423 | uptr GetTlsSize() { | |
424 | return 0; | |
425 | } | |
426 | ||
427 | void InitTlsSize() { | |
428 | } | |
429 | ||
36093749 | 430 | uptr TlsBaseAddr() { |
431 | uptr segbase = 0; | |
432 | #if defined(__x86_64__) | |
433 | asm("movq %%gs:0,%0" : "=r"(segbase)); | |
434 | #elif defined(__i386__) | |
435 | asm("movl %%gs:0,%0" : "=r"(segbase)); | |
436 | #endif | |
437 | return segbase; | |
438 | } | |
439 | ||
440 | // The size of the tls on darwin does not appear to be well documented, | |
441 | // however the vm memory map suggests that it is 1024 uptrs in size, | |
442 | // with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386. | |
443 | uptr TlsSize() { | |
444 | #if defined(__x86_64__) || defined(__i386__) | |
445 | return 1024 * sizeof(uptr); | |
446 | #else | |
447 | return 0; | |
448 | #endif | |
449 | } | |
450 | ||
1e80ce41 | 451 | void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, |
452 | uptr *tls_addr, uptr *tls_size) { | |
23e39437 | 453 | #if !SANITIZER_GO |
1e80ce41 | 454 | uptr stack_top, stack_bottom; |
455 | GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); | |
456 | *stk_addr = stack_bottom; | |
457 | *stk_size = stack_top - stack_bottom; | |
36093749 | 458 | *tls_addr = TlsBaseAddr(); |
459 | *tls_size = TlsSize(); | |
1e80ce41 | 460 | #else |
461 | *stk_addr = 0; | |
462 | *stk_size = 0; | |
463 | *tls_addr = 0; | |
464 | *tls_size = 0; | |
465 | #endif | |
466 | } | |
467 | ||
23e39437 | 468 | void ListOfModules::init() { |
36093749 | 469 | clearOrInit(); |
1e80ce41 | 470 | MemoryMappingLayout memory_mapping(false); |
23e39437 | 471 | memory_mapping.DumpListOfModules(&modules_); |
7d752f28 | 472 | } |
473 | ||
36093749 | 474 | void ListOfModules::fallbackInit() { clear(); } |
475 | ||
476 | static HandleSignalMode GetHandleSignalModeImpl(int signum) { | |
477 | switch (signum) { | |
478 | case SIGABRT: | |
479 | return common_flags()->handle_abort; | |
480 | case SIGILL: | |
481 | return common_flags()->handle_sigill; | |
d2ef4bee | 482 | case SIGTRAP: |
483 | return common_flags()->handle_sigtrap; | |
36093749 | 484 | case SIGFPE: |
485 | return common_flags()->handle_sigfpe; | |
486 | case SIGSEGV: | |
487 | return common_flags()->handle_segv; | |
488 | case SIGBUS: | |
489 | return common_flags()->handle_sigbus; | |
490 | } | |
491 | return kHandleSignalNo; | |
492 | } | |
493 | ||
494 | HandleSignalMode GetHandleSignalMode(int signum) { | |
495 | // Handling fatal signals on watchOS and tvOS devices is disallowed. | |
23e39437 | 496 | if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) |
36093749 | 497 | return kHandleSignalNo; |
498 | HandleSignalMode result = GetHandleSignalModeImpl(signum); | |
499 | if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler) | |
500 | return kHandleSignalExclusive; | |
501 | return result; | |
7d752f28 | 502 | } |
503 | ||
504 | MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; | |
505 | ||
506 | MacosVersion GetMacosVersionInternal() { | |
507 | int mib[2] = { CTL_KERN, KERN_OSRELEASE }; | |
508 | char version[100]; | |
509 | uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); | |
510 | for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; | |
511 | // Get the version length. | |
d2ef4bee | 512 | CHECK_NE(internal_sysctl(mib, 2, 0, &len, 0, 0), -1); |
7d752f28 | 513 | CHECK_LT(len, maxlen); |
d2ef4bee | 514 | CHECK_NE(internal_sysctl(mib, 2, version, &len, 0, 0), -1); |
7d752f28 | 515 | switch (version[0]) { |
516 | case '9': return MACOS_VERSION_LEOPARD; | |
517 | case '1': { | |
518 | switch (version[1]) { | |
519 | case '0': return MACOS_VERSION_SNOW_LEOPARD; | |
520 | case '1': return MACOS_VERSION_LION; | |
521 | case '2': return MACOS_VERSION_MOUNTAIN_LION; | |
522 | case '3': return MACOS_VERSION_MAVERICKS; | |
0328398d | 523 | case '4': return MACOS_VERSION_YOSEMITE; |
d2ef4bee | 524 | case '5': return MACOS_VERSION_EL_CAPITAN; |
525 | case '6': return MACOS_VERSION_SIERRA; | |
526 | case '7': return MACOS_VERSION_HIGH_SIERRA; | |
527 | case '8': return MACOS_VERSION_MOJAVE; | |
5645a48f | 528 | default: |
529 | if (IsDigit(version[1])) | |
530 | return MACOS_VERSION_UNKNOWN_NEWER; | |
531 | else | |
532 | return MACOS_VERSION_UNKNOWN; | |
7d752f28 | 533 | } |
1e80ce41 | 534 | } |
7d752f28 | 535 | default: return MACOS_VERSION_UNKNOWN; |
536 | } | |
537 | } | |
538 | ||
539 | MacosVersion GetMacosVersion() { | |
540 | atomic_uint32_t *cache = | |
541 | reinterpret_cast<atomic_uint32_t*>(&cached_macos_version); | |
542 | MacosVersion result = | |
543 | static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire)); | |
544 | if (result == MACOS_VERSION_UNINITIALIZED) { | |
545 | result = GetMacosVersionInternal(); | |
546 | atomic_store(cache, result, memory_order_release); | |
1e80ce41 | 547 | } |
7d752f28 | 548 | return result; |
1e80ce41 | 549 | } |
550 | ||
36093749 | 551 | bool PlatformHasDifferentMemcpyAndMemmove() { |
552 | // On OS X 10.7 memcpy() and memmove() are both resolved | |
553 | // into memmove$VARIANT$sse42. | |
554 | // See also https://github.com/google/sanitizers/issues/34. | |
555 | // TODO(glider): need to check dynamically that memcpy() and memmove() are | |
556 | // actually the same function. | |
557 | return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; | |
558 | } | |
559 | ||
5645a48f | 560 | uptr GetRSS() { |
561 | struct task_basic_info info; | |
562 | unsigned count = TASK_BASIC_INFO_COUNT; | |
563 | kern_return_t result = | |
564 | task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); | |
565 | if (UNLIKELY(result != KERN_SUCCESS)) { | |
566 | Report("Cannot get task info. Error: %d\n", result); | |
567 | Die(); | |
568 | } | |
569 | return info.resident_size; | |
570 | } | |
571 | ||
61b44d84 | 572 | void *internal_start_thread(void(*func)(void *arg), void *arg) { |
573 | // Start the thread with signals blocked, otherwise it can steal user signals. | |
574 | __sanitizer_sigset_t set, old; | |
575 | internal_sigfillset(&set); | |
576 | internal_sigprocmask(SIG_SETMASK, &set, &old); | |
577 | pthread_t th; | |
578 | pthread_create(&th, 0, (void*(*)(void *arg))func, arg); | |
579 | internal_sigprocmask(SIG_SETMASK, &old, 0); | |
580 | return th; | |
581 | } | |
582 | ||
583 | void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } | |
5645a48f | 584 | |
23e39437 | 585 | #if !SANITIZER_GO |
586 | static BlockingMutex syslog_lock(LINKER_INITIALIZED); | |
587 | #endif | |
588 | ||
589 | void WriteOneLineToSyslog(const char *s) { | |
590 | #if !SANITIZER_GO | |
591 | syslog_lock.CheckLocked(); | |
592 | asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s); | |
593 | #endif | |
594 | } | |
595 | ||
596 | void LogMessageOnPrintf(const char *str) { | |
597 | // Log all printf output to CrashLog. | |
598 | if (common_flags()->abort_on_error) | |
599 | CRAppendCrashLogMessage(str); | |
600 | } | |
601 | ||
602 | void LogFullErrorReport(const char *buffer) { | |
603 | #if !SANITIZER_GO | |
604 | // Log with os_trace. This will make it into the crash log. | |
605 | #if SANITIZER_OS_TRACE | |
606 | if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) { | |
607 | // os_trace requires the message (format parameter) to be a string literal. | |
608 | if (internal_strncmp(SanitizerToolName, "AddressSanitizer", | |
609 | sizeof("AddressSanitizer") - 1) == 0) | |
610 | os_trace("Address Sanitizer reported a failure."); | |
611 | else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", | |
612 | sizeof("UndefinedBehaviorSanitizer") - 1) == 0) | |
613 | os_trace("Undefined Behavior Sanitizer reported a failure."); | |
614 | else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", | |
615 | sizeof("ThreadSanitizer") - 1) == 0) | |
616 | os_trace("Thread Sanitizer reported a failure."); | |
617 | else | |
618 | os_trace("Sanitizer tool reported a failure."); | |
619 | ||
620 | if (common_flags()->log_to_syslog) | |
621 | os_trace("Consult syslog for more information."); | |
622 | } | |
623 | #endif | |
624 | ||
625 | // Log to syslog. | |
626 | // The logging on OS X may call pthread_create so we need the threading | |
627 | // environment to be fully initialized. Also, this should never be called when | |
628 | // holding the thread registry lock since that may result in a deadlock. If | |
629 | // the reporting thread holds the thread registry mutex, and asl_log waits | |
630 | // for GCD to dispatch a new thread, the process will deadlock, because the | |
631 | // pthread_create wrapper needs to acquire the lock as well. | |
632 | BlockingMutexLock l(&syslog_lock); | |
633 | if (common_flags()->log_to_syslog) | |
634 | WriteToSyslog(buffer); | |
635 | ||
636 | // The report is added to CrashLog as part of logging all of Printf output. | |
637 | #endif | |
638 | } | |
639 | ||
36093749 | 640 | SignalContext::WriteFlag SignalContext::GetWriteFlag() const { |
23e39437 | 641 | #if defined(__x86_64__) || defined(__i386__) |
642 | ucontext_t *ucontext = static_cast<ucontext_t*>(context); | |
643 | return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ; | |
644 | #else | |
645 | return UNKNOWN; | |
646 | #endif | |
647 | } | |
648 | ||
36093749 | 649 | static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { |
5645a48f | 650 | ucontext_t *ucontext = (ucontext_t*)context; |
651 | # if defined(__aarch64__) | |
652 | *pc = ucontext->uc_mcontext->__ss.__pc; | |
653 | # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 | |
654 | *bp = ucontext->uc_mcontext->__ss.__fp; | |
655 | # else | |
656 | *bp = ucontext->uc_mcontext->__ss.__lr; | |
657 | # endif | |
658 | *sp = ucontext->uc_mcontext->__ss.__sp; | |
659 | # elif defined(__x86_64__) | |
660 | *pc = ucontext->uc_mcontext->__ss.__rip; | |
661 | *bp = ucontext->uc_mcontext->__ss.__rbp; | |
662 | *sp = ucontext->uc_mcontext->__ss.__rsp; | |
663 | # elif defined(__arm__) | |
664 | *pc = ucontext->uc_mcontext->__ss.__pc; | |
665 | *bp = ucontext->uc_mcontext->__ss.__r[7]; | |
666 | *sp = ucontext->uc_mcontext->__ss.__sp; | |
667 | # elif defined(__i386__) | |
668 | *pc = ucontext->uc_mcontext->__ss.__eip; | |
669 | *bp = ucontext->uc_mcontext->__ss.__ebp; | |
670 | *sp = ucontext->uc_mcontext->__ss.__esp; | |
671 | # else | |
672 | # error "Unknown architecture" | |
673 | # endif | |
674 | } | |
675 | ||
36093749 | 676 | void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } |
677 | ||
23e39437 | 678 | #if !SANITIZER_GO |
679 | static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; | |
680 | LowLevelAllocator allocator_for_env; | |
681 | ||
682 | // Change the value of the env var |name|, leaking the original value. | |
683 | // If |name_value| is NULL, the variable is deleted from the environment, | |
684 | // otherwise the corresponding "NAME=value" string is replaced with | |
685 | // |name_value|. | |
686 | void LeakyResetEnv(const char *name, const char *name_value) { | |
687 | char **env = GetEnviron(); | |
688 | uptr name_len = internal_strlen(name); | |
689 | while (*env != 0) { | |
690 | uptr len = internal_strlen(*env); | |
691 | if (len > name_len) { | |
692 | const char *p = *env; | |
693 | if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { | |
694 | // Match. | |
695 | if (name_value) { | |
696 | // Replace the old value with the new one. | |
697 | *env = const_cast<char*>(name_value); | |
698 | } else { | |
699 | // Shift the subsequent pointers back. | |
700 | char **del = env; | |
701 | do { | |
702 | del[0] = del[1]; | |
703 | } while (*del++); | |
704 | } | |
705 | } | |
706 | } | |
707 | env++; | |
708 | } | |
709 | } | |
710 | ||
711 | SANITIZER_WEAK_CXX_DEFAULT_IMPL | |
712 | bool ReexecDisabled() { | |
713 | return false; | |
714 | } | |
715 | ||
716 | extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber; | |
717 | static const double kMinDyldVersionWithAutoInterposition = 360.0; | |
718 | ||
719 | bool DyldNeedsEnvVariable() { | |
720 | // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users | |
721 | // still may want use them on older systems. On older Darwin platforms, dyld | |
722 | // doesn't export dyldVersionNumber symbol and we simply return true. | |
723 | if (!&dyldVersionNumber) return true; | |
724 | // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if | |
725 | // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via | |
726 | // GetMacosVersion() doesn't work for the simulator. Let's instead check | |
727 | // `dyldVersionNumber`, which is exported by dyld, against a known version | |
728 | // number from the first OS release where this appeared. | |
729 | return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; | |
730 | } | |
731 | ||
732 | void MaybeReexec() { | |
d2ef4bee | 733 | // FIXME: This should really live in some "InitializePlatform" method. |
734 | MonotonicNanoTime(); | |
735 | ||
23e39437 | 736 | if (ReexecDisabled()) return; |
737 | ||
738 | // Make sure the dynamic runtime library is preloaded so that the | |
739 | // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec | |
740 | // ourselves. | |
741 | Dl_info info; | |
742 | RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info)); | |
743 | char *dyld_insert_libraries = | |
744 | const_cast<char*>(GetEnv(kDyldInsertLibraries)); | |
745 | uptr old_env_len = dyld_insert_libraries ? | |
746 | internal_strlen(dyld_insert_libraries) : 0; | |
747 | uptr fname_len = internal_strlen(info.dli_fname); | |
748 | const char *dylib_name = StripModuleName(info.dli_fname); | |
749 | uptr dylib_name_len = internal_strlen(dylib_name); | |
750 | ||
751 | bool lib_is_in_env = dyld_insert_libraries && | |
752 | internal_strstr(dyld_insert_libraries, dylib_name); | |
753 | if (DyldNeedsEnvVariable() && !lib_is_in_env) { | |
754 | // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime | |
755 | // library. | |
756 | InternalScopedString program_name(1024); | |
757 | uint32_t buf_size = program_name.size(); | |
758 | _NSGetExecutablePath(program_name.data(), &buf_size); | |
759 | char *new_env = const_cast<char*>(info.dli_fname); | |
760 | if (dyld_insert_libraries) { | |
761 | // Append the runtime dylib name to the existing value of | |
762 | // DYLD_INSERT_LIBRARIES. | |
763 | new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); | |
764 | internal_strncpy(new_env, dyld_insert_libraries, old_env_len); | |
765 | new_env[old_env_len] = ':'; | |
766 | // Copy fname_len and add a trailing zero. | |
767 | internal_strncpy(new_env + old_env_len + 1, info.dli_fname, | |
768 | fname_len + 1); | |
769 | // Ok to use setenv() since the wrappers don't depend on the value of | |
770 | // asan_inited. | |
771 | setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); | |
772 | } else { | |
773 | // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. | |
774 | setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); | |
775 | } | |
776 | VReport(1, "exec()-ing the program with\n"); | |
777 | VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); | |
778 | VReport(1, "to enable wrappers.\n"); | |
779 | execv(program_name.data(), *_NSGetArgv()); | |
780 | ||
781 | // We get here only if execv() failed. | |
782 | Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " | |
783 | "which is required for the sanitizer to work. We tried to set the " | |
784 | "environment variable and re-execute itself, but execv() failed, " | |
785 | "possibly because of sandbox restrictions. Make sure to launch the " | |
786 | "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); | |
787 | RAW_CHECK("execv failed" && 0); | |
788 | } | |
789 | ||
790 | // Verify that interceptors really work. We'll use dlsym to locate | |
791 | // "pthread_create", if interceptors are working, it should really point to | |
792 | // "wrap_pthread_create" within our own dylib. | |
793 | Dl_info info_pthread_create; | |
794 | void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create"); | |
795 | RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create)); | |
796 | if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) { | |
797 | Report( | |
798 | "ERROR: Interceptors are not working. This may be because %s is " | |
799 | "loaded too late (e.g. via dlopen). Please launch the executable " | |
800 | "with:\n%s=%s\n", | |
801 | SanitizerToolName, kDyldInsertLibraries, info.dli_fname); | |
802 | RAW_CHECK("interceptors not installed" && 0); | |
803 | } | |
804 | ||
805 | if (!lib_is_in_env) | |
806 | return; | |
807 | ||
d2ef4bee | 808 | if (!common_flags()->strip_env) |
809 | return; | |
810 | ||
23e39437 | 811 | // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove |
812 | // the dylib from the environment variable, because interceptors are installed | |
813 | // and we don't want our children to inherit the variable. | |
814 | ||
815 | uptr env_name_len = internal_strlen(kDyldInsertLibraries); | |
816 | // Allocate memory to hold the previous env var name, its value, the '=' | |
817 | // sign and the '\0' char. | |
818 | char *new_env = (char*)allocator_for_env.Allocate( | |
819 | old_env_len + 2 + env_name_len); | |
820 | RAW_CHECK(new_env); | |
821 | internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); | |
822 | internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); | |
823 | new_env[env_name_len] = '='; | |
824 | char *new_env_pos = new_env + env_name_len + 1; | |
825 | ||
826 | // Iterate over colon-separated pieces of |dyld_insert_libraries|. | |
827 | char *piece_start = dyld_insert_libraries; | |
828 | char *piece_end = NULL; | |
829 | char *old_env_end = dyld_insert_libraries + old_env_len; | |
830 | do { | |
831 | if (piece_start[0] == ':') piece_start++; | |
832 | piece_end = internal_strchr(piece_start, ':'); | |
833 | if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; | |
834 | if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; | |
835 | uptr piece_len = piece_end - piece_start; | |
836 | ||
837 | char *filename_start = | |
838 | (char *)internal_memrchr(piece_start, '/', piece_len); | |
839 | uptr filename_len = piece_len; | |
840 | if (filename_start) { | |
841 | filename_start += 1; | |
842 | filename_len = piece_len - (filename_start - piece_start); | |
843 | } else { | |
844 | filename_start = piece_start; | |
845 | } | |
846 | ||
847 | // If the current piece isn't the runtime library name, | |
848 | // append it to new_env. | |
849 | if ((dylib_name_len != filename_len) || | |
850 | (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { | |
851 | if (new_env_pos != new_env + env_name_len + 1) { | |
852 | new_env_pos[0] = ':'; | |
853 | new_env_pos++; | |
854 | } | |
855 | internal_strncpy(new_env_pos, piece_start, piece_len); | |
856 | new_env_pos += piece_len; | |
857 | } | |
858 | // Move on to the next piece. | |
859 | piece_start = piece_end; | |
860 | } while (piece_start < old_env_end); | |
861 | ||
862 | // Can't use setenv() here, because it requires the allocator to be | |
863 | // initialized. | |
864 | // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in | |
865 | // a separate function called after InitializeAllocator(). | |
866 | if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; | |
867 | LeakyResetEnv(kDyldInsertLibraries, new_env); | |
868 | } | |
869 | #endif // SANITIZER_GO | |
870 | ||
871 | char **GetArgv() { | |
872 | return *_NSGetArgv(); | |
873 | } | |
874 | ||
36093749 | 875 | #if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM |
876 | // The task_vm_info struct is normally provided by the macOS SDK, but we need | |
877 | // fields only available in 10.12+. Declare the struct manually to be able to | |
878 | // build against older SDKs. | |
879 | struct __sanitizer_task_vm_info { | |
880 | mach_vm_size_t virtual_size; | |
881 | integer_t region_count; | |
882 | integer_t page_size; | |
883 | mach_vm_size_t resident_size; | |
884 | mach_vm_size_t resident_size_peak; | |
885 | mach_vm_size_t device; | |
886 | mach_vm_size_t device_peak; | |
887 | mach_vm_size_t internal; | |
888 | mach_vm_size_t internal_peak; | |
889 | mach_vm_size_t external; | |
890 | mach_vm_size_t external_peak; | |
891 | mach_vm_size_t reusable; | |
892 | mach_vm_size_t reusable_peak; | |
893 | mach_vm_size_t purgeable_volatile_pmap; | |
894 | mach_vm_size_t purgeable_volatile_resident; | |
895 | mach_vm_size_t purgeable_volatile_virtual; | |
896 | mach_vm_size_t compressed; | |
897 | mach_vm_size_t compressed_peak; | |
898 | mach_vm_size_t compressed_lifetime; | |
899 | mach_vm_size_t phys_footprint; | |
900 | mach_vm_address_t min_address; | |
901 | mach_vm_address_t max_address; | |
902 | }; | |
903 | #define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \ | |
904 | (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t))) | |
905 | ||
906 | uptr GetTaskInfoMaxAddress() { | |
d2ef4bee | 907 | __sanitizer_task_vm_info vm_info = {} /* zero initialize */; |
36093749 | 908 | mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT; |
909 | int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count); | |
d2ef4bee | 910 | if (err == 0 && vm_info.max_address != 0) { |
36093749 | 911 | return vm_info.max_address - 1; |
912 | } else { | |
913 | // xnu cannot provide vm address limit | |
914 | return 0x200000000 - 1; | |
915 | } | |
916 | } | |
917 | #endif | |
918 | ||
d2ef4bee | 919 | uptr GetMaxUserVirtualAddress() { |
36093749 | 920 | #if SANITIZER_WORDSIZE == 64 |
921 | # if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM | |
922 | // Get the maximum VM address | |
923 | static uptr max_vm = GetTaskInfoMaxAddress(); | |
924 | CHECK(max_vm); | |
925 | return max_vm; | |
926 | # else | |
927 | return (1ULL << 47) - 1; // 0x00007fffffffffffUL; | |
928 | # endif | |
929 | #else // SANITIZER_WORDSIZE == 32 | |
930 | return (1ULL << 32) - 1; // 0xffffffff; | |
931 | #endif // SANITIZER_WORDSIZE | |
932 | } | |
933 | ||
d2ef4bee | 934 | uptr GetMaxVirtualAddress() { |
935 | return GetMaxUserVirtualAddress(); | |
936 | } | |
937 | ||
938 | uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, | |
939 | uptr *largest_gap_found, | |
940 | uptr *max_occupied_addr) { | |
23e39437 | 941 | typedef vm_region_submap_short_info_data_64_t RegionInfo; |
942 | enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; | |
943 | // Start searching for available memory region past PAGEZERO, which is | |
944 | // 4KB on 32-bit and 4GB on 64-bit. | |
945 | mach_vm_address_t start_address = | |
946 | (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000; | |
947 | ||
948 | mach_vm_address_t address = start_address; | |
949 | mach_vm_address_t free_begin = start_address; | |
950 | kern_return_t kr = KERN_SUCCESS; | |
36093749 | 951 | if (largest_gap_found) *largest_gap_found = 0; |
d2ef4bee | 952 | if (max_occupied_addr) *max_occupied_addr = 0; |
23e39437 | 953 | while (kr == KERN_SUCCESS) { |
954 | mach_vm_size_t vmsize = 0; | |
955 | natural_t depth = 0; | |
956 | RegionInfo vminfo; | |
957 | mach_msg_type_number_t count = kRegionInfoSize; | |
958 | kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth, | |
959 | (vm_region_info_t)&vminfo, &count); | |
d2ef4bee | 960 | if (kr == KERN_INVALID_ADDRESS) { |
961 | // No more regions beyond "address", consider the gap at the end of VM. | |
962 | address = GetMaxVirtualAddress() + 1; | |
963 | vmsize = 0; | |
964 | } else { | |
965 | if (max_occupied_addr) *max_occupied_addr = address + vmsize; | |
966 | } | |
23e39437 | 967 | if (free_begin != address) { |
968 | // We found a free region [free_begin..address-1]. | |
36093749 | 969 | uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment); |
970 | uptr gap_end = RoundDownTo((uptr)address, alignment); | |
971 | uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0; | |
d2ef4bee | 972 | if (size < gap_size) { |
36093749 | 973 | return gap_start; |
974 | } | |
975 | ||
976 | if (largest_gap_found && *largest_gap_found < gap_size) { | |
977 | *largest_gap_found = gap_size; | |
23e39437 | 978 | } |
979 | } | |
980 | // Move to the next region. | |
981 | address += vmsize; | |
982 | free_begin = address; | |
983 | } | |
984 | ||
985 | // We looked at all free regions and could not find one large enough. | |
986 | return 0; | |
987 | } | |
988 | ||
989 | // FIXME implement on this platform. | |
990 | void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { } | |
991 | ||
36093749 | 992 | void SignalContext::DumpAllRegisters(void *context) { |
993 | Report("Register values:\n"); | |
994 | ||
995 | ucontext_t *ucontext = (ucontext_t*)context; | |
996 | # define DUMPREG64(r) \ | |
997 | Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r); | |
998 | # define DUMPREG32(r) \ | |
999 | Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r); | |
1000 | # define DUMPREG_(r) Printf(" "); DUMPREG(r); | |
1001 | # define DUMPREG__(r) Printf(" "); DUMPREG(r); | |
1002 | # define DUMPREG___(r) Printf(" "); DUMPREG(r); | |
1003 | ||
1004 | # if defined(__x86_64__) | |
1005 | # define DUMPREG(r) DUMPREG64(r) | |
1006 | DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n"); | |
1007 | DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n"); | |
1008 | DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n"); | |
1009 | DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n"); | |
1010 | # elif defined(__i386__) | |
1011 | # define DUMPREG(r) DUMPREG32(r) | |
1012 | DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n"); | |
1013 | DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n"); | |
1014 | # elif defined(__aarch64__) | |
1015 | # define DUMPREG(r) DUMPREG64(r) | |
1016 | DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n"); | |
1017 | DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n"); | |
1018 | DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n"); | |
1019 | DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n"); | |
1020 | DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n"); | |
1021 | DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n"); | |
1022 | DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n"); | |
1023 | DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n"); | |
1024 | # elif defined(__arm__) | |
1025 | # define DUMPREG(r) DUMPREG32(r) | |
1026 | DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n"); | |
1027 | DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n"); | |
1028 | DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n"); | |
1029 | DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n"); | |
1030 | # else | |
1031 | # error "Unknown architecture" | |
1032 | # endif | |
1033 | ||
1034 | # undef DUMPREG64 | |
1035 | # undef DUMPREG32 | |
1036 | # undef DUMPREG_ | |
1037 | # undef DUMPREG__ | |
1038 | # undef DUMPREG___ | |
1039 | # undef DUMPREG | |
1040 | } | |
1041 | ||
1042 | static inline bool CompareBaseAddress(const LoadedModule &a, | |
1043 | const LoadedModule &b) { | |
1044 | return a.base_address() < b.base_address(); | |
1045 | } | |
1046 | ||
1047 | void FormatUUID(char *out, uptr size, const u8 *uuid) { | |
1048 | internal_snprintf(out, size, | |
1049 | "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-" | |
1050 | "%02X%02X%02X%02X%02X%02X>", | |
1051 | uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], | |
1052 | uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], | |
1053 | uuid[12], uuid[13], uuid[14], uuid[15]); | |
1054 | } | |
1055 | ||
1056 | void PrintModuleMap() { | |
1057 | Printf("Process module map:\n"); | |
1058 | MemoryMappingLayout memory_mapping(false); | |
d2ef4bee | 1059 | InternalMmapVector<LoadedModule> modules; |
1060 | modules.reserve(128); | |
36093749 | 1061 | memory_mapping.DumpListOfModules(&modules); |
d2ef4bee | 1062 | Sort(modules.data(), modules.size(), CompareBaseAddress); |
36093749 | 1063 | for (uptr i = 0; i < modules.size(); ++i) { |
1064 | char uuid_str[128]; | |
1065 | FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid()); | |
1066 | Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(), | |
1067 | modules[i].max_executable_address(), modules[i].full_name(), | |
1068 | ModuleArchToString(modules[i].arch()), uuid_str); | |
1069 | } | |
1070 | Printf("End of module map.\n"); | |
1071 | } | |
1072 | ||
1073 | void CheckNoDeepBind(const char *filename, int flag) { | |
1074 | // Do nothing. | |
1075 | } | |
1076 | ||
36093749 | 1077 | bool GetRandom(void *buffer, uptr length, bool blocking) { |
d2ef4bee | 1078 | if (!buffer || !length || length > 256) |
1079 | return false; | |
1080 | // arc4random never fails. | |
1081 | arc4random_buf(buffer, length); | |
1082 | return true; | |
1083 | } | |
1084 | ||
1085 | u32 GetNumberOfCPUs() { | |
1086 | return (u32)sysconf(_SC_NPROCESSORS_ONLN); | |
36093749 | 1087 | } |
1088 | ||
549e2197 | 1089 | } // namespace __sanitizer |
1090 | ||
1e80ce41 | 1091 | #endif // SANITIZER_MAC |