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
12909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar// sanitizer_posix.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"
20909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar#include "sanitizer_posix.h"
21be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov#include "sanitizer_procmaps.h"
22736cf49a46b3cc5aa1856762f85e6f2799c24e5aSergey Matveev#include "sanitizer_stacktrace.h"
231f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
247c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#include <fcntl.h>
257c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#include <signal.h>
26230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov#include <sys/mman.h>
271f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_LINUX
292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include <sys/utsname.h>
302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif
312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_LINUX && !SANITIZER_ANDROID
332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include <sys/personality.h>
342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif
352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
3686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#if SANITIZER_FREEBSD
3786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
3886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines// that, it was never implemented.  So just define it to zero.
3986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#undef  MAP_NORESERVE
4086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#define MAP_NORESERVE 0
4186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#endif
4286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
431f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonovnamespace __sanitizer {
441f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
45be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov// ------------- sanitizer_common.h
46f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryanyuptr GetMmapGranularity() {
47f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  return GetPageSize();
48f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany}
49be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov
502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if SANITIZER_WORDSIZE == 32
512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// Take care of unusable kernel area in top gigabyte.
522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic uptr GetKernelAreaSize() {
537c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#if SANITIZER_LINUX && !SANITIZER_X32
542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  const uptr gbyte = 1UL << 30;
552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Firstly check if there are writable segments
572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // mapped to top gigabyte (e.g. stack).
582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr end, prot;
602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  while (proc_maps.Next(/*start*/0, &end,
612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                        /*offset*/0, /*filename*/0,
622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                        /*filename_size*/0, &prot)) {
632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    if ((end >= 3 * gbyte)
642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        && (prot & MemoryMappingLayout::kProtectionWrite) != 0)
652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      return 0;
662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if !SANITIZER_ANDROID
692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Even if nothing is mapped, top Gb may still be accessible
702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // if we are running on 64-bit kernel.
712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Uname may report misleading results if personality type
722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // is modified (e.g. under schroot) so check this as well.
732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  struct utsname uname_info;
742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  int pers = personality(0xffffffffUL);
752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (!(pers & PER_MASK)
762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      && uname(&uname_info) == 0
772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      && internal_strstr(uname_info.machine, "64"))
782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return 0;
792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif  // SANITIZER_ANDROID
802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Top gigabyte is reserved for kernel.
822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return gbyte;
832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#else
842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return 0;
857c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#endif  // SANITIZER_LINUX && !SANITIZER_X32
862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif  // SANITIZER_WORDSIZE == 32
882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
89bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanovuptr GetMaxVirtualAddress() {
90bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#if SANITIZER_WORDSIZE == 64
9186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines# if defined(__powerpc64__) || defined(__aarch64__)
92bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // We somehow need to figure out which one we are using now and choose
94bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
95bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // Note that with 'ulimit -s unlimited' the stack is moved away from the top
96bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  // of the address space, so simply checking the stack address is not enough.
976d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  // This should (does) work for both PowerPC64 Endian modes.
9886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
996d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
1006d1862363c88c183b0ed7740fca876342cf0474bStephen Hines# elif defined(__mips64)
1016d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return (1ULL << 40) - 1;  // 0x000000ffffffffffUL;
102bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# else
103bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
104bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov# endif
105bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#else  // SANITIZER_WORDSIZE == 32
1062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr res = (1ULL << 32) - 1;  // 0xffffffff;
1072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (!common_flags()->full_address_space)
1082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    res -= GetKernelAreaSize();
1092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  CHECK_LT(reinterpret_cast<uptr>(&res), res);
1102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return res;
111bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov#endif  // SANITIZER_WORDSIZE
112bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov}
113bb7f2d880c843dd5ee1c5e53d2517f7ca9058e66Timur Iskhodzhanov
114a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonovvoid *MmapOrDie(uptr size, const char *mem_type) {
115f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  size = RoundUpTo(size, GetPageSizeCached());
1169578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr res = internal_mmap(0, size,
117230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov                            PROT_READ | PROT_WRITE,
118230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov                            MAP_PRIVATE | MAP_ANON, -1, 0);
1199578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int reserrno;
1209578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(res, &reserrno)) {
121e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    static int recursion_count;
122e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    if (recursion_count) {
123e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany      // The Report() and CHECK calls below may call mmap recursively and fail.
124e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany      // If we went into recursion, just die.
125c8490e2a09cd415cc58fc8f3b63bebddce61c82dDmitry Vyukov      RawWrite("ERROR: Failed to mmap\n");
126e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany      Die();
127e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    }
128e8216fd93f6f8980965197a1779b6f54441255caKostya Serebryany    recursion_count++;
1292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Report("ERROR: %s failed to "
1302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines           "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n",
1319578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne           SanitizerToolName, size, size, mem_type, reserrno);
1320aa04b3f432bc55e7c116d5280685ee3f243be8eKostya Serebryany    DumpProcessMap();
133a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov    CHECK("unable to mmap" && 0);
134230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  }
1352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  IncreaseTotalMmap(size);
1369578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)res;
137230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov}
138230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov
139230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonovvoid UnmapOrDie(void *addr, uptr size) {
140230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  if (!addr || !size) return;
1419578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr res = internal_munmap(addr, size);
1429578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(res)) {
143859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
144859778a4e2dffa4024fa3e13b105fd62eca44b1cKostya Serebryany           SanitizerToolName, size, size, addr);
145a25b3463477d2a825df4f656001fc07c594b35acAlexey Samsonov    CHECK("unable to unmap" && 0);
146230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov  }
1472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  DecreaseTotalMmap(size);
1482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid *MmapNoReserveOrDie(uptr size, const char *mem_type) {
1512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr PageSize = GetPageSizeCached();
1522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr p = internal_mmap(0,
1532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      RoundUpTo(size, PageSize),
1542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PROT_READ | PROT_WRITE,
1552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
1562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      -1, 0);
1572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  int reserrno;
1582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (internal_iserror(p, &reserrno)) {
1592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Report("ERROR: %s failed to "
1602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines           "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n",
1612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines           SanitizerToolName, size, size, mem_type, reserrno);
1622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    CHECK("unable to mmap" && 0);
1632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  IncreaseTotalMmap(size);
1652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return (void *)p;
166230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov}
167230c3be6cdd094a187f48e27ba0961dbeee70344Alexey Samsonov
168f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonovvoid *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
169f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  uptr PageSize = GetPageSizeCached();
1709578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
171f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany      RoundUpTo(size, PageSize),
1726b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov      PROT_READ | PROT_WRITE,
1736b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
1746b641c5e63be45a03f96346886d27c4b4135ddafDmitry Vyukov      -1, 0);
1759578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int reserrno;
1769578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(p, &reserrno))
1772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Report("ERROR: %s failed to "
1782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines           "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
1799578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne           SanitizerToolName, size, size, fixed_addr, reserrno);
1802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  IncreaseTotalMmap(size);
1819578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)p;
182f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov}
183f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov
1849bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryanyvoid *MmapFixedOrDie(uptr fixed_addr, uptr size) {
1859bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany  uptr PageSize = GetPageSizeCached();
1869578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
1879bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      RoundUpTo(size, PageSize),
1889bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      PROT_READ | PROT_WRITE,
1899bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      MAP_PRIVATE | MAP_ANON | MAP_FIXED,
1909bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany      -1, 0);
1919578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int reserrno;
1929578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(p, &reserrno)) {
1932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Report("ERROR: %s failed to "
1942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines           "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
1959578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne           SanitizerToolName, size, size, fixed_addr, reserrno);
1969bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany    CHECK("unable to mmap" && 0);
1979bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany  }
1982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  IncreaseTotalMmap(size);
1999578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)p;
2009bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany}
2019bfe78f7d4f9af3cdacb4d34bd7b4fead27dcda5Kostya Serebryany
202909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarvoid *MmapNoAccess(uptr fixed_addr, uptr size) {
2039578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return (void *)internal_mmap((void*)fixed_addr, size,
2049578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne                               PROT_NONE,
2059578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne                               MAP_PRIVATE | MAP_ANON | MAP_FIXED |
2069578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne                               MAP_NORESERVE, -1, 0);
207f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov}
208f607fc1c67a613a59a1db3c80c5d1322e1978102Alexey Samsonov
209909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarbool MprotectNoAccess(uptr addr, uptr size) {
210909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
211909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar}
212909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar
213909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarfd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
2147c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  int flags;
2157c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  switch (mode) {
2167c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    case RdOnly: flags = O_RDONLY; break;
2177c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    case WrOnly: flags = O_WRONLY | O_CREAT; break;
2187c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    case RdWr: flags = O_RDWR | O_CREAT; break;
2197c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  }
220909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  fd_t res = internal_open(filename, flags, 0660);
221909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  if (internal_iserror(res, errno_p))
222909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar    return kInvalidFd;
223909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  return res;
224909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar}
225909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar
226909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarvoid CloseFile(fd_t fd) {
227909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  internal_close(fd);
228909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar}
229909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar
230909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarbool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
231909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar                  error_t *error_p) {
232909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  uptr res = internal_read(fd, buff, buff_size);
233909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  if (internal_iserror(res, error_p))
234909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar    return false;
235909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  if (bytes_read)
236909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar    *bytes_read = res;
237909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  return true;
238909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar}
239909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar
240909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarbool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
241909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar                 error_t *error_p) {
242909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  uptr res = internal_write(fd, buff, buff_size);
243909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  if (internal_iserror(res, error_p))
244909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar    return false;
245909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  if (bytes_written)
246909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar    *bytes_written = res;
247909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  return true;
248909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar}
249909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar
250909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarbool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
251909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  uptr res = internal_rename(oldpath, newpath);
252909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  return !internal_iserror(res, error_p);
2537c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
2547c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
255a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonovvoid *MapFileToMemory(const char *file_name, uptr *buff_size) {
256909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  fd_t fd = OpenFile(file_name, RdOnly);
257909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar  CHECK(fd != kInvalidFd);
258a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov  uptr fsize = internal_filesize(fd);
259a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov  CHECK_NE(fsize, (uptr)-1);
260a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov  CHECK_GT(fsize, 0);
261f67ec2b6e8d2ae328c27de0b026eea2d6667836eKostya Serebryany  *buff_size = RoundUpTo(fsize, GetPageSizeCached());
2629578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
2639578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_iserror(map) ? 0 : (void *)map;
264a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov}
265a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov
266909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainarvoid *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
2672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr flags = MAP_SHARED;
2682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (addr) flags |= MAP_FIXED;
2692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
2707c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  int mmap_errno = 0;
2717c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (internal_iserror(p, &mmap_errno)) {
272909fff81b83df049ecc6e02407394640435d7befPirama Arumuga Nainar    Printf("could not map writable file (%d, %zu, %zu): %zd, errno: %d\n",
2737c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar           fd, offset, size, p, mmap_errno);
2742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return 0;
2752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
2762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return (void *)p;
2772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
278a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov
279dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonovstatic inline bool IntervalsAreSeparate(uptr start1, uptr end1,
280dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov                                        uptr start2, uptr end2) {
281dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  CHECK(start1 <= end1);
282dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  CHECK(start2 <= end2);
283dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  return (end1 < start2) || (end2 < start1);
284dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov}
285dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov
286dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// FIXME: this is thread-unsafe, but should not cause problems most of the time.
287dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// When the shadow is mapped only a single thread usually exists (plus maybe
288dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// several worker threads on Mac, which aren't expected to map big chunks of
289dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov// memory).
290dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonovbool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
2919ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
292dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  uptr start, end;
2939ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  while (proc_maps.Next(&start, &end,
2949ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko                        /*offset*/0, /*filename*/0, /*filename_size*/0,
2959ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko                        /*protection*/0)) {
29686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    CHECK_NE(0, end);
29786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    if (!IntervalsAreSeparate(start, end - 1, range_start, range_end))
298dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov      return false;
299dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  }
300dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov  return true;
301dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov}
302dd3a911e46b3f0416d60d9be5c84ccfc4b1c3aa8Alexey Samsonov
303be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonovvoid DumpProcessMap() {
3049ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
305be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  uptr start, end;
306be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  const sptr kBufSize = 4095;
3072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  char *filename = (char*)MmapOrDie(kBufSize, __func__);
308be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  Report("Process memory map follows:\n");
309be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  while (proc_maps.Next(&start, &end, /* file_offset */0,
31045717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov                        filename, kBufSize, /* protection */0)) {
311be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov    Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
312be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  }
313be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov  Report("End of process memory map.\n");
314b84ee029ada36949c30c57c5f701191783990574Alexey Samsonov  UnmapOrDie(filename, kBufSize);
315be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov}
316be7420cc79d8580eb354666eef638d39ee9cff80Alexey Samsonov
3170969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonovconst char *GetPwd() {
3180969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov  return GetEnv("PWD");
3190969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov}
3200969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov
3211dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonovchar *FindPathToBinary(const char *name) {
3221dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  const char *path = GetEnv("PATH");
3231dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  if (!path)
3241dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov    return 0;
3251dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  uptr name_len = internal_strlen(name);
3261dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  InternalScopedBuffer<char> buffer(kMaxPathLength);
3271dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  const char *beg = path;
3281dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  while (true) {
3291dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov    const char *end = internal_strchrnul(beg, ':');
3301dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov    uptr prefix_len = end - beg;
3311dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov    if (prefix_len + name_len + 2 <= kMaxPathLength) {
3321dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov      internal_memcpy(buffer.data(), beg, prefix_len);
3331dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov      buffer[prefix_len] = '/';
3341dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov      internal_memcpy(&buffer[prefix_len + 1], name, name_len);
3351dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov      buffer[prefix_len + 1 + name_len] = '\0';
3361dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov      if (FileExists(buffer.data()))
3371dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov        return internal_strdup(buffer.data());
3381dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov    }
3391dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov    if (*end == '\0') break;
3401dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov    beg = end + 1;
3411dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  }
3421dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov  return 0;
3431dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov}
3441dcd1d9d1c86ab9b728386d261fbebe00b32e097Alexey Samsonov
3457c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarbool IsPathSeparator(const char c) {
3467c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  return c == '/';
3477c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
3487c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
3497c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainarbool IsAbsolutePath(const char *path) {
3507c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  return path != nullptr && IsPathSeparator(path[0]);
3517c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
3527c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
35386277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid ReportFile::Write(const char *buffer, uptr length) {
35486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SpinMutexLock l(mu);
35586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  static const char *kWriteError =
35686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      "ReportFile::Write() can't output requested buffer!\n";
35786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  ReopenIfNecessary();
35886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (length != internal_write(fd, buffer, length)) {
35986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    internal_write(fd, kWriteError, internal_strlen(kWriteError));
360923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner    Die();
361923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner  }
362923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner}
363923bac7a85d8bd37219b440a6b4c0800ea4bcd21Reid Kleckner
364821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukovbool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
365821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov  uptr s, e, off, prot;
36686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  InternalScopedString buff(kMaxPathLength);
367821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov  MemoryMappingLayout proc_maps(/*cache_enabled*/false);
3682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
369821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov    if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
3702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        && internal_strcmp(module, buff.data()) == 0) {
371821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov      *start = s;
372821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov      *end = e;
373821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov      return true;
374821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov    }
375821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov  }
376821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov  return false;
377821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov}
378821acfaccc7d11b987e2882b022e8d167b0c8a54Dmitry Vyukov
3797c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga NainarSignalContext SignalContext::Create(void *siginfo, void *context) {
3807c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
3817c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  uptr pc, sp, bp;
3827c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  GetPcSpBp(context, &pc, &sp, &bp);
3837c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  return SignalContext(context, addr, pc, sp, bp);
3847c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar}
3857c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar
3861f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov}  // namespace __sanitizer
3871f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
3882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif  // SANITIZER_POSIX
389