sanitizer_posix.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
11f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//===-- sanitizer_posix.cc ------------------------------------------------===// 21f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// 31f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// The LLVM Compiler Infrastructure 41f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// 51f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// This file is distributed under the University of Illinois Open Source 61f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// License. See LICENSE.TXT for details. 71f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// 81f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//===----------------------------------------------------------------------===// 91f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// 101f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// This file is shared between AddressSanitizer and ThreadSanitizer 111f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// run-time libraries and implements POSIX-specific functions from 121f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov// sanitizer_libc.h. 131f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov//===----------------------------------------------------------------------===// 1424e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov 1524e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#include "sanitizer_platform.h" 162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_POSIX 171f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov 18230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov#include "sanitizer_common.h" 191f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov#include "sanitizer_libc.h" 20be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov#include "sanitizer_procmaps.h" 21736cf49a46b3cc5aa1856762f85e6f2799c24e5aSergey Matveev#include "sanitizer_stacktrace.h" 221f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov 23230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov#include <sys/mman.h> 241f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov 252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_LINUX 262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include <sys/utsname.h> 272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif 282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_LINUX && !SANITIZER_ANDROID 302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include <sys/personality.h> 312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif 322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 331f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonovnamespace __sanitizer { 341f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov 35be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov// ------------- sanitizer_common.h 36f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryanyuptr GetMmapGranularity() { 37f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany return GetPageSize(); 38f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany} 39be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov 402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_WORDSIZE == 32 412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// Take care of unusable kernel area in top gigabyte. 422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic uptr GetKernelAreaSize() { 432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_LINUX 442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines const uptr gbyte = 1UL << 30; 452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Firstly check if there are writable segments 472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // mapped to top gigabyte (e.g. stack). 482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines MemoryMappingLayout proc_maps(/*cache_enabled*/true); 492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr end, prot; 502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines while (proc_maps.Next(/*start*/0, &end, 512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines /*offset*/0, /*filename*/0, 522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines /*filename_size*/0, &prot)) { 532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if ((end >= 3 * gbyte) 542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines && (prot & MemoryMappingLayout::kProtectionWrite) != 0) 552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return 0; 562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if !SANITIZER_ANDROID 592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Even if nothing is mapped, top Gb may still be accessible 602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // if we are running on 64-bit kernel. 612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Uname may report misleading results if personality type 622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // is modified (e.g. under schroot) so check this as well. 632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines struct utsname uname_info; 642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines int pers = personality(0xffffffffUL); 652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (!(pers & PER_MASK) 662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines && uname(&uname_info) == 0 672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines && internal_strstr(uname_info.machine, "64")) 682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return 0; 692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif // SANITIZER_ANDROID 702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // Top gigabyte is reserved for kernel. 722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return gbyte; 732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#else 742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return 0; 752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif // SANITIZER_LINUX 762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif // SANITIZER_WORDSIZE == 32 782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 79bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanovuptr GetMaxVirtualAddress() { 80bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#if SANITIZER_WORDSIZE == 64 81bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# if defined(__powerpc64__) 82bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov // On PowerPC64 we have two different address space layouts: 44- and 46-bit. 832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // We somehow need to figure out which one we are using now and choose 84bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. 85bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov // Note that with 'ulimit -s unlimited' the stack is moved away from the top 86bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov // of the address space, so simply checking the stack address is not enough. 87bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov return (1ULL << 44) - 1; // 0x00000fffffffffffUL 882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines# elif defined(__aarch64__) 892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return (1ULL << 39) - 1; 90bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# else 91bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov return (1ULL << 47) - 1; // 0x00007fffffffffffUL; 92bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# endif 93bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#else // SANITIZER_WORDSIZE == 32 942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr res = (1ULL << 32) - 1; // 0xffffffff; 952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (!common_flags()->full_address_space) 962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines res -= GetKernelAreaSize(); 972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK_LT(reinterpret_cast<uptr>(&res), res); 982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return res; 99bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#endif // SANITIZER_WORDSIZE 100bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov} 101bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov 102a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonovvoid *MmapOrDie(uptr size, const char *mem_type) { 103f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany size = RoundUpTo(size, GetPageSizeCached()); 1049578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne uptr res = internal_mmap(0, size, 105230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov PROT_READ | PROT_WRITE, 106230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov MAP_PRIVATE | MAP_ANON, -1, 0); 1079578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne int reserrno; 1089578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne if (internal_iserror(res, &reserrno)) { 109e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany static int recursion_count; 110e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany if (recursion_count) { 111e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany // The Report() and CHECK calls below may call mmap recursively and fail. 112e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany // If we went into recursion, just die. 113c8490e2a09cd415cc58fc8f3b63bebddce61c82dDmitry Vyukov RawWrite("ERROR: Failed to mmap\n"); 114e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany Die(); 115e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany } 116e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany recursion_count++; 1172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Report("ERROR: %s failed to " 1182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n", 1199578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne SanitizerToolName, size, size, mem_type, reserrno); 1200aa04b3f432bc55e7c116d5280685ee3f243be8eKostya Serebryany DumpProcessMap(); 121a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov CHECK("unable to mmap" && 0); 122230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov } 1232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines IncreaseTotalMmap(size); 1249578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne return (void *)res; 125230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov} 126230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov 127230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonovvoid UnmapOrDie(void *addr, uptr size) { 128230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov if (!addr || !size) return; 1299578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne uptr res = internal_munmap(addr, size); 1309578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne if (internal_iserror(res)) { 131859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n", 132859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany SanitizerToolName, size, size, addr); 133a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov CHECK("unable to unmap" && 0); 134230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov } 1352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines DecreaseTotalMmap(size); 1362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 1372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines 1382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid *MmapNoReserveOrDie(uptr size, const char *mem_type) { 1392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr PageSize = GetPageSizeCached(); 1402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr p = internal_mmap(0, 1412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines RoundUpTo(size, PageSize), 1422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines PROT_READ | PROT_WRITE, 1432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, 1442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines -1, 0); 1452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines int reserrno; 1462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (internal_iserror(p, &reserrno)) { 1472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Report("ERROR: %s failed to " 1482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n", 1492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines SanitizerToolName, size, size, mem_type, reserrno); 1502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines CHECK("unable to mmap" && 0); 1512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 1522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines IncreaseTotalMmap(size); 1532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return (void *)p; 154230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov} 155230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov 156f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonovvoid *MmapFixedNoReserve(uptr fixed_addr, uptr size) { 157f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany uptr PageSize = GetPageSizeCached(); 1589578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 159f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany RoundUpTo(size, PageSize), 1606b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov PROT_READ | PROT_WRITE, 1616b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 1626b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov -1, 0); 1639578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne int reserrno; 1649578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne if (internal_iserror(p, &reserrno)) 1652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Report("ERROR: %s failed to " 1662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", 1679578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne SanitizerToolName, size, size, fixed_addr, reserrno); 1682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines IncreaseTotalMmap(size); 1699578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne return (void *)p; 170f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov} 171f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov 1729bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryanyvoid *MmapFixedOrDie(uptr fixed_addr, uptr size) { 1739bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany uptr PageSize = GetPageSizeCached(); 1749578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), 1759bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany RoundUpTo(size, PageSize), 1769bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany PROT_READ | PROT_WRITE, 1779bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany MAP_PRIVATE | MAP_ANON | MAP_FIXED, 1789bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany -1, 0); 1799578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne int reserrno; 1809578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne if (internal_iserror(p, &reserrno)) { 1812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Report("ERROR: %s failed to " 1822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", 1839578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne SanitizerToolName, size, size, fixed_addr, reserrno); 1849bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany CHECK("unable to mmap" && 0); 1859bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany } 1862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines IncreaseTotalMmap(size); 1879578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne return (void *)p; 1889bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany} 1899bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany 190f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonovvoid *Mprotect(uptr fixed_addr, uptr size) { 1919578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne return (void *)internal_mmap((void*)fixed_addr, size, 1929578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne PROT_NONE, 1939578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne MAP_PRIVATE | MAP_ANON | MAP_FIXED | 1949578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne MAP_NORESERVE, -1, 0); 195f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov} 196f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov 197a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonovvoid *MapFileToMemory(const char *file_name, uptr *buff_size) { 1989578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne uptr openrv = OpenFile(file_name, false); 1999578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne CHECK(!internal_iserror(openrv)); 2009578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne fd_t fd = openrv; 201a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov uptr fsize = internal_filesize(fd); 202a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov CHECK_NE(fsize, (uptr)-1); 203a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov CHECK_GT(fsize, 0); 204f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany *buff_size = RoundUpTo(fsize, GetPageSizeCached()); 2059578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); 2069578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne return internal_iserror(map) ? 0 : (void *)map; 207a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov} 208a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov 2092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) { 2102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr flags = MAP_SHARED; 2112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (addr) flags |= MAP_FIXED; 2122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); 2132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (internal_iserror(p)) { 2142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset, 2152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines size, p); 2162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return 0; 2172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines } 2182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines return (void *)p; 2192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines} 220a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov 221dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonovstatic inline bool IntervalsAreSeparate(uptr start1, uptr end1, 222dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov uptr start2, uptr end2) { 223dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov CHECK(start1 <= end1); 224dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov CHECK(start2 <= end2); 225dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov return (end1 < start2) || (end2 < start1); 226dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov} 227dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov 228dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// FIXME: this is thread-unsafe, but should not cause problems most of the time. 229dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// When the shadow is mapped only a single thread usually exists (plus maybe 230dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// several worker threads on Mac, which aren't expected to map big chunks of 231dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// memory). 232dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonovbool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 2339ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko MemoryMappingLayout proc_maps(/*cache_enabled*/true); 234dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov uptr start, end; 2359ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko while (proc_maps.Next(&start, &end, 2369ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko /*offset*/0, /*filename*/0, /*filename_size*/0, 2379ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko /*protection*/0)) { 238dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov if (!IntervalsAreSeparate(start, end, range_start, range_end)) 239dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov return false; 240dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov } 241dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov return true; 242dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov} 243dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov 244be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonovvoid DumpProcessMap() { 2459ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko MemoryMappingLayout proc_maps(/*cache_enabled*/true); 246be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov uptr start, end; 247be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov const sptr kBufSize = 4095; 2482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines char *filename = (char*)MmapOrDie(kBufSize, __func__); 249be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov Report("Process memory map follows:\n"); 250be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov while (proc_maps.Next(&start, &end, /* file_offset */0, 25145717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov filename, kBufSize, /* protection */0)) { 252be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); 253be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov } 254be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov Report("End of process memory map.\n"); 255b84ee029ada36949c30c57c5f701191783990574Alexey Samsonov UnmapOrDie(filename, kBufSize); 256be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov} 257be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov 2580969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonovconst char *GetPwd() { 2590969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov return GetEnv("PWD"); 2600969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov} 2610969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov 2621dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonovchar *FindPathToBinary(const char *name) { 2631dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov const char *path = GetEnv("PATH"); 2641dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov if (!path) 2651dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov return 0; 2661dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov uptr name_len = internal_strlen(name); 2671dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov InternalScopedBuffer<char> buffer(kMaxPathLength); 2681dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov const char *beg = path; 2691dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov while (true) { 2701dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov const char *end = internal_strchrnul(beg, ':'); 2711dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov uptr prefix_len = end - beg; 2721dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov if (prefix_len + name_len + 2 <= kMaxPathLength) { 2731dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov internal_memcpy(buffer.data(), beg, prefix_len); 2741dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov buffer[prefix_len] = '/'; 2751dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov internal_memcpy(&buffer[prefix_len + 1], name, name_len); 2761dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov buffer[prefix_len + 1 + name_len] = '\0'; 2771dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov if (FileExists(buffer.data())) 2781dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov return internal_strdup(buffer.data()); 2791dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov } 2801dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov if (*end == '\0') break; 2811dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov beg = end + 1; 2821dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov } 2831dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov return 0; 2841dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov} 2851dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov 286923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Klecknervoid MaybeOpenReportFile() { 2872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (!log_to_file) return; 2882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines uptr pid = internal_getpid(); 2892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines // If in tracer, use the parent's file. 2902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (pid == stoptheworld_tracer_pid) 2912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines pid = stoptheworld_tracer_ppid; 2922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines if (report_fd_pid == pid) return; 293923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner InternalScopedBuffer<char> report_path_full(4096); 294923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner internal_snprintf(report_path_full.data(), report_path_full.size(), 2952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines "%s.%zu", report_path_prefix, pid); 296923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner uptr openrv = OpenFile(report_path_full.data(), true); 297923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner if (internal_iserror(openrv)) { 298923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner report_fd = kStderrFd; 299923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner log_to_file = false; 300923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner Report("ERROR: Can't open file: %s\n", report_path_full.data()); 301923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner Die(); 302923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner } 303923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner if (report_fd != kInvalidFd) { 304923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner // We're in the child. Close the parent's log. 305923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner internal_close(report_fd); 306923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner } 307923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner report_fd = openrv; 3082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines report_fd_pid = pid; 309923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner} 310923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner 311923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Klecknervoid RawWrite(const char *buffer) { 312923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner static const char *kRawWriteError = 313923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner "RawWrite can't output requested buffer!\n"; 314923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner uptr length = (uptr)internal_strlen(buffer); 315923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner MaybeOpenReportFile(); 316923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner if (length != internal_write(report_fd, buffer, length)) { 317923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError)); 318923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner Die(); 319923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner } 320923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner} 321923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner 322821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukovbool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { 323821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov uptr s, e, off, prot; 3242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines InternalScopedString buff(4096); 325821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov MemoryMappingLayout proc_maps(/*cache_enabled*/false); 3262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) { 327821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov if ((prot & MemoryMappingLayout::kProtectionExecute) != 0 3282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines && internal_strcmp(module, buff.data()) == 0) { 329821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov *start = s; 330821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov *end = e; 331821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov return true; 332821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov } 333821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov } 334821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov return false; 335821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov} 336821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov 3371f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov} // namespace __sanitizer 3381f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov 3392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif // SANITIZER_POSIX 340