1 //===-- tsan_platform_linux.cc --------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a part of ThreadSanitizer (TSan), a race detector.
11 //
12 // Linux-specific code.
13 //===----------------------------------------------------------------------===//
14
15 #ifdef __linux__
16
17 #include "sanitizer_common/sanitizer_common.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 #include "tsan_flags.h"
23
24 #include <asm/prctl.h>
25 #include <fcntl.h>
26 #include <pthread.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <sys/mman.h>
33 #include <sys/prctl.h>
34 #include <sys/syscall.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <sys/resource.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <sched.h>
42 #include <dlfcn.h>
43
44 extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
45
46 namespace __sanitizer {
47
Die()48 void Die() {
49 _exit(1);
50 }
51
52 } // namespace __sanitizer
53
54 namespace __tsan {
55
56 #ifndef TSAN_GO
ScopedInRtl()57 ScopedInRtl::ScopedInRtl()
58 : thr_(cur_thread()) {
59 in_rtl_ = thr_->in_rtl;
60 thr_->in_rtl++;
61 errno_ = errno;
62 }
63
~ScopedInRtl()64 ScopedInRtl::~ScopedInRtl() {
65 thr_->in_rtl--;
66 errno = errno_;
67 CHECK_EQ(in_rtl_, thr_->in_rtl);
68 }
69 #else
70 ScopedInRtl::ScopedInRtl() {
71 }
72
73 ScopedInRtl::~ScopedInRtl() {
74 }
75 #endif
76
GetShadowMemoryConsumption()77 uptr GetShadowMemoryConsumption() {
78 return 0;
79 }
80
FlushShadowMemory()81 void FlushShadowMemory() {
82 madvise((void*)kLinuxShadowBeg,
83 kLinuxShadowEnd - kLinuxShadowBeg,
84 MADV_DONTNEED);
85 }
86
87 #ifndef TSAN_GO
ProtectRange(uptr beg,uptr end)88 static void ProtectRange(uptr beg, uptr end) {
89 ScopedInRtl in_rtl;
90 CHECK_LE(beg, end);
91 if (beg == end)
92 return;
93 if (beg != (uptr)Mprotect(beg, end - beg)) {
94 TsanPrintf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
95 TsanPrintf("FATAL: Make sure you are not using unlimited stack\n");
96 Die();
97 }
98 }
99 #endif
100
InitializeShadowMemory()101 void InitializeShadowMemory() {
102 uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
103 kLinuxShadowEnd - kLinuxShadowBeg);
104 if (shadow != kLinuxShadowBeg) {
105 TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
106 TsanPrintf("FATAL: Make sure to compile with -fPIE and "
107 "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
108 Die();
109 }
110 #ifndef TSAN_GO
111 const uptr kClosedLowBeg = 0x200000;
112 const uptr kClosedLowEnd = kLinuxShadowBeg - 1;
113 const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
114 const uptr kClosedMidEnd = kLinuxAppMemBeg - 1;
115 ProtectRange(kClosedLowBeg, kClosedLowEnd);
116 ProtectRange(kClosedMidBeg, kClosedMidEnd);
117 #endif
118 #ifndef TSAN_GO
119 DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
120 kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
121 #endif
122 DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
123 kLinuxShadowBeg, kLinuxShadowEnd,
124 (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
125 #ifndef TSAN_GO
126 DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
127 kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
128 #endif
129 DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
130 kLinuxAppMemBeg, kLinuxAppMemEnd,
131 (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
132 DPrintf("stack %zx\n", (uptr)&shadow);
133 }
134
135 static uptr g_tls_size;
136 static uptr g_data_start;
137 static uptr g_data_end;
138
139 #ifndef TSAN_GO
CheckPIE()140 static void CheckPIE() {
141 // Ensure that the binary is indeed compiled with -pie.
142 MemoryMappingLayout proc_maps;
143 uptr start, end;
144 if (proc_maps.Next(&start, &end,
145 /*offset*/0, /*filename*/0, /*filename_size*/0)) {
146 if ((u64)start < kLinuxAppMemBeg) {
147 TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
148 "something is mapped at 0x%zx < 0x%zx)\n",
149 start, kLinuxAppMemBeg);
150 TsanPrintf("FATAL: Make sure to compile with -fPIE"
151 " and to link with -pie.\n");
152 Die();
153 }
154 }
155 }
156
InitDataSeg()157 static void InitDataSeg() {
158 MemoryMappingLayout proc_maps;
159 uptr start, end, offset;
160 char name[128];
161 bool prev_is_data = false;
162 while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name))) {
163 DPrintf("%p-%p %p %s\n", start, end, offset, name);
164 bool is_data = offset != 0 && name[0] != 0;
165 bool is_bss = offset == 0 && name[0] == 0 && prev_is_data;
166 if (g_data_start == 0 && is_data)
167 g_data_start = start;
168 if (is_bss)
169 g_data_end = end;
170 prev_is_data = is_data;
171 }
172 DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
173 CHECK_LT(g_data_start, g_data_end);
174 CHECK_GE((uptr)&g_data_start, g_data_start);
175 CHECK_LT((uptr)&g_data_start, g_data_end);
176 }
177
178 #ifdef __i386__
179 # define INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
180 #else
181 # define INTERNAL_FUNCTION
182 #endif
183 extern "C" void _dl_get_tls_static_info(size_t*, size_t*)
184 __attribute__((weak)) INTERNAL_FUNCTION;
185
InitTlsSize()186 static int InitTlsSize() {
187 typedef void (*get_tls_func)(size_t*, size_t*) INTERNAL_FUNCTION;
188 get_tls_func get_tls = &_dl_get_tls_static_info;
189 if (get_tls == 0)
190 get_tls = (get_tls_func)dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
191 CHECK_NE(get_tls, 0);
192 size_t tls_size = 0;
193 size_t tls_align = 0;
194 get_tls(&tls_size, &tls_align);
195 return tls_size;
196 }
197 #endif // #ifndef TSAN_GO
198
InitializePlatform()199 const char *InitializePlatform() {
200 void *p = 0;
201 if (sizeof(p) == 8) {
202 // Disable core dumps, dumping of 16TB usually takes a bit long.
203 // The following magic is to prevent clang from replacing it with memset.
204 volatile rlimit lim;
205 lim.rlim_cur = 0;
206 lim.rlim_max = 0;
207 setrlimit(RLIMIT_CORE, (rlimit*)&lim);
208 }
209
210 #ifndef TSAN_GO
211 CheckPIE();
212 g_tls_size = (uptr)InitTlsSize();
213 InitDataSeg();
214 #endif
215 return getenv("TSAN_OPTIONS");
216 }
217
FinalizePlatform()218 void FinalizePlatform() {
219 fflush(0);
220 }
221
GetTlsSize()222 uptr GetTlsSize() {
223 #ifndef TSAN_GO
224 return g_tls_size;
225 #else
226 return 0;
227 #endif
228 }
229
GetThreadStackAndTls(bool main,uptr * stk_addr,uptr * stk_size,uptr * tls_addr,uptr * tls_size)230 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
231 uptr *tls_addr, uptr *tls_size) {
232 #ifndef TSAN_GO
233 arch_prctl(ARCH_GET_FS, tls_addr);
234 *tls_addr -= g_tls_size;
235 *tls_size = g_tls_size;
236
237 uptr stack_top, stack_bottom;
238 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
239 *stk_addr = stack_bottom;
240 *stk_size = stack_top - stack_bottom;
241
242 if (!main) {
243 // If stack and tls intersect, make them non-intersecting.
244 if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
245 CHECK_GT(*tls_addr + *tls_size, *stk_addr);
246 CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
247 *stk_size -= *tls_size;
248 *tls_addr = *stk_addr + *stk_size;
249 }
250 }
251 #else
252 *stk_addr = 0;
253 *stk_size = 0;
254 *tls_addr = 0;
255 *tls_size = 0;
256 #endif
257 }
258
IsGlobalVar(uptr addr)259 bool IsGlobalVar(uptr addr) {
260 return g_data_start && addr >= g_data_start && addr < g_data_end;
261 }
262
263 } // namespace __tsan
264
265 #endif // #ifdef __linux__
266