sanitizer_posix.cc revision 821acfaccc7d11b987e2882b022e8d167b0c8a54
1//===-- sanitizer_posix.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 POSIX-specific functions from 12// sanitizer_libc.h. 13//===----------------------------------------------------------------------===// 14 15#include "sanitizer_platform.h" 16#if SANITIZER_LINUX || SANITIZER_MAC 17 18#include "sanitizer_common.h" 19#include "sanitizer_libc.h" 20#include "sanitizer_procmaps.h" 21#include "sanitizer_stacktrace.h" 22 23#include <sys/mman.h> 24 25namespace __sanitizer { 26 27// ------------- sanitizer_common.h 28uptr GetMmapGranularity() { 29 return GetPageSize(); 30} 31 32uptr GetMaxVirtualAddress() { 33#if SANITIZER_WORDSIZE == 64 34# if defined(__powerpc64__) 35 // On PowerPC64 we have two different address space layouts: 44- and 46-bit. 36 // We somehow need to figure our which one we are using now and choose 37 // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. 38 // Note that with 'ulimit -s unlimited' the stack is moved away from the top 39 // of the address space, so simply checking the stack address is not enough. 40 return (1ULL << 44) - 1; // 0x00000fffffffffffUL 41# else 42 return (1ULL << 47) - 1; // 0x00007fffffffffffUL; 43# endif 44#else // SANITIZER_WORDSIZE == 32 45 // FIXME: We can probably lower this on Android? 46 return (1ULL << 32) - 1; // 0xffffffff; 47#endif // SANITIZER_WORDSIZE 48} 49 50void *MmapOrDie(uptr size, const char *mem_type) { 51 size = RoundUpTo(size, GetPageSizeCached()); 52 uptr res = internal_mmap(0, size, 53 PROT_READ | PROT_WRITE, 54 MAP_PRIVATE | MAP_ANON, -1, 0); 55 int reserrno; 56 if (internal_iserror(res, &reserrno)) { 57 static int recursion_count; 58 if (recursion_count) { 59 // The Report() and CHECK calls below may call mmap recursively and fail. 60 // If we went into recursion, just die. 61 RawWrite("ERROR: Failed to mmap\n"); 62 Die(); 63 } 64 recursion_count++; 65 Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n", 66 SanitizerToolName, size, size, mem_type, reserrno); 67 DumpProcessMap(); 68 CHECK("unable to mmap" && 0); 69 } 70 return (void *)res; 71} 72 73void UnmapOrDie(void *addr, uptr size) { 74 if (!addr || !size) return; 75 uptr res = internal_munmap(addr, size); 76 if (internal_iserror(res)) { 77 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", 78 SanitizerToolName, size, size, addr); 79 CHECK("unable to unmap" && 0); 80 } 81} 82 83void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { 84 uptr PageSize = GetPageSizeCached(); 85 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 86 RoundUpTo(size, PageSize), 87 PROT_READ | PROT_WRITE, 88 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 89 -1, 0); 90 int reserrno; 91 if (internal_iserror(p, &reserrno)) 92 Report("ERROR: " 93 "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n", 94 SanitizerToolName, size, size, fixed_addr, reserrno); 95 return (void *)p; 96} 97 98void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 99 uptr PageSize = GetPageSizeCached(); 100 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 101 RoundUpTo(size, PageSize), 102 PROT_READ | PROT_WRITE, 103 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 104 -1, 0); 105 int reserrno; 106 if (internal_iserror(p, &reserrno)) { 107 Report("ERROR:" 108 " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n", 109 SanitizerToolName, size, size, fixed_addr, reserrno); 110 CHECK("unable to mmap" && 0); 111 } 112 return (void *)p; 113} 114 115void *Mprotect(uptr fixed_addr, uptr size) { 116 return (void *)internal_mmap((void*)fixed_addr, size, 117 PROT_NONE, 118 MAP_PRIVATE | MAP_ANON | MAP_FIXED | 119 MAP_NORESERVE, -1, 0); 120} 121 122void *MapFileToMemory(const char *file_name, uptr *buff_size) { 123 uptr openrv = OpenFile(file_name, false); 124 CHECK(!internal_iserror(openrv)); 125 fd_t fd = openrv; 126 uptr fsize = internal_filesize(fd); 127 CHECK_NE(fsize, (uptr)-1); 128 CHECK_GT(fsize, 0); 129 *buff_size = RoundUpTo(fsize, GetPageSizeCached()); 130 uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); 131 return internal_iserror(map) ? 0 : (void *)map; 132} 133 134 135static inline bool IntervalsAreSeparate(uptr start1, uptr end1, 136 uptr start2, uptr end2) { 137 CHECK(start1 <= end1); 138 CHECK(start2 <= end2); 139 return (end1 < start2) || (end2 < start1); 140} 141 142// FIXME: this is thread-unsafe, but should not cause problems most of the time. 143// When the shadow is mapped only a single thread usually exists (plus maybe 144// several worker threads on Mac, which aren't expected to map big chunks of 145// memory). 146bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 147 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 148 uptr start, end; 149 while (proc_maps.Next(&start, &end, 150 /*offset*/0, /*filename*/0, /*filename_size*/0, 151 /*protection*/0)) { 152 if (!IntervalsAreSeparate(start, end, range_start, range_end)) 153 return false; 154 } 155 return true; 156} 157 158void DumpProcessMap() { 159 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 160 uptr start, end; 161 const sptr kBufSize = 4095; 162 char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__); 163 Report("Process memory map follows:\n"); 164 while (proc_maps.Next(&start, &end, /* file_offset */0, 165 filename, kBufSize, /* protection */0)) { 166 Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); 167 } 168 Report("End of process memory map.\n"); 169 UnmapOrDie(filename, kBufSize); 170} 171 172const char *GetPwd() { 173 return GetEnv("PWD"); 174} 175 176char *FindPathToBinary(const char *name) { 177 const char *path = GetEnv("PATH"); 178 if (!path) 179 return 0; 180 uptr name_len = internal_strlen(name); 181 InternalScopedBuffer<char> buffer(kMaxPathLength); 182 const char *beg = path; 183 while (true) { 184 const char *end = internal_strchrnul(beg, ':'); 185 uptr prefix_len = end - beg; 186 if (prefix_len + name_len + 2 <= kMaxPathLength) { 187 internal_memcpy(buffer.data(), beg, prefix_len); 188 buffer[prefix_len] = '/'; 189 internal_memcpy(&buffer[prefix_len + 1], name, name_len); 190 buffer[prefix_len + 1 + name_len] = '\0'; 191 if (FileExists(buffer.data())) 192 return internal_strdup(buffer.data()); 193 } 194 if (*end == '\0') break; 195 beg = end + 1; 196 } 197 return 0; 198} 199 200void MaybeOpenReportFile() { 201 if (!log_to_file || (report_fd_pid == internal_getpid())) return; 202 InternalScopedBuffer<char> report_path_full(4096); 203 internal_snprintf(report_path_full.data(), report_path_full.size(), 204 "%s.%d", report_path_prefix, internal_getpid()); 205 uptr openrv = OpenFile(report_path_full.data(), true); 206 if (internal_iserror(openrv)) { 207 report_fd = kStderrFd; 208 log_to_file = false; 209 Report("ERROR: Can't open file: %s\n", report_path_full.data()); 210 Die(); 211 } 212 if (report_fd != kInvalidFd) { 213 // We're in the child. Close the parent's log. 214 internal_close(report_fd); 215 } 216 report_fd = openrv; 217 report_fd_pid = internal_getpid(); 218} 219 220void RawWrite(const char *buffer) { 221 static const char *kRawWriteError = 222 "RawWrite can't output requested buffer!\n"; 223 uptr length = (uptr)internal_strlen(buffer); 224 MaybeOpenReportFile(); 225 if (length != internal_write(report_fd, buffer, length)) { 226 internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError)); 227 Die(); 228 } 229} 230 231bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { 232 uptr s, e, off, prot; 233 InternalMmapVector<char> fn(4096); 234 fn.push_back(0); 235 MemoryMappingLayout proc_maps(/*cache_enabled*/false); 236 while (proc_maps.Next(&s, &e, &off, &fn[0], fn.capacity(), &prot)) { 237 if ((prot & MemoryMappingLayout::kProtectionExecute) != 0 238 && internal_strcmp(module, &fn[0]) == 0) { 239 *start = s; 240 *end = e; 241 return true; 242 } 243 } 244 return false; 245} 246 247} // namespace __sanitizer 248 249#endif // SANITIZER_LINUX || SANITIZER_MAC 250