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