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