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