blob: 8134f894c60e07d50633a678fe0ecfb0a6ff42d7 [file] [log] [blame]
Alexey Samsonovae4d9ca2012-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//
10// This file is shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries and implements mac-specific functions from
12// sanitizer_libc.h.
13//===----------------------------------------------------------------------===//
14
Evgeniy Stepanov24e13722013-03-19 14:33:38 +000015#include "sanitizer_platform.h"
16#if SANITIZER_MAC
17
Alexander Potapenko2bf0d032013-02-06 14:41:15 +000018// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
19// the clients will most certainly use 64-bit ones as well.
20#ifndef _DARWIN_USE_64_BIT_INODE
21#define _DARWIN_USE_64_BIT_INODE 1
22#endif
23#include <stdio.h>
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000024
Alexey Samsonove5931fd2012-06-07 07:13:46 +000025#include "sanitizer_common.h"
Alexey Samsonov94b50362012-06-05 14:25:27 +000026#include "sanitizer_internal_defs.h"
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000027#include "sanitizer_libc.h"
Alexey Samsonov6895adc2012-06-07 06:15:12 +000028#include "sanitizer_procmaps.h"
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000029
Alexey Samsonov3dbeabb2012-06-14 14:07:21 +000030#include <crt_externs.h> // for _NSGetEnviron
Alexey Samsonove5931fd2012-06-07 07:13:46 +000031#include <fcntl.h>
Alexey Samsonov6895adc2012-06-07 06:15:12 +000032#include <mach-o/dyld.h>
33#include <mach-o/loader.h>
Alexey Samsonove5931fd2012-06-07 07:13:46 +000034#include <pthread.h>
Alexey Samsonov0969bcf2012-06-18 08:44:30 +000035#include <sched.h>
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000036#include <sys/mman.h>
Alexey Samsonove5931fd2012-06-07 07:13:46 +000037#include <sys/resource.h>
Alexey Samsonovc5d46512012-06-05 07:05:10 +000038#include <sys/stat.h>
39#include <sys/types.h>
Alexey Samsonova56aefd2012-06-05 08:32:53 +000040#include <unistd.h>
Dmitry Vyukov48526012013-01-14 08:01:58 +000041#include <libkern/OSAtomic.h>
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000042
43namespace __sanitizer {
44
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000045#include "sanitizer_syscall_generic.inc"
46
Alexey Samsonove5931fd2012-06-07 07:13:46 +000047// ---------------------- sanitizer_libc.h
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000048void *internal_mmap(void *addr, size_t length, int prot, int flags,
49 int fd, u64 offset) {
50 return mmap(addr, length, prot, flags, fd, offset);
51}
52
Alexey Samsonov1f11d312012-06-05 09:49:25 +000053int internal_munmap(void *addr, uptr length) {
54 return munmap(addr, length);
55}
56
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000057uptr internal_close(fd_t fd) {
Alexey Samsonova56aefd2012-06-05 08:32:53 +000058 return close(fd);
59}
60
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000061uptr internal_open(const char *filename, int flags) {
Alexey Samsonovee7cc442013-02-01 15:58:46 +000062 return open(filename, flags);
63}
64
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000065uptr internal_open(const char *filename, int flags, u32 mode) {
Alexey Samsonovee7cc442013-02-01 15:58:46 +000066 return open(filename, flags, mode);
67}
68
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000069uptr OpenFile(const char *filename, bool write) {
Alexey Samsonovee7cc442013-02-01 15:58:46 +000070 return internal_open(filename,
71 write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
Alexey Samsonovc5d46512012-06-05 07:05:10 +000072}
73
Alexey Samsonova56aefd2012-06-05 08:32:53 +000074uptr internal_read(fd_t fd, void *buf, uptr count) {
75 return read(fd, buf, count);
76}
77
78uptr internal_write(fd_t fd, const void *buf, uptr count) {
79 return write(fd, buf, count);
80}
81
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000082uptr internal_stat(const char *path, void *buf) {
Alexey Samsonov7c50ee72013-02-04 10:31:39 +000083 return stat(path, (struct stat *)buf);
Alexey Samsonov4c9317a2013-02-04 10:16:50 +000084}
85
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000086uptr internal_lstat(const char *path, void *buf) {
Alexey Samsonov7c50ee72013-02-04 10:31:39 +000087 return lstat(path, (struct stat *)buf);
Alexey Samsonov4c9317a2013-02-04 10:16:50 +000088}
89
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000090uptr internal_fstat(fd_t fd, void *buf) {
Alexey Samsonov7c50ee72013-02-04 10:31:39 +000091 return fstat(fd, (struct stat *)buf);
Alexey Samsonov4c9317a2013-02-04 10:16:50 +000092}
93
Alexey Samsonov8e820fc2012-06-06 07:30:33 +000094uptr internal_filesize(fd_t fd) {
Alexey Samsonov668accc2012-08-02 10:09:31 +000095 struct stat st;
Alexey Samsonov4c9317a2013-02-04 10:16:50 +000096 if (internal_fstat(fd, &st))
Alexey Samsonov8e820fc2012-06-06 07:30:33 +000097 return -1;
98 return (uptr)st.st_size;
99}
100
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000101uptr internal_dup2(int oldfd, int newfd) {
Alexey Samsonov8e820fc2012-06-06 07:30:33 +0000102 return dup2(oldfd, newfd);
103}
104
Alexey Samsonovd1b8f582012-09-05 14:48:24 +0000105uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
106 return readlink(path, buf, bufsize);
107}
108
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000109uptr internal_sched_yield() {
Alexey Samsonov0969bcf2012-06-18 08:44:30 +0000110 return sched_yield();
111}
112
Alexey Samsonovf8822472013-02-20 13:54:32 +0000113void internal__exit(int exitcode) {
114 _exit(exitcode);
115}
116
Alexey Samsonove5931fd2012-06-07 07:13:46 +0000117// ----------------- sanitizer_common.h
Alexey Samsonov93b4caf2012-11-09 14:45:30 +0000118bool FileExists(const char *filename) {
119 struct stat st;
120 if (stat(filename, &st))
121 return false;
122 // Sanity check: filename is a regular file.
123 return S_ISREG(st.st_mode);
124}
125
Dmitry Vyukove0023f72012-10-02 12:58:14 +0000126uptr GetTid() {
127 return reinterpret_cast<uptr>(pthread_self());
128}
129
Alexey Samsonoved996f72012-06-07 07:32:00 +0000130void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
Alexey Samsonove5931fd2012-06-07 07:13:46 +0000131 uptr *stack_bottom) {
132 CHECK(stack_top);
133 CHECK(stack_bottom);
134 uptr stacksize = pthread_get_stacksize_np(pthread_self());
135 void *stackaddr = pthread_get_stackaddr_np(pthread_self());
136 *stack_top = (uptr)stackaddr;
Alexey Samsonoved996f72012-06-07 07:32:00 +0000137 *stack_bottom = *stack_top - stacksize;
Alexey Samsonove5931fd2012-06-07 07:13:46 +0000138}
139
Alexey Samsonov3dbeabb2012-06-14 14:07:21 +0000140const char *GetEnv(const char *name) {
141 char ***env_ptr = _NSGetEnviron();
142 CHECK(env_ptr);
143 char **environ = *env_ptr;
144 CHECK(environ);
145 uptr name_len = internal_strlen(name);
146 while (*environ != 0) {
147 uptr len = internal_strlen(*environ);
148 if (len > name_len) {
149 const char *p = *environ;
150 if (!internal_memcmp(p, name, name_len) &&
151 p[name_len] == '=') { // Match.
152 return *environ + name_len + 1; // String starting after =.
153 }
154 }
155 environ++;
156 }
157 return 0;
158}
Alexey Samsonove5931fd2012-06-07 07:13:46 +0000159
Alexey Samsonovd7e5bb42012-09-17 09:12:39 +0000160void ReExec() {
161 UNIMPLEMENTED();
162}
163
Alexander Potapenko25742572012-12-10 13:10:40 +0000164void PrepareForSandboxing() {
165 // Nothing here for now.
166}
167
Alexey Samsonove5931fd2012-06-07 07:13:46 +0000168// ----------------- sanitizer_procmaps.h
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000169
Alexander Potapenko9ae28832013-03-26 10:34:37 +0000170MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000171 Reset();
172}
173
Alexey Samsonove1f5dac2012-08-27 13:48:48 +0000174MemoryMappingLayout::~MemoryMappingLayout() {
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000175}
176
177// More information about Mach-O headers can be found in mach-o/loader.h
178// Each Mach-O image has a header (mach_header or mach_header_64) starting with
179// a magic number, and a list of linker load commands directly following the
180// header.
181// A load command is at least two 32-bit words: the command type and the
182// command size in bytes. We're interested only in segment load commands
183// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
184// into the task's address space.
185// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
186// segment_command_64 correspond to the memory address, memory size and the
187// file offset of the current memory segment.
188// Because these fields are taken from the images as is, one needs to add
189// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
190
Alexey Samsonove1f5dac2012-08-27 13:48:48 +0000191void MemoryMappingLayout::Reset() {
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000192 // Count down from the top.
193 // TODO(glider): as per man 3 dyld, iterating over the headers with
194 // _dyld_image_count is thread-unsafe. We need to register callbacks for
Alexey Samsonove1f5dac2012-08-27 13:48:48 +0000195 // adding and removing images which will invalidate the MemoryMappingLayout
196 // state.
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000197 current_image_ = _dyld_image_count();
198 current_load_cmd_count_ = -1;
199 current_load_cmd_addr_ = 0;
200 current_magic_ = 0;
Alexander Potapenko8bf8b792012-10-02 15:42:24 +0000201 current_filetype_ = 0;
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000202}
203
Alexander Potapenko93da8b62012-12-01 02:39:45 +0000204// static
205void MemoryMappingLayout::CacheMemoryMappings() {
206 // No-op on Mac for now.
207}
208
209void MemoryMappingLayout::LoadFromCache() {
210 // No-op on Mac for now.
211}
212
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000213// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
214// Google Perftools, http://code.google.com/p/google-perftools.
215
216// NextSegmentLoad scans the current image for the next segment load command
217// and returns the start and end addresses and file offset of the corresponding
218// segment.
219// Note that the segment addresses are not necessarily sorted.
220template<u32 kLCSegment, typename SegmentCommand>
Alexey Samsonove1f5dac2012-08-27 13:48:48 +0000221bool MemoryMappingLayout::NextSegmentLoad(
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000222 uptr *start, uptr *end, uptr *offset,
Alexey Samsonov45717c92013-03-13 06:51:02 +0000223 char filename[], uptr filename_size, uptr *protection) {
224 if (protection)
225 UNIMPLEMENTED();
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000226 const char* lc = current_load_cmd_addr_;
227 current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
228 if (((const load_command *)lc)->cmd == kLCSegment) {
229 const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
230 const SegmentCommand* sc = (const SegmentCommand *)lc;
231 if (start) *start = sc->vmaddr + dlloff;
232 if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
Alexander Potapenko8bf8b792012-10-02 15:42:24 +0000233 if (offset) {
234 if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
235 *offset = sc->vmaddr;
236 } else {
237 *offset = sc->fileoff;
238 }
239 }
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000240 if (filename) {
241 internal_strncpy(filename, _dyld_get_image_name(current_image_),
242 filename_size);
243 }
244 return true;
245 }
246 return false;
247}
248
Alexey Samsonove1f5dac2012-08-27 13:48:48 +0000249bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
Alexey Samsonov4a1a4952013-03-13 07:39:25 +0000250 char filename[], uptr filename_size,
251 uptr *protection) {
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000252 for (; current_image_ >= 0; current_image_--) {
253 const mach_header* hdr = _dyld_get_image_header(current_image_);
254 if (!hdr) continue;
255 if (current_load_cmd_count_ < 0) {
256 // Set up for this image;
257 current_load_cmd_count_ = hdr->ncmds;
258 current_magic_ = hdr->magic;
Alexander Potapenko8bf8b792012-10-02 15:42:24 +0000259 current_filetype_ = hdr->filetype;
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000260 switch (current_magic_) {
261#ifdef MH_MAGIC_64
262 case MH_MAGIC_64: {
263 current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
264 break;
265 }
266#endif
267 case MH_MAGIC: {
268 current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
269 break;
270 }
271 default: {
272 continue;
273 }
274 }
275 }
276
277 for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
278 switch (current_magic_) {
279 // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
280#ifdef MH_MAGIC_64
281 case MH_MAGIC_64: {
282 if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
Alexey Samsonov4a1a4952013-03-13 07:39:25 +0000283 start, end, offset, filename, filename_size, protection))
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000284 return true;
285 break;
286 }
287#endif
288 case MH_MAGIC: {
289 if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
Alexey Samsonov4a1a4952013-03-13 07:39:25 +0000290 start, end, offset, filename, filename_size, protection))
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000291 return true;
292 break;
293 }
294 }
295 }
296 // If we get here, no more load_cmd's in this image talk about
297 // segments. Go on to the next image.
298 }
299 return false;
300}
301
Alexey Samsonove1f5dac2012-08-27 13:48:48 +0000302bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
303 char filename[],
Alexey Samsonov4a1a4952013-03-13 07:39:25 +0000304 uptr filename_size,
Alexey Samsonov45717c92013-03-13 06:51:02 +0000305 uptr *protection) {
306 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
307 protection);
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000308}
309
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000310BlockingMutex::BlockingMutex(LinkerInitialized) {
311 // We assume that OS_SPINLOCK_INIT is zero
312}
313
Alexey Samsonov93af5942013-03-14 13:30:56 +0000314BlockingMutex::BlockingMutex() {
315 internal_memset(this, 0, sizeof(*this));
316}
317
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000318void BlockingMutex::Lock() {
319 CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
Kostya Serebryanyf155fcc2013-02-26 12:59:06 +0000320 CHECK_EQ(OS_SPINLOCK_INIT, 0);
321 CHECK_NE(owner_, (uptr)pthread_self());
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000322 OSSpinLockLock((OSSpinLock*)&opaque_storage_);
323 CHECK(!owner_);
324 owner_ = (uptr)pthread_self();
325}
326
327void BlockingMutex::Unlock() {
328 CHECK(owner_ == (uptr)pthread_self());
329 owner_ = 0;
330 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
331}
332
Alexey Samsonovce700972013-03-11 15:45:20 +0000333void BlockingMutex::CheckLocked() {
334 CHECK_EQ((uptr)pthread_self(), owner_);
335}
336
Evgeniy Stepanovb114ed82013-03-13 08:19:53 +0000337uptr GetTlsSize() {
338 return 0;
339}
340
341void InitTlsSize() {
342}
343
Sergey Matveev24323de2013-05-07 14:41:43 +0000344void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
345 uptr *tls_addr, uptr *tls_size) {
346 uptr stack_top, stack_bottom;
347 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
348 *stk_addr = stack_bottom;
349 *stk_size = stack_top - stack_bottom;
350 *tls_addr = 0;
351 *tls_size = 0;
352}
353
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +0000354} // namespace __sanitizer
355
Alexey Samsonov46f93952013-04-03 07:24:35 +0000356#endif // SANITIZER_MAC