sanitizer_mac.cc revision 48526014de78e21f7ed027a60670016bc7f5d292
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 AddressSanitizer and ThreadSanitizer
11// run-time libraries and implements mac-specific functions from
12// sanitizer_libc.h.
13//===----------------------------------------------------------------------===//
14
15#ifdef __APPLE__
16
17#include "sanitizer_common.h"
18#include "sanitizer_internal_defs.h"
19#include "sanitizer_libc.h"
20#include "sanitizer_procmaps.h"
21
22#include <crt_externs.h>  // for _NSGetEnviron
23#include <fcntl.h>
24#include <mach-o/dyld.h>
25#include <mach-o/loader.h>
26#include <pthread.h>
27#include <sched.h>
28#include <sys/mman.h>
29#include <sys/resource.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <unistd.h>
33#include <libkern/OSAtomic.h>
34
35namespace __sanitizer {
36
37// ---------------------- sanitizer_libc.h
38void *internal_mmap(void *addr, size_t length, int prot, int flags,
39                    int fd, u64 offset) {
40  return mmap(addr, length, prot, flags, fd, offset);
41}
42
43int internal_munmap(void *addr, uptr length) {
44  return munmap(addr, length);
45}
46
47int internal_close(fd_t fd) {
48  return close(fd);
49}
50
51fd_t internal_open(const char *filename, bool write) {
52  return open(filename,
53              write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
54}
55
56uptr internal_read(fd_t fd, void *buf, uptr count) {
57  return read(fd, buf, count);
58}
59
60uptr internal_write(fd_t fd, const void *buf, uptr count) {
61  return write(fd, buf, count);
62}
63
64uptr internal_filesize(fd_t fd) {
65  struct stat st;
66  if (fstat(fd, &st))
67    return -1;
68  return (uptr)st.st_size;
69}
70
71int internal_dup2(int oldfd, int newfd) {
72  return dup2(oldfd, newfd);
73}
74
75uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
76  return readlink(path, buf, bufsize);
77}
78
79int internal_sched_yield() {
80  return sched_yield();
81}
82
83// ----------------- sanitizer_common.h
84bool FileExists(const char *filename) {
85  struct stat st;
86  if (stat(filename, &st))
87    return false;
88  // Sanity check: filename is a regular file.
89  return S_ISREG(st.st_mode);
90}
91
92uptr GetTid() {
93  return reinterpret_cast<uptr>(pthread_self());
94}
95
96void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
97                                uptr *stack_bottom) {
98  CHECK(stack_top);
99  CHECK(stack_bottom);
100  uptr stacksize = pthread_get_stacksize_np(pthread_self());
101  void *stackaddr = pthread_get_stackaddr_np(pthread_self());
102  *stack_top = (uptr)stackaddr;
103  *stack_bottom = *stack_top - stacksize;
104}
105
106const char *GetEnv(const char *name) {
107  char ***env_ptr = _NSGetEnviron();
108  CHECK(env_ptr);
109  char **environ = *env_ptr;
110  CHECK(environ);
111  uptr name_len = internal_strlen(name);
112  while (*environ != 0) {
113    uptr len = internal_strlen(*environ);
114    if (len > name_len) {
115      const char *p = *environ;
116      if (!internal_memcmp(p, name, name_len) &&
117          p[name_len] == '=') {  // Match.
118        return *environ + name_len + 1;  // String starting after =.
119      }
120    }
121    environ++;
122  }
123  return 0;
124}
125
126void ReExec() {
127  UNIMPLEMENTED();
128}
129
130void PrepareForSandboxing() {
131  // Nothing here for now.
132}
133
134// ----------------- sanitizer_procmaps.h
135
136MemoryMappingLayout::MemoryMappingLayout() {
137  Reset();
138}
139
140MemoryMappingLayout::~MemoryMappingLayout() {
141}
142
143// More information about Mach-O headers can be found in mach-o/loader.h
144// Each Mach-O image has a header (mach_header or mach_header_64) starting with
145// a magic number, and a list of linker load commands directly following the
146// header.
147// A load command is at least two 32-bit words: the command type and the
148// command size in bytes. We're interested only in segment load commands
149// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
150// into the task's address space.
151// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
152// segment_command_64 correspond to the memory address, memory size and the
153// file offset of the current memory segment.
154// Because these fields are taken from the images as is, one needs to add
155// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
156
157void MemoryMappingLayout::Reset() {
158  // Count down from the top.
159  // TODO(glider): as per man 3 dyld, iterating over the headers with
160  // _dyld_image_count is thread-unsafe. We need to register callbacks for
161  // adding and removing images which will invalidate the MemoryMappingLayout
162  // state.
163  current_image_ = _dyld_image_count();
164  current_load_cmd_count_ = -1;
165  current_load_cmd_addr_ = 0;
166  current_magic_ = 0;
167  current_filetype_ = 0;
168}
169
170// static
171void MemoryMappingLayout::CacheMemoryMappings() {
172  // No-op on Mac for now.
173}
174
175void MemoryMappingLayout::LoadFromCache() {
176  // No-op on Mac for now.
177}
178
179// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
180// Google Perftools, http://code.google.com/p/google-perftools.
181
182// NextSegmentLoad scans the current image for the next segment load command
183// and returns the start and end addresses and file offset of the corresponding
184// segment.
185// Note that the segment addresses are not necessarily sorted.
186template<u32 kLCSegment, typename SegmentCommand>
187bool MemoryMappingLayout::NextSegmentLoad(
188    uptr *start, uptr *end, uptr *offset,
189    char filename[], uptr filename_size) {
190  const char* lc = current_load_cmd_addr_;
191  current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
192  if (((const load_command *)lc)->cmd == kLCSegment) {
193    const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
194    const SegmentCommand* sc = (const SegmentCommand *)lc;
195    if (start) *start = sc->vmaddr + dlloff;
196    if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
197    if (offset) {
198      if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
199        *offset = sc->vmaddr;
200      } else {
201        *offset = sc->fileoff;
202      }
203    }
204    if (filename) {
205      internal_strncpy(filename, _dyld_get_image_name(current_image_),
206                       filename_size);
207    }
208    return true;
209  }
210  return false;
211}
212
213bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
214                               char filename[], uptr filename_size) {
215  for (; current_image_ >= 0; current_image_--) {
216    const mach_header* hdr = _dyld_get_image_header(current_image_);
217    if (!hdr) continue;
218    if (current_load_cmd_count_ < 0) {
219      // Set up for this image;
220      current_load_cmd_count_ = hdr->ncmds;
221      current_magic_ = hdr->magic;
222      current_filetype_ = hdr->filetype;
223      switch (current_magic_) {
224#ifdef MH_MAGIC_64
225        case MH_MAGIC_64: {
226          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
227          break;
228        }
229#endif
230        case MH_MAGIC: {
231          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
232          break;
233        }
234        default: {
235          continue;
236        }
237      }
238    }
239
240    for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
241      switch (current_magic_) {
242        // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
243#ifdef MH_MAGIC_64
244        case MH_MAGIC_64: {
245          if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
246                  start, end, offset, filename, filename_size))
247            return true;
248          break;
249        }
250#endif
251        case MH_MAGIC: {
252          if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
253                  start, end, offset, filename, filename_size))
254            return true;
255          break;
256        }
257      }
258    }
259    // If we get here, no more load_cmd's in this image talk about
260    // segments.  Go on to the next image.
261  }
262  return false;
263}
264
265bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
266                                                 char filename[],
267                                                 uptr filename_size) {
268  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
269}
270
271BlockingMutex::BlockingMutex(LinkerInitialized) {
272  // We assume that OS_SPINLOCK_INIT is zero
273}
274
275void BlockingMutex::Lock() {
276  CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
277  CHECK(OS_SPINLOCK_INIT == 0);
278  CHECK(owner_ != (uptr)pthread_self());
279  OSSpinLockLock((OSSpinLock*)&opaque_storage_);
280  CHECK(!owner_);
281  owner_ = (uptr)pthread_self();
282}
283
284void BlockingMutex::Unlock() {
285  CHECK(owner_ == (uptr)pthread_self());
286  owner_ = 0;
287  OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
288}
289
290}  // namespace __sanitizer
291
292#endif  // __APPLE__
293