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