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