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 25 namespace __sanitizer { 26 27 // ------------- sanitizer_common.h 28 uptr GetMmapGranularity() { 29 return GetPageSize(); 30 } 31 32 uptr 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 50 void *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 73 void 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 83 void *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 98 void *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 115 void *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 122 void *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 135 static 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). 146 bool 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 158 void 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 172 const char *GetPwd() { 173 return GetEnv("PWD"); 174 } 175 176 } // namespace __sanitizer 177 178 #endif // SANITIZER_LINUX || SANITIZER_MAC 179