blob: 04051e9fef7ad6fc503adb7338ad980d8ed16c69 [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
Ismail Pazarbasib981dc82015-05-12 20:47:21 +000033#include <errno.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000034#include <fcntl.h>
Ismail Pazarbasib981dc82015-05-12 20:47:21 +000035#include <libkern/OSAtomic.h>
Anna Zaks22490492015-02-27 03:12:19 +000036#include <mach-o/dyld.h>
Ismail Pazarbasib981dc82015-05-12 20:47:21 +000037#include <mach/mach.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000038#include <pthread.h>
Alexey Samsonov58a3c582012-06-18 08:44:30 +000039#include <sched.h>
Alexander Potapenko789e3e12014-01-31 13:10:07 +000040#include <signal.h>
Anna Zaks22490492015-02-27 03:12:19 +000041#include <stdlib.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000042#include <sys/mman.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000043#include <sys/resource.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000044#include <sys/stat.h>
Alexander Potapenko768e3152014-02-03 15:32:19 +000045#include <sys/sysctl.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000046#include <sys/types.h>
Alexey Samsonov03c8b842012-06-05 08:32:53 +000047#include <unistd.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000048
49namespace __sanitizer {
50
Peter Collingbourne6f4be192013-05-08 14:43:49 +000051#include "sanitizer_syscall_generic.inc"
52
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000053// ---------------------- sanitizer_libc.h
Peter Collingbourne8e110ce2013-05-08 15:07:12 +000054uptr internal_mmap(void *addr, size_t length, int prot, int flags,
55 int fd, u64 offset) {
56 return (uptr)mmap(addr, length, prot, flags, fd, offset);
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000057}
58
Peter Collingbourne8e110ce2013-05-08 15:07:12 +000059uptr internal_munmap(void *addr, uptr length) {
Alexey Samsonov7ac77d62012-06-05 09:49:25 +000060 return munmap(addr, length);
61}
62
Timur Iskhodzhanovea1f3322015-04-10 15:02:19 +000063int internal_mprotect(void *addr, uptr length, int prot) {
64 return mprotect(addr, length, prot);
65}
66
Peter Collingbourne6f4be192013-05-08 14:43:49 +000067uptr internal_close(fd_t fd) {
Alexey Samsonov03c8b842012-06-05 08:32:53 +000068 return close(fd);
69}
70
Peter Collingbourne6f4be192013-05-08 14:43:49 +000071uptr internal_open(const char *filename, int flags) {
Alexey Samsonov39313b72013-02-01 15:58:46 +000072 return open(filename, flags);
73}
74
Peter Collingbourne6f4be192013-05-08 14:43:49 +000075uptr internal_open(const char *filename, int flags, u32 mode) {
Alexey Samsonov39313b72013-02-01 15:58:46 +000076 return open(filename, flags, mode);
77}
78
Alexey Samsonov03c8b842012-06-05 08:32:53 +000079uptr internal_read(fd_t fd, void *buf, uptr count) {
80 return read(fd, buf, count);
81}
82
83uptr internal_write(fd_t fd, const void *buf, uptr count) {
84 return write(fd, buf, count);
85}
86
Peter Collingbourne6f4be192013-05-08 14:43:49 +000087uptr internal_stat(const char *path, void *buf) {
Alexey Samsonov576e2702013-02-04 10:31:39 +000088 return stat(path, (struct stat *)buf);
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +000089}
90
Peter Collingbourne6f4be192013-05-08 14:43:49 +000091uptr internal_lstat(const char *path, void *buf) {
Alexey Samsonov576e2702013-02-04 10:31:39 +000092 return lstat(path, (struct stat *)buf);
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +000093}
94
Peter Collingbourne6f4be192013-05-08 14:43:49 +000095uptr internal_fstat(fd_t fd, void *buf) {
Alexey Samsonov576e2702013-02-04 10:31:39 +000096 return fstat(fd, (struct stat *)buf);
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +000097}
98
Alexey Samsonovca2b5d72012-06-06 07:30:33 +000099uptr internal_filesize(fd_t fd) {
Alexey Samsonovce8d4972012-08-02 10:09:31 +0000100 struct stat st;
Alexey Samsonov2c5cbd22013-02-04 10:16:50 +0000101 if (internal_fstat(fd, &st))
Alexey Samsonovca2b5d72012-06-06 07:30:33 +0000102 return -1;
103 return (uptr)st.st_size;
104}
105
Peter Collingbourne6f4be192013-05-08 14:43:49 +0000106uptr internal_dup2(int oldfd, int newfd) {
Alexey Samsonovca2b5d72012-06-06 07:30:33 +0000107 return dup2(oldfd, newfd);
108}
109
Alexey Samsonovf6d21252012-09-05 14:48:24 +0000110uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
111 return readlink(path, buf, bufsize);
112}
113
Kuba Breckac52f3002014-12-29 02:18:59 +0000114uptr internal_unlink(const char *path) {
115 return unlink(path);
116}
117
Peter Collingbourne6f4be192013-05-08 14:43:49 +0000118uptr internal_sched_yield() {
Alexey Samsonov58a3c582012-06-18 08:44:30 +0000119 return sched_yield();
120}
121
Alexey Samsonovaadd1f22013-02-20 13:54:32 +0000122void internal__exit(int exitcode) {
123 _exit(exitcode);
124}
125
Peter Collingbourneffaf2ea2013-05-17 16:56:53 +0000126uptr internal_getpid() {
127 return getpid();
128}
129
Alexander Potapenko789e3e12014-01-31 13:10:07 +0000130int internal_sigaction(int signum, const void *act, void *oldact) {
131 return sigaction(signum,
132 (struct sigaction *)act, (struct sigaction *)oldact);
133}
134
Alexander Potapenko4a6cac42014-05-13 16:17:54 +0000135int internal_fork() {
136 // TODO(glider): this may call user's pthread_atfork() handlers which is bad.
137 return fork();
138}
139
Evgeniy Stepanov567e5162014-05-27 12:37:52 +0000140uptr internal_rename(const char *oldpath, const char *newpath) {
141 return rename(oldpath, newpath);
142}
143
144uptr internal_ftruncate(fd_t fd, uptr size) {
145 return ftruncate(fd, size);
146}
147
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000148// ----------------- sanitizer_common.h
Alexey Samsonovae9b18b2012-11-09 14:45:30 +0000149bool FileExists(const char *filename) {
150 struct stat st;
151 if (stat(filename, &st))
152 return false;
153 // Sanity check: filename is a regular file.
154 return S_ISREG(st.st_mode);
155}
156
Dmitry Vyukov56faa552012-10-02 12:58:14 +0000157uptr GetTid() {
158 return reinterpret_cast<uptr>(pthread_self());
159}
160
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +0000161void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000162 uptr *stack_bottom) {
163 CHECK(stack_top);
164 CHECK(stack_bottom);
165 uptr stacksize = pthread_get_stacksize_np(pthread_self());
Alexander Potapenkof6ff6b02014-02-03 16:42:29 +0000166 // pthread_get_stacksize_np() returns an incorrect stack size for the main
167 // thread on Mavericks. See
168 // https://code.google.com/p/address-sanitizer/issues/detail?id=261
Kuba Brecka0078cea72014-11-05 18:55:38 +0000169 if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
Alexander Potapenkof6ff6b02014-02-03 16:42:29 +0000170 stacksize == (1 << 19)) {
171 struct rlimit rl;
172 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
173 // Most often rl.rlim_cur will be the desired 8M.
174 if (rl.rlim_cur < kMaxThreadStackSize) {
175 stacksize = rl.rlim_cur;
176 } else {
177 stacksize = kMaxThreadStackSize;
178 }
179 }
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000180 void *stackaddr = pthread_get_stackaddr_np(pthread_self());
181 *stack_top = (uptr)stackaddr;
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +0000182 *stack_bottom = *stack_top - stacksize;
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000183}
184
Alexey Samsonov0c53a382012-06-14 14:07:21 +0000185const char *GetEnv(const char *name) {
186 char ***env_ptr = _NSGetEnviron();
Alexander Potapenkofa82ba92013-11-13 13:34:53 +0000187 if (!env_ptr) {
188 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
189 "called after libSystem_initializer().\n");
190 CHECK(env_ptr);
191 }
Alexey Samsonov0c53a382012-06-14 14:07:21 +0000192 char **environ = *env_ptr;
193 CHECK(environ);
194 uptr name_len = internal_strlen(name);
195 while (*environ != 0) {
196 uptr len = internal_strlen(*environ);
197 if (len > name_len) {
198 const char *p = *environ;
199 if (!internal_memcmp(p, name, name_len) &&
200 p[name_len] == '=') { // Match.
201 return *environ + name_len + 1; // String starting after =.
202 }
203 }
204 environ++;
205 }
206 return 0;
207}
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000208
Anna Zaks22490492015-02-27 03:12:19 +0000209uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
210 CHECK_LE(kMaxPathLength, buf_len);
211
212 // On OS X the executable path is saved to the stack by dyld. Reading it
213 // from there is much faster than calling dladdr, especially for large
214 // binaries with symbols.
215 InternalScopedString exe_path(kMaxPathLength);
216 uint32_t size = exe_path.size();
217 if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
218 realpath(exe_path.data(), buf) != 0) {
219 return internal_strlen(buf);
220 }
221 return 0;
222}
223
Alexey Samsonov97ca3062012-09-17 09:12:39 +0000224void ReExec() {
225 UNIMPLEMENTED();
226}
227
Peter Collingbourneb69b8a42013-05-20 17:05:29 +0000228uptr GetPageSize() {
229 return sysconf(_SC_PAGESIZE);
230}
231
Alexey Samsonova097f7b2013-03-14 13:30:56 +0000232BlockingMutex::BlockingMutex() {
233 internal_memset(this, 0, sizeof(*this));
234}
235
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000236void BlockingMutex::Lock() {
237 CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
Kostya Serebryany459df6f2013-02-26 12:59:06 +0000238 CHECK_EQ(OS_SPINLOCK_INIT, 0);
239 CHECK_NE(owner_, (uptr)pthread_self());
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000240 OSSpinLockLock((OSSpinLock*)&opaque_storage_);
241 CHECK(!owner_);
242 owner_ = (uptr)pthread_self();
243}
244
245void BlockingMutex::Unlock() {
246 CHECK(owner_ == (uptr)pthread_self());
247 owner_ = 0;
248 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
249}
250
Alexey Samsonovdb7d9652013-03-11 15:45:20 +0000251void BlockingMutex::CheckLocked() {
252 CHECK_EQ((uptr)pthread_self(), owner_);
253}
254
Dmitry Vyukovc9e304a2013-06-06 13:00:32 +0000255u64 NanoTime() {
256 return 0;
257}
258
Evgeniy Stepanov5697b582013-03-13 08:19:53 +0000259uptr GetTlsSize() {
260 return 0;
261}
262
263void InitTlsSize() {
264}
265
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000266void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
267 uptr *tls_addr, uptr *tls_size) {
Dmitry Vyukovce0247c2013-06-06 13:20:40 +0000268#ifndef SANITIZER_GO
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000269 uptr stack_top, stack_bottom;
270 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
271 *stk_addr = stack_bottom;
272 *stk_size = stack_top - stack_bottom;
273 *tls_addr = 0;
274 *tls_size = 0;
Dmitry Vyukovce0247c2013-06-06 13:20:40 +0000275#else
276 *stk_addr = 0;
277 *stk_size = 0;
278 *tls_addr = 0;
279 *tls_size = 0;
280#endif
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000281}
282
Alexey Samsonov7a36e612013-09-10 14:36:16 +0000283uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
284 string_predicate_t filter) {
285 MemoryMappingLayout memory_mapping(false);
Alexey Samsonov64ffa592013-12-25 08:39:38 +0000286 return memory_mapping.DumpListOfModules(modules, max_modules, filter);
Alexey Samsonov7a36e612013-09-10 14:36:16 +0000287}
288
Alexander Potapenko789e3e12014-01-31 13:10:07 +0000289bool IsDeadlySignal(int signum) {
290 return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
291}
292
Alexander Potapenko768e3152014-02-03 15:32:19 +0000293MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
294
295MacosVersion GetMacosVersionInternal() {
296 int mib[2] = { CTL_KERN, KERN_OSRELEASE };
297 char version[100];
298 uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]);
299 for (uptr i = 0; i < maxlen; i++) version[i] = '\0';
300 // Get the version length.
301 CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1);
302 CHECK_LT(len, maxlen);
303 CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1);
304 switch (version[0]) {
305 case '9': return MACOS_VERSION_LEOPARD;
306 case '1': {
307 switch (version[1]) {
308 case '0': return MACOS_VERSION_SNOW_LEOPARD;
309 case '1': return MACOS_VERSION_LION;
310 case '2': return MACOS_VERSION_MOUNTAIN_LION;
311 case '3': return MACOS_VERSION_MAVERICKS;
Kuba Breckaf4bdbde2014-11-05 18:53:22 +0000312 case '4': return MACOS_VERSION_YOSEMITE;
Kuba Brecka731089b2014-12-16 04:46:15 +0000313 default:
314 if (IsDigit(version[1]))
315 return MACOS_VERSION_UNKNOWN_NEWER;
316 else
317 return MACOS_VERSION_UNKNOWN;
Alexander Potapenko768e3152014-02-03 15:32:19 +0000318 }
319 }
320 default: return MACOS_VERSION_UNKNOWN;
321 }
322}
323
324MacosVersion GetMacosVersion() {
325 atomic_uint32_t *cache =
326 reinterpret_cast<atomic_uint32_t*>(&cached_macos_version);
327 MacosVersion result =
328 static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire));
329 if (result == MACOS_VERSION_UNINITIALIZED) {
330 result = GetMacosVersionInternal();
331 atomic_store(cache, result, memory_order_release);
332 }
333 return result;
334}
335
Kostya Serebryany6c54a6b2014-12-09 01:22:59 +0000336uptr GetRSS() {
Ismail Pazarbasib981dc82015-05-12 20:47:21 +0000337 struct task_basic_info info;
338 unsigned count = TASK_BASIC_INFO_COUNT;
339 kern_return_t result =
340 task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count);
341 if (UNLIKELY(result != KERN_SUCCESS)) {
342 Report("Cannot get task info. Error: %d\n", result);
343 Die();
344 }
345 return info.resident_size;
Kostya Serebryany6c54a6b2014-12-09 01:22:59 +0000346}
347
Kostya Serebryany43eb7732014-12-16 19:13:01 +0000348void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
Kostya Serebryany5f5bc4a2014-12-16 21:06:07 +0000349void internal_join_thread(void *th) { }
Kostya Serebryany43eb7732014-12-16 19:13:01 +0000350
Dmitry Vyukovb79ac882015-03-02 17:36:02 +0000351void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
352 ucontext_t *ucontext = (ucontext_t*)context;
353# if SANITIZER_WORDSIZE == 64
354 *pc = ucontext->uc_mcontext->__ss.__rip;
355 *bp = ucontext->uc_mcontext->__ss.__rbp;
356 *sp = ucontext->uc_mcontext->__ss.__rsp;
357# else
358 *pc = ucontext->uc_mcontext->__ss.__eip;
359 *bp = ucontext->uc_mcontext->__ss.__ebp;
360 *sp = ucontext->uc_mcontext->__ss.__esp;
361# endif // SANITIZER_WORDSIZE
362}
363
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +0000364} // namespace __sanitizer
365
Alexey Samsonova0e28a72013-04-03 07:24:35 +0000366#endif // SANITIZER_MAC