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