1//===-- tsan_platform_posix.cc --------------------------------------------===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// This file is a part of ThreadSanitizer (TSan), a race detector.
9//
10// POSIX-specific code.
11//===----------------------------------------------------------------------===//
12
13#include "sanitizer_common/sanitizer_platform.h"
14#if SANITIZER_POSIX
15
16#include "sanitizer_common/sanitizer_common.h"
17#include "sanitizer_common/sanitizer_errno.h"
18#include "sanitizer_common/sanitizer_libc.h"
19#include "sanitizer_common/sanitizer_procmaps.h"
20#include "tsan_platform.h"
21#include "tsan_rtl.h"
22
23namespace __tsan {
24
25static const char kShadowMemoryMappingWarning[] =
26    "FATAL: %s can not madvise shadow region [%zx, %zx] with %s (errno: %d)\n";
27static const char kShadowMemoryMappingHint[] =
28    "HINT: if %s is not supported in your environment, you may set "
29    "TSAN_OPTIONS=%s=0\n";
30
31static void NoHugePagesInShadow(uptr addr, uptr size) {
32  if (common_flags()->no_huge_pages_for_shadow)
33    if (!NoHugePagesInRegion(addr, size)) {
34      Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size,
35             "MADV_NOHUGEPAGE", errno);
36      Printf(kShadowMemoryMappingHint, "MADV_NOHUGEPAGE",
37             "no_huge_pages_for_shadow");
38      Die();
39    }
40}
41
42static void DontDumpShadow(uptr addr, uptr size) {
43  if (common_flags()->use_madv_dontdump)
44    if (!DontDumpShadowMemory(addr, size)) {
45      Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size,
46             "MADV_DONTDUMP", errno);
47      Printf(kShadowMemoryMappingHint, "MADV_DONTDUMP", "use_madv_dontdump");
48      Die();
49    }
50}
51
52#if !SANITIZER_GO
53void InitializeShadowMemory() {
54  // Map memory shadow.
55  if (!MmapFixedNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(), "shadow")) {
56    Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
57    Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
58    Die();
59  }
60  // This memory range is used for thread stacks and large user mmaps.
61  // Frequently a thread uses only a small part of stack and similarly
62  // a program uses a small part of large mmap. On some programs
63  // we see 20% memory usage reduction without huge pages for this range.
64  // FIXME: don't use constants here.
65#if defined(__x86_64__)
66  const uptr kMadviseRangeBeg  = 0x7f0000000000ull;
67  const uptr kMadviseRangeSize = 0x010000000000ull;
68#elif defined(__mips64)
69  const uptr kMadviseRangeBeg  = 0xff00000000ull;
70  const uptr kMadviseRangeSize = 0x0100000000ull;
71#elif defined(__aarch64__) && defined(__APPLE__)
72  uptr kMadviseRangeBeg = LoAppMemBeg();
73  uptr kMadviseRangeSize = LoAppMemEnd() - LoAppMemBeg();
74#elif defined(__aarch64__)
75  uptr kMadviseRangeBeg = 0;
76  uptr kMadviseRangeSize = 0;
77  if (vmaSize == 39) {
78    kMadviseRangeBeg  = 0x7d00000000ull;
79    kMadviseRangeSize = 0x0300000000ull;
80  } else if (vmaSize == 42) {
81    kMadviseRangeBeg  = 0x3f000000000ull;
82    kMadviseRangeSize = 0x01000000000ull;
83  } else {
84    DCHECK(0);
85  }
86#elif defined(__powerpc64__)
87  uptr kMadviseRangeBeg = 0;
88  uptr kMadviseRangeSize = 0;
89  if (vmaSize == 44) {
90    kMadviseRangeBeg  = 0x0f60000000ull;
91    kMadviseRangeSize = 0x0010000000ull;
92  } else if (vmaSize == 46) {
93    kMadviseRangeBeg  = 0x3f0000000000ull;
94    kMadviseRangeSize = 0x010000000000ull;
95  } else {
96    DCHECK(0);
97  }
98#endif
99  NoHugePagesInShadow(MemToShadow(kMadviseRangeBeg),
100                      kMadviseRangeSize * kShadowMultiplier);
101  DontDumpShadow(ShadowBeg(), ShadowEnd() - ShadowBeg());
102  DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
103      ShadowBeg(), ShadowEnd(),
104      (ShadowEnd() - ShadowBeg()) >> 30);
105
106  // Map meta shadow.
107  const uptr meta = MetaShadowBeg();
108  const uptr meta_size = MetaShadowEnd() - meta;
109  if (!MmapFixedNoReserve(meta, meta_size, "meta shadow")) {
110    Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
111    Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
112    Die();
113  }
114  NoHugePagesInShadow(meta, meta_size);
115  DontDumpShadow(meta, meta_size);
116  DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
117      meta, meta + meta_size, meta_size >> 30);
118
119  InitializeShadowMemoryPlatform();
120}
121
122static void ProtectRange(uptr beg, uptr end) {
123  CHECK_LE(beg, end);
124  if (beg == end)
125    return;
126  if (beg != (uptr)MmapFixedNoAccess(beg, end - beg)) {
127    Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
128    Printf("FATAL: Make sure you are not using unlimited stack\n");
129    Die();
130  }
131}
132
133void CheckAndProtect() {
134  // Ensure that the binary is indeed compiled with -pie.
135  MemoryMappingLayout proc_maps(true);
136  MemoryMappedSegment segment;
137  while (proc_maps.Next(&segment)) {
138    if (IsAppMem(segment.start)) continue;
139    if (segment.start >= HeapMemEnd() && segment.start < HeapEnd()) continue;
140    if (segment.protection == 0)  // Zero page or mprotected.
141      continue;
142    if (segment.start >= VdsoBeg())  // vdso
143      break;
144    Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n",
145           segment.start, segment.end);
146    Die();
147  }
148
149#if defined(__aarch64__) && defined(__APPLE__)
150  ProtectRange(HeapMemEnd(), ShadowBeg());
151  ProtectRange(ShadowEnd(), MetaShadowBeg());
152  ProtectRange(MetaShadowEnd(), TraceMemBeg());
153#else
154  ProtectRange(LoAppMemEnd(), ShadowBeg());
155  ProtectRange(ShadowEnd(), MetaShadowBeg());
156#ifdef TSAN_MID_APP_RANGE
157  ProtectRange(MetaShadowEnd(), MidAppMemBeg());
158  ProtectRange(MidAppMemEnd(), TraceMemBeg());
159#else
160  ProtectRange(MetaShadowEnd(), TraceMemBeg());
161#endif
162  // Memory for traces is mapped lazily in MapThreadTrace.
163  // Protect the whole range for now, so that user does not map something here.
164  ProtectRange(TraceMemBeg(), TraceMemEnd());
165  ProtectRange(TraceMemEnd(), HeapMemBeg());
166  ProtectRange(HeapEnd(), HiAppMemBeg());
167#endif
168}
169#endif
170
171}  // namespace __tsan
172
173#endif  // SANITIZER_POSIX
174