blob: 4c5b40935ef653a7bd467f9698afddc38ef0ad86 [file] [log] [blame]
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +00001//===-- 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//
Alexander Potapenko768e3152014-02-03 15:32:19 +000010// This file is shared between various sanitizers' runtime libraries and
11// implements OSX-specific functions.
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000012//===----------------------------------------------------------------------===//
13
Evgeniy Stepanov0af67232013-03-19 14:33:38 +000014#include "sanitizer_platform.h"
15#if SANITIZER_MAC
16
Alexander Potapenkod895ae92013-02-06 14:41:15 +000017// 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>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000023
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000024#include "sanitizer_common.h"
Alexander Potapenko789e3e12014-01-31 13:10:07 +000025#include "sanitizer_flags.h"
Alexey Samsonov5bbf8292012-06-05 14:25:27 +000026#include "sanitizer_internal_defs.h"
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000027#include "sanitizer_libc.h"
Alexander Potapenko768e3152014-02-03 15:32:19 +000028#include "sanitizer_mac.h"
Alexey Samsonov7a36e612013-09-10 14:36:16 +000029#include "sanitizer_placement_new.h"
Alexey Samsonov28a98952012-06-07 06:15:12 +000030#include "sanitizer_procmaps.h"
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000031
Alexey Samsonov0c53a382012-06-14 14:07:21 +000032#include <crt_externs.h> // for _NSGetEnviron
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000033#include <fcntl.h>
Anna Zaks22490492015-02-27 03:12:19 +000034#include <mach-o/dyld.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000035#include <pthread.h>
Alexey Samsonov58a3c582012-06-18 08:44:30 +000036#include <sched.h>
Alexander Potapenko789e3e12014-01-31 13:10:07 +000037#include <signal.h>
Anna Zaks22490492015-02-27 03:12:19 +000038#include <stdlib.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000039#include <sys/mman.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000040#include <sys/resource.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000041#include <sys/stat.h>
Alexander Potapenko768e3152014-02-03 15:32:19 +000042#include <sys/sysctl.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000043#include <sys/types.h>
Alexey Samsonov03c8b842012-06-05 08:32:53 +000044#include <unistd.h>
Dmitry Vyukovaf4b0b02013-01-14 08:01:58 +000045#include <libkern/OSAtomic.h>
Peter Collingbourne8e110ce2013-05-08 15:07:12 +000046#include <errno.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000047
48namespace __sanitizer {
49
Peter Collingbourne6f4be192013-05-08 14:43:49 +000050#include "sanitizer_syscall_generic.inc"
51
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000052// ---------------------- sanitizer_libc.h
Peter Collingbourne8e110ce2013-05-08 15:07:12 +000053uptr 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);
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000056}
57
Peter Collingbourne8e110ce2013-05-08 15:07:12 +000058uptr internal_munmap(void *addr, uptr length) {
Alexey Samsonov7ac77d62012-06-05 09:49:25 +000059 return munmap(addr, length);
60}
61
Timur Iskhodzhanovea1f3322015-04-10 15:02:19 +000062int internal_mprotect(void *addr, uptr length, int prot) {
63 return mprotect(addr, length, prot);
64}
65
Peter Collingbourne6f4be192013-05-08 14:43:49 +000066uptr internal_close(fd_t fd) {
Alexey Samsonov03c8b842012-06-05 08:32:53 +000067 return close(fd);
68}
69
Peter Collingbourne6f4be192013-05-08 14:43:49 +000070uptr internal_open(const char *filename, int flags) {
Alexey Samsonov39313b72013-02-01 15:58:46 +000071 return open(filename, flags);
72}
73
Peter Collingbourne6f4be192013-05-08 14:43:49 +000074uptr internal_open(const char *filename, int flags, u32 mode) {
Alexey Samsonov39313b72013-02-01 15:58:46 +000075 return open(filename, flags, mode);
76}
77
Alexey Samsonov03c8b842012-06-05 08:32:53 +000078uptr 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
Peter Collingbourne6f4be192013-05-08 14:43:49 +000086uptr internal_stat(const char *path, void *buf) {
Alexey Samsonov576e2702013-02-04 10:31:39 +000087 return stat(path, (struct stat *)buf);
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +000088}
89
Peter Collingbourne6f4be192013-05-08 14:43:49 +000090uptr internal_lstat(const char *path, void *buf) {
Alexey Samsonov576e2702013-02-04 10:31:39 +000091 return lstat(path, (struct stat *)buf);
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +000092}
93
Peter Collingbourne6f4be192013-05-08 14:43:49 +000094uptr internal_fstat(fd_t fd, void *buf) {
Alexey Samsonov576e2702013-02-04 10:31:39 +000095 return fstat(fd, (struct stat *)buf);
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +000096}
97
Alexey Samsonovca2b5d72012-06-06 07:30:33 +000098uptr internal_filesize(fd_t fd) {
Alexey Samsonovce8d4972012-08-02 10:09:31 +000099 struct stat st;
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +0000100 if (internal_fstat(fd, &st))
Alexey Samsonovca2b5d72012-06-06 07:30:33 +0000101 return -1;
102 return (uptr)st.st_size;
103}
104
Peter Collingbourne6f4be192013-05-08 14:43:49 +0000105uptr internal_dup2(int oldfd, int newfd) {
Alexey Samsonovca2b5d72012-06-06 07:30:33 +0000106 return dup2(oldfd, newfd);
107}
108
Alexey Samsonovf6d21252012-09-05 14:48:24 +0000109uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
110 return readlink(path, buf, bufsize);
111}
112
Kuba Breckac52f3002014-12-29 02:18:59 +0000113uptr internal_unlink(const char *path) {
114 return unlink(path);
115}
116
Peter Collingbourne6f4be192013-05-08 14:43:49 +0000117uptr internal_sched_yield() {
Alexey Samsonov58a3c582012-06-18 08:44:30 +0000118 return sched_yield();
119}
120
Alexey Samsonovaadd1f22013-02-20 13:54:32 +0000121void internal__exit(int exitcode) {
122 _exit(exitcode);
123}
124
Peter Collingbourneffaf2ea2013-05-17 16:56:53 +0000125uptr internal_getpid() {
126 return getpid();
127}
128
Alexander Potapenko789e3e12014-01-31 13:10:07 +0000129int internal_sigaction(int signum, const void *act, void *oldact) {
130 return sigaction(signum,
131 (struct sigaction *)act, (struct sigaction *)oldact);
132}
133
Alexander Potapenko4a6cac42014-05-13 16:17:54 +0000134int internal_fork() {
135 // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
136 return fork();
137}
138
Evgeniy Stepanov567e5162014-05-27 12:37:52 +0000139uptr 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
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000147// ----------------- sanitizer_common.h
Alexey Samsonovae9b18b2012-11-09 14:45:30 +0000148bool 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
Dmitry Vyukov56faa552012-10-02 12:58:14 +0000156uptr GetTid() {
157 return reinterpret_cast<uptr>(pthread_self());
158}
159
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +0000160void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000161 uptr *stack_bottom) {
162 CHECK(stack_top);
163 CHECK(stack_bottom);
164 uptr stacksize = pthread_get_stacksize_np(pthread_self());
Alexander Potapenkof6ff6b02014-02-03 16:42:29 +0000165 // 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
Kuba Brecka0078cea72014-11-05 18:55:38 +0000168 if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
Alexander Potapenkof6ff6b02014-02-03 16:42:29 +0000169 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 }
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000179 void *stackaddr = pthread_get_stackaddr_np(pthread_self());
180 *stack_top = (uptr)stackaddr;
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +0000181 *stack_bottom = *stack_top - stacksize;
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000182}
183
Alexey Samsonov0c53a382012-06-14 14:07:21 +0000184const char *GetEnv(const char *name) {
185 char ***env_ptr = _NSGetEnviron();
Alexander Potapenkofa82ba92013-11-13 13:34:53 +0000186 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 }
Alexey Samsonov0c53a382012-06-14 14:07:21 +0000191 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}
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000207
Anna Zaks22490492015-02-27 03:12:19 +0000208uptr 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
Alexey Samsonov97ca3062012-09-17 09:12:39 +0000223void ReExec() {
224 UNIMPLEMENTED();
225}
226
Peter Collingbourneb69b8a42013-05-20 17:05:29 +0000227uptr GetPageSize() {
228 return sysconf(_SC_PAGESIZE);
229}
230
Alexey Samsonova097f7b2013-03-14 13:30:56 +0000231BlockingMutex::BlockingMutex() {
232 internal_memset(this, 0, sizeof(*this));
233}
234
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000235void BlockingMutex::Lock() {
236 CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
Kostya Serebryany459df6f2013-02-26 12:59:06 +0000237 CHECK_EQ(OS_SPINLOCK_INIT, 0);
238 CHECK_NE(owner_, (uptr)pthread_self());
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000239 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
Alexey Samsonovdb7d9652013-03-11 15:45:20 +0000250void BlockingMutex::CheckLocked() {
251 CHECK_EQ((uptr)pthread_self(), owner_);
252}
253
Dmitry Vyukovc9e304a2013-06-06 13:00:32 +0000254u64 NanoTime() {
255 return 0;
256}
257
Evgeniy Stepanov5697b582013-03-13 08:19:53 +0000258uptr GetTlsSize() {
259 return 0;
260}
261
262void InitTlsSize() {
263}
264
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000265void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
266 uptr *tls_addr, uptr *tls_size) {
Dmitry Vyukovce0247c2013-06-06 13:20:40 +0000267#ifndef SANITIZER_GO
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000268 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;
Dmitry Vyukovce0247c2013-06-06 13:20:40 +0000274#else
275 *stk_addr = 0;
276 *stk_size = 0;
277 *tls_addr = 0;
278 *tls_size = 0;
279#endif
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000280}
281
Alexey Samsonov7a36e612013-09-10 14:36:16 +0000282uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
283 string_predicate_t filter) {
284 MemoryMappingLayout memory_mapping(false);
Alexey Samsonov64ffa592013-12-25 08:39:38 +0000285 return memory_mapping.DumpListOfModules(modules, max_modules, filter);
Alexey Samsonov7a36e612013-09-10 14:36:16 +0000286}
287
Alexander Potapenko789e3e12014-01-31 13:10:07 +0000288bool IsDeadlySignal(int signum) {
289 return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
290}
291
Alexander Potapenko768e3152014-02-03 15:32:19 +0000292MacosVersion 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;
Kuba Breckaf4bdbde2014-11-05 18:53:22 +0000311 case '4': return MACOS_VERSION_YOSEMITE;
Kuba Brecka731089b2014-12-16 04:46:15 +0000312 default:
313 if (IsDigit(version[1]))
314 return MACOS_VERSION_UNKNOWN_NEWER;
315 else
316 return MACOS_VERSION_UNKNOWN;
Alexander Potapenko768e3152014-02-03 15:32:19 +0000317 }
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
Kostya Serebryany6c54a6b2014-12-09 01:22:59 +0000335uptr GetRSS() {
336 return 0;
337}
338
Kostya Serebryany43eb7732014-12-16 19:13:01 +0000339void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
Kostya Serebryany5f5bc4a2014-12-16 21:06:07 +0000340void internal_join_thread(void *th) { }
Kostya Serebryany43eb7732014-12-16 19:13:01 +0000341
Dmitry Vyukovb79ac882015-03-02 17:36:02 +0000342void 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
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +0000355} // namespace __sanitizer
356
Alexey Samsonova0e28a72013-04-03 07:24:35 +0000357#endif // SANITIZER_MAC