sanitizer_posix.cc revision 04a2281586c2dafaa523d4e8dc5488b52e44194e
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 32void *MmapOrDie(uptr size, const char *mem_type) { 33 size = RoundUpTo(size, GetPageSizeCached()); 34 uptr res = internal_mmap(0, size, 35 PROT_READ | PROT_WRITE, 36 MAP_PRIVATE | MAP_ANON, -1, 0); 37 int reserrno; 38 if (internal_iserror(res, &reserrno)) { 39 static int recursion_count; 40 if (recursion_count) { 41 // The Report() and CHECK calls below may call mmap recursively and fail. 42 // If we went into recursion, just die. 43 RawWrite("ERROR: Failed to mmap\n"); 44 Die(); 45 } 46 recursion_count++; 47 Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n", 48 SanitizerToolName, size, size, mem_type, reserrno); 49 DumpProcessMap(); 50 CHECK("unable to mmap" && 0); 51 } 52 return (void *)res; 53} 54 55void UnmapOrDie(void *addr, uptr size) { 56 if (!addr || !size) return; 57 uptr res = internal_munmap(addr, size); 58 if (internal_iserror(res)) { 59 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", 60 SanitizerToolName, size, size, addr); 61 CHECK("unable to unmap" && 0); 62 } 63} 64 65void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { 66 uptr PageSize = GetPageSizeCached(); 67 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 68 RoundUpTo(size, PageSize), 69 PROT_READ | PROT_WRITE, 70 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 71 -1, 0); 72 int reserrno; 73 if (internal_iserror(p, &reserrno)) 74 Report("ERROR: " 75 "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n", 76 SanitizerToolName, size, size, fixed_addr, reserrno); 77 return (void *)p; 78} 79 80void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 81 uptr PageSize = GetPageSizeCached(); 82 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 83 RoundUpTo(size, PageSize), 84 PROT_READ | PROT_WRITE, 85 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 86 -1, 0); 87 int reserrno; 88 if (internal_iserror(p, &reserrno)) { 89 Report("ERROR:" 90 " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n", 91 SanitizerToolName, size, size, fixed_addr, reserrno); 92 CHECK("unable to mmap" && 0); 93 } 94 return (void *)p; 95} 96 97void *Mprotect(uptr fixed_addr, uptr size) { 98 return (void *)internal_mmap((void*)fixed_addr, size, 99 PROT_NONE, 100 MAP_PRIVATE | MAP_ANON | MAP_FIXED | 101 MAP_NORESERVE, -1, 0); 102} 103 104void *MapFileToMemory(const char *file_name, uptr *buff_size) { 105 uptr openrv = OpenFile(file_name, false); 106 CHECK(!internal_iserror(openrv)); 107 fd_t fd = openrv; 108 uptr fsize = internal_filesize(fd); 109 CHECK_NE(fsize, (uptr)-1); 110 CHECK_GT(fsize, 0); 111 *buff_size = RoundUpTo(fsize, GetPageSizeCached()); 112 uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); 113 return internal_iserror(map) ? 0 : (void *)map; 114} 115 116 117static inline bool IntervalsAreSeparate(uptr start1, uptr end1, 118 uptr start2, uptr end2) { 119 CHECK(start1 <= end1); 120 CHECK(start2 <= end2); 121 return (end1 < start2) || (end2 < start1); 122} 123 124// FIXME: this is thread-unsafe, but should not cause problems most of the time. 125// When the shadow is mapped only a single thread usually exists (plus maybe 126// several worker threads on Mac, which aren't expected to map big chunks of 127// memory). 128bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 129 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 130 uptr start, end; 131 while (proc_maps.Next(&start, &end, 132 /*offset*/0, /*filename*/0, /*filename_size*/0, 133 /*protection*/0)) { 134 if (!IntervalsAreSeparate(start, end, range_start, range_end)) 135 return false; 136 } 137 return true; 138} 139 140void DumpProcessMap() { 141 MemoryMappingLayout proc_maps(/*cache_enabled*/true); 142 uptr start, end; 143 const sptr kBufSize = 4095; 144 char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__); 145 Report("Process memory map follows:\n"); 146 while (proc_maps.Next(&start, &end, /* file_offset */0, 147 filename, kBufSize, /* protection */0)) { 148 Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); 149 } 150 Report("End of process memory map.\n"); 151 UnmapOrDie(filename, kBufSize); 152} 153 154const char *GetPwd() { 155 return GetEnv("PWD"); 156} 157 158} // namespace __sanitizer 159 160#endif // SANITIZER_LINUX || SANITIZER_MAC 161