1//===-- sanitizer_mac.cc --------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is shared between various sanitizers' runtime libraries and 11// implements OSX-specific functions. 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_platform.h" 15#if SANITIZER_MAC 16 17// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so 18// the clients will most certainly use 64-bit ones as well. 19#ifndef _DARWIN_USE_64_BIT_INODE 20#define _DARWIN_USE_64_BIT_INODE 1 21#endif 22#include <stdio.h> 23 24#include "sanitizer_common.h" 25#include "sanitizer_flags.h" 26#include "sanitizer_internal_defs.h" 27#include "sanitizer_libc.h" 28#include "sanitizer_mac.h" 29#include "sanitizer_placement_new.h" 30#include "sanitizer_procmaps.h" 31 32#include <crt_externs.h> // for _NSGetEnviron 33#include <fcntl.h> 34#include <mach-o/dyld.h> 35#include <pthread.h> 36#include <sched.h> 37#include <signal.h> 38#include <stdlib.h> 39#include <sys/mman.h> 40#include <sys/resource.h> 41#include <sys/stat.h> 42#include <sys/sysctl.h> 43#include <sys/types.h> 44#include <unistd.h> 45#include <libkern/OSAtomic.h> 46#include <errno.h> 47 48namespace __sanitizer { 49 50#include "sanitizer_syscall_generic.inc" 51 52// ---------------------- sanitizer_libc.h 53uptr internal_mmap(void *addr, size_t length, int prot, int flags, 54 int fd, u64 offset) { 55 return (uptr)mmap(addr, length, prot, flags, fd, offset); 56} 57 58uptr internal_munmap(void *addr, uptr length) { 59 return munmap(addr, length); 60} 61 62int internal_mprotect(void *addr, uptr length, int prot) { 63 return mprotect(addr, length, prot); 64} 65 66uptr internal_close(fd_t fd) { 67 return close(fd); 68} 69 70uptr internal_open(const char *filename, int flags) { 71 return open(filename, flags); 72} 73 74uptr internal_open(const char *filename, int flags, u32 mode) { 75 return open(filename, flags, mode); 76} 77 78uptr internal_read(fd_t fd, void *buf, uptr count) { 79 return read(fd, buf, count); 80} 81 82uptr internal_write(fd_t fd, const void *buf, uptr count) { 83 return write(fd, buf, count); 84} 85 86uptr internal_stat(const char *path, void *buf) { 87 return stat(path, (struct stat *)buf); 88} 89 90uptr internal_lstat(const char *path, void *buf) { 91 return lstat(path, (struct stat *)buf); 92} 93 94uptr internal_fstat(fd_t fd, void *buf) { 95 return fstat(fd, (struct stat *)buf); 96} 97 98uptr internal_filesize(fd_t fd) { 99 struct stat st; 100 if (internal_fstat(fd, &st)) 101 return -1; 102 return (uptr)st.st_size; 103} 104 105uptr internal_dup2(int oldfd, int newfd) { 106 return dup2(oldfd, newfd); 107} 108 109uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 110 return readlink(path, buf, bufsize); 111} 112 113uptr internal_unlink(const char *path) { 114 return unlink(path); 115} 116 117uptr internal_sched_yield() { 118 return sched_yield(); 119} 120 121void internal__exit(int exitcode) { 122 _exit(exitcode); 123} 124 125uptr internal_getpid() { 126 return getpid(); 127} 128 129int internal_sigaction(int signum, const void *act, void *oldact) { 130 return sigaction(signum, 131 (struct sigaction *)act, (struct sigaction *)oldact); 132} 133 134int internal_fork() { 135 // TODO(glider): this may call user's pthread_atfork() handlers which is bad. 136 return fork(); 137} 138 139uptr internal_rename(const char *oldpath, const char *newpath) { 140 return rename(oldpath, newpath); 141} 142 143uptr internal_ftruncate(fd_t fd, uptr size) { 144 return ftruncate(fd, size); 145} 146 147// ----------------- sanitizer_common.h 148bool FileExists(const char *filename) { 149 struct stat st; 150 if (stat(filename, &st)) 151 return false; 152 // Sanity check: filename is a regular file. 153 return S_ISREG(st.st_mode); 154} 155 156uptr GetTid() { 157 return reinterpret_cast<uptr>(pthread_self()); 158} 159 160void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 161 uptr *stack_bottom) { 162 CHECK(stack_top); 163 CHECK(stack_bottom); 164 uptr stacksize = pthread_get_stacksize_np(pthread_self()); 165 // pthread_get_stacksize_np() returns an incorrect stack size for the main 166 // thread on Mavericks. See 167 // https://code.google.com/p/address-sanitizer/issues/detail?id=261 168 if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && 169 stacksize == (1 << 19)) { 170 struct rlimit rl; 171 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); 172 // Most often rl.rlim_cur will be the desired 8M. 173 if (rl.rlim_cur < kMaxThreadStackSize) { 174 stacksize = rl.rlim_cur; 175 } else { 176 stacksize = kMaxThreadStackSize; 177 } 178 } 179 void *stackaddr = pthread_get_stackaddr_np(pthread_self()); 180 *stack_top = (uptr)stackaddr; 181 *stack_bottom = *stack_top - stacksize; 182} 183 184const char *GetEnv(const char *name) { 185 char ***env_ptr = _NSGetEnviron(); 186 if (!env_ptr) { 187 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " 188 "called after libSystem_initializer().\n"); 189 CHECK(env_ptr); 190 } 191 char **environ = *env_ptr; 192 CHECK(environ); 193 uptr name_len = internal_strlen(name); 194 while (*environ != 0) { 195 uptr len = internal_strlen(*environ); 196 if (len > name_len) { 197 const char *p = *environ; 198 if (!internal_memcmp(p, name, name_len) && 199 p[name_len] == '=') { // Match. 200 return *environ + name_len + 1; // String starting after =. 201 } 202 } 203 environ++; 204 } 205 return 0; 206} 207 208uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { 209 CHECK_LE(kMaxPathLength, buf_len); 210 211 // On OS X the executable path is saved to the stack by dyld. Reading it 212 // from there is much faster than calling dladdr, especially for large 213 // binaries with symbols. 214 InternalScopedString exe_path(kMaxPathLength); 215 uint32_t size = exe_path.size(); 216 if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && 217 realpath(exe_path.data(), buf) != 0) { 218 return internal_strlen(buf); 219 } 220 return 0; 221} 222 223void ReExec() { 224 UNIMPLEMENTED(); 225} 226 227uptr GetPageSize() { 228 return sysconf(_SC_PAGESIZE); 229} 230 231BlockingMutex::BlockingMutex() { 232 internal_memset(this, 0, sizeof(*this)); 233} 234 235void BlockingMutex::Lock() { 236 CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); 237 CHECK_EQ(OS_SPINLOCK_INIT, 0); 238 CHECK_NE(owner_, (uptr)pthread_self()); 239 OSSpinLockLock((OSSpinLock*)&opaque_storage_); 240 CHECK(!owner_); 241 owner_ = (uptr)pthread_self(); 242} 243 244void BlockingMutex::Unlock() { 245 CHECK(owner_ == (uptr)pthread_self()); 246 owner_ = 0; 247 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); 248} 249 250void BlockingMutex::CheckLocked() { 251 CHECK_EQ((uptr)pthread_self(), owner_); 252} 253 254u64 NanoTime() { 255 return 0; 256} 257 258uptr GetTlsSize() { 259 return 0; 260} 261 262void InitTlsSize() { 263} 264 265void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 266 uptr *tls_addr, uptr *tls_size) { 267#ifndef SANITIZER_GO 268 uptr stack_top, stack_bottom; 269 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 270 *stk_addr = stack_bottom; 271 *stk_size = stack_top - stack_bottom; 272 *tls_addr = 0; 273 *tls_size = 0; 274#else 275 *stk_addr = 0; 276 *stk_size = 0; 277 *tls_addr = 0; 278 *tls_size = 0; 279#endif 280} 281 282uptr GetListOfModules(LoadedModule *modules, uptr max_modules, 283 string_predicate_t filter) { 284 MemoryMappingLayout memory_mapping(false); 285 return memory_mapping.DumpListOfModules(modules, max_modules, filter); 286} 287 288bool IsDeadlySignal(int signum) { 289 return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; 290} 291 292MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; 293 294MacosVersion GetMacosVersionInternal() { 295 int mib[2] = { CTL_KERN, KERN_OSRELEASE }; 296 char version[100]; 297 uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); 298 for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; 299 // Get the version length. 300 CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1); 301 CHECK_LT(len, maxlen); 302 CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1); 303 switch (version[0]) { 304 case '9': return MACOS_VERSION_LEOPARD; 305 case '1': { 306 switch (version[1]) { 307 case '0': return MACOS_VERSION_SNOW_LEOPARD; 308 case '1': return MACOS_VERSION_LION; 309 case '2': return MACOS_VERSION_MOUNTAIN_LION; 310 case '3': return MACOS_VERSION_MAVERICKS; 311 case '4': return MACOS_VERSION_YOSEMITE; 312 default: 313 if (IsDigit(version[1])) 314 return MACOS_VERSION_UNKNOWN_NEWER; 315 else 316 return MACOS_VERSION_UNKNOWN; 317 } 318 } 319 default: return MACOS_VERSION_UNKNOWN; 320 } 321} 322 323MacosVersion GetMacosVersion() { 324 atomic_uint32_t *cache = 325 reinterpret_cast<atomic_uint32_t*>(&cached_macos_version); 326 MacosVersion result = 327 static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire)); 328 if (result == MACOS_VERSION_UNINITIALIZED) { 329 result = GetMacosVersionInternal(); 330 atomic_store(cache, result, memory_order_release); 331 } 332 return result; 333} 334 335uptr GetRSS() { 336 return 0; 337} 338 339void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } 340void internal_join_thread(void *th) { } 341 342void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { 343 ucontext_t *ucontext = (ucontext_t*)context; 344# if SANITIZER_WORDSIZE == 64 345 *pc = ucontext->uc_mcontext->__ss.__rip; 346 *bp = ucontext->uc_mcontext->__ss.__rbp; 347 *sp = ucontext->uc_mcontext->__ss.__rsp; 348# else 349 *pc = ucontext->uc_mcontext->__ss.__eip; 350 *bp = ucontext->uc_mcontext->__ss.__ebp; 351 *sp = ucontext->uc_mcontext->__ss.__esp; 352# endif // SANITIZER_WORDSIZE 353} 354 355} // namespace __sanitizer 356 357#endif // SANITIZER_MAC 358