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 
     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 
     34 namespace __sanitizer {
     35 
     36 // ---------------------- sanitizer_libc.h
     37 void *internal_mmap(void *addr, size_t length, int prot, int flags,
     38                     int fd, u64 offset) {
     39   return mmap(addr, length, prot, flags, fd, offset);
     40 }
     41 
     42 int internal_munmap(void *addr, uptr length) {
     43   return munmap(addr, length);
     44 }
     45 
     46 int internal_close(fd_t fd) {
     47   return close(fd);
     48 }
     49 
     50 fd_t internal_open(const char *filename, bool write) {
     51   return open(filename,
     52               write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
     53 }
     54 
     55 uptr internal_read(fd_t fd, void *buf, uptr count) {
     56   return read(fd, buf, count);
     57 }
     58 
     59 uptr internal_write(fd_t fd, const void *buf, uptr count) {
     60   return write(fd, buf, count);
     61 }
     62 
     63 uptr internal_filesize(fd_t fd) {
     64   struct stat st;
     65   if (fstat(fd, &st))
     66     return -1;
     67   return (uptr)st.st_size;
     68 }
     69 
     70 int internal_dup2(int oldfd, int newfd) {
     71   return dup2(oldfd, newfd);
     72 }
     73 
     74 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
     75   return readlink(path, buf, bufsize);
     76 }
     77 
     78 int internal_sched_yield() {
     79   return sched_yield();
     80 }
     81 
     82 // ----------------- sanitizer_common.h
     83 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
     84                                 uptr *stack_bottom) {
     85   CHECK(stack_top);
     86   CHECK(stack_bottom);
     87   uptr stacksize = pthread_get_stacksize_np(pthread_self());
     88   void *stackaddr = pthread_get_stackaddr_np(pthread_self());
     89   *stack_top = (uptr)stackaddr;
     90   *stack_bottom = *stack_top - stacksize;
     91 }
     92 
     93 const char *GetEnv(const char *name) {
     94   char ***env_ptr = _NSGetEnviron();
     95   CHECK(env_ptr);
     96   char **environ = *env_ptr;
     97   CHECK(environ);
     98   uptr name_len = internal_strlen(name);
     99   while (*environ != 0) {
    100     uptr len = internal_strlen(*environ);
    101     if (len > name_len) {
    102       const char *p = *environ;
    103       if (!internal_memcmp(p, name, name_len) &&
    104           p[name_len] == '=') {  // Match.
    105         return *environ + name_len + 1;  // String starting after =.
    106       }
    107     }
    108     environ++;
    109   }
    110   return 0;
    111 }
    112 
    113 // ----------------- sanitizer_procmaps.h
    114 
    115 MemoryMappingLayout::MemoryMappingLayout() {
    116   Reset();
    117 }
    118 
    119 MemoryMappingLayout::~MemoryMappingLayout() {
    120 }
    121 
    122 // More information about Mach-O headers can be found in mach-o/loader.h
    123 // Each Mach-O image has a header (mach_header or mach_header_64) starting with
    124 // a magic number, and a list of linker load commands directly following the
    125 // header.
    126 // A load command is at least two 32-bit words: the command type and the
    127 // command size in bytes. We're interested only in segment load commands
    128 // (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
    129 // into the task's address space.
    130 // The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
    131 // segment_command_64 correspond to the memory address, memory size and the
    132 // file offset of the current memory segment.
    133 // Because these fields are taken from the images as is, one needs to add
    134 // _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
    135 
    136 void MemoryMappingLayout::Reset() {
    137   // Count down from the top.
    138   // TODO(glider): as per man 3 dyld, iterating over the headers with
    139   // _dyld_image_count is thread-unsafe. We need to register callbacks for
    140   // adding and removing images which will invalidate the MemoryMappingLayout
    141   // state.
    142   current_image_ = _dyld_image_count();
    143   current_load_cmd_count_ = -1;
    144   current_load_cmd_addr_ = 0;
    145   current_magic_ = 0;
    146 }
    147 
    148 // Next and NextSegmentLoad were inspired by base/sysinfo.cc in
    149 // Google Perftools, http://code.google.com/p/google-perftools.
    150 
    151 // NextSegmentLoad scans the current image for the next segment load command
    152 // and returns the start and end addresses and file offset of the corresponding
    153 // segment.
    154 // Note that the segment addresses are not necessarily sorted.
    155 template<u32 kLCSegment, typename SegmentCommand>
    156 bool MemoryMappingLayout::NextSegmentLoad(
    157     uptr *start, uptr *end, uptr *offset,
    158     char filename[], uptr filename_size) {
    159   const char* lc = current_load_cmd_addr_;
    160   current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
    161   if (((const load_command *)lc)->cmd == kLCSegment) {
    162     const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
    163     const SegmentCommand* sc = (const SegmentCommand *)lc;
    164     if (start) *start = sc->vmaddr + dlloff;
    165     if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
    166     if (offset) *offset = sc->fileoff;
    167     if (filename) {
    168       internal_strncpy(filename, _dyld_get_image_name(current_image_),
    169                        filename_size);
    170     }
    171     return true;
    172   }
    173   return false;
    174 }
    175 
    176 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
    177                                char filename[], uptr filename_size) {
    178   for (; current_image_ >= 0; current_image_--) {
    179     const mach_header* hdr = _dyld_get_image_header(current_image_);
    180     if (!hdr) continue;
    181     if (current_load_cmd_count_ < 0) {
    182       // Set up for this image;
    183       current_load_cmd_count_ = hdr->ncmds;
    184       current_magic_ = hdr->magic;
    185       switch (current_magic_) {
    186 #ifdef MH_MAGIC_64
    187         case MH_MAGIC_64: {
    188           current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
    189           break;
    190         }
    191 #endif
    192         case MH_MAGIC: {
    193           current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
    194           break;
    195         }
    196         default: {
    197           continue;
    198         }
    199       }
    200     }
    201 
    202     for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
    203       switch (current_magic_) {
    204         // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
    205 #ifdef MH_MAGIC_64
    206         case MH_MAGIC_64: {
    207           if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
    208                   start, end, offset, filename, filename_size))
    209             return true;
    210           break;
    211         }
    212 #endif
    213         case MH_MAGIC: {
    214           if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
    215                   start, end, offset, filename, filename_size))
    216             return true;
    217           break;
    218         }
    219       }
    220     }
    221     // If we get here, no more load_cmd's in this image talk about
    222     // segments.  Go on to the next image.
    223   }
    224   return false;
    225 }
    226 
    227 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
    228                                                  char filename[],
    229                                                  uptr filename_size) {
    230   return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
    231 }
    232 
    233 }  // namespace __sanitizer
    234 
    235 #endif  // __APPLE__
    236