1//===-- tsan_platform.h -----------------------------------------*- C++ -*-===//
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// Platform-specific code.
13//===----------------------------------------------------------------------===//
14
15#ifndef TSAN_PLATFORM_H
16#define TSAN_PLATFORM_H
17
18#if !defined(__LP64__) && !defined(_WIN64)
19# error "Only 64-bit is supported"
20#endif
21
22#include "tsan_defs.h"
23#include "tsan_trace.h"
24
25namespace __tsan {
26
27#if !defined(SANITIZER_GO)
28
29#if defined(__x86_64__)
30/*
31C/C++ on linux/x86_64 and freebsd/x86_64
320000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings
330100 0000 0000 - 0200 0000 0000: -
340200 0000 0000 - 1000 0000 0000: shadow
351000 0000 0000 - 3000 0000 0000: -
363000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
374000 0000 0000 - 6000 0000 0000: -
386000 0000 0000 - 6200 0000 0000: traces
396200 0000 0000 - 7d00 0000 0000: -
407d00 0000 0000 - 7e00 0000 0000: heap
417e00 0000 0000 - 7e80 0000 0000: -
427e80 0000 0000 - 8000 0000 0000: modules and main thread stack
43*/
44const uptr kMetaShadowBeg = 0x300000000000ull;
45const uptr kMetaShadowEnd = 0x400000000000ull;
46const uptr kTraceMemBeg   = 0x600000000000ull;
47const uptr kTraceMemEnd   = 0x620000000000ull;
48const uptr kShadowBeg     = 0x020000000000ull;
49const uptr kShadowEnd     = 0x100000000000ull;
50const uptr kHeapMemBeg    = 0x7d0000000000ull;
51const uptr kHeapMemEnd    = 0x7e0000000000ull;
52const uptr kLoAppMemBeg   = 0x000000001000ull;
53const uptr kLoAppMemEnd   = 0x010000000000ull;
54const uptr kHiAppMemBeg   = 0x7e8000000000ull;
55const uptr kHiAppMemEnd   = 0x800000000000ull;
56const uptr kAppMemMsk     = 0x7c0000000000ull;
57const uptr kAppMemXor     = 0x020000000000ull;
58const uptr kVdsoBeg       = 0xf000000000000000ull;
59#elif defined(__mips64)
60/*
61C/C++ on linux/mips64
620100 0000 00 - 0200 0000 00: main binary
630200 0000 00 - 1400 0000 00: -
641400 0000 00 - 2400 0000 00: shadow
652400 0000 00 - 3000 0000 00: -
663000 0000 00 - 4000 0000 00: metainfo (memory blocks and sync objects)
674000 0000 00 - 6000 0000 00: -
686000 0000 00 - 6200 0000 00: traces
696200 0000 00 - fe00 0000 00: -
70fe00 0000 00 - ff00 0000 00: heap
71ff00 0000 00 - ff80 0000 00: -
72ff80 0000 00 - ffff ffff ff: modules and main thread stack
73*/
74const uptr kMetaShadowBeg = 0x3000000000ull;
75const uptr kMetaShadowEnd = 0x4000000000ull;
76const uptr kTraceMemBeg   = 0x6000000000ull;
77const uptr kTraceMemEnd   = 0x6200000000ull;
78const uptr kShadowBeg     = 0x1400000000ull;
79const uptr kShadowEnd     = 0x2400000000ull;
80const uptr kHeapMemBeg    = 0xfe00000000ull;
81const uptr kHeapMemEnd    = 0xff00000000ull;
82const uptr kLoAppMemBeg   = 0x0100000000ull;
83const uptr kLoAppMemEnd   = 0x0200000000ull;
84const uptr kHiAppMemBeg   = 0xff80000000ull;
85const uptr kHiAppMemEnd   = 0xffffffffffull;
86const uptr kAppMemMsk     = 0xfc00000000ull;
87const uptr kAppMemXor     = 0x0400000000ull;
88const uptr kVdsoBeg       = 0xfffff00000ull;
89#endif
90
91ALWAYS_INLINE
92bool IsAppMem(uptr mem) {
93  return (mem >= kHeapMemBeg && mem < kHeapMemEnd) ||
94         (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) ||
95         (mem >= kHiAppMemBeg && mem < kHiAppMemEnd);
96}
97
98ALWAYS_INLINE
99bool IsShadowMem(uptr mem) {
100  return mem >= kShadowBeg && mem <= kShadowEnd;
101}
102
103ALWAYS_INLINE
104bool IsMetaMem(uptr mem) {
105  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
106}
107
108ALWAYS_INLINE
109uptr MemToShadow(uptr x) {
110  DCHECK(IsAppMem(x));
111  return (((x) & ~(kAppMemMsk | (kShadowCell - 1)))
112      ^ kAppMemXor) * kShadowCnt;
113}
114
115ALWAYS_INLINE
116u32 *MemToMeta(uptr x) {
117  DCHECK(IsAppMem(x));
118  return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1)))
119      ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
120}
121
122ALWAYS_INLINE
123uptr ShadowToMem(uptr s) {
124  CHECK(IsShadowMem(s));
125  if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1))
126    return (s / kShadowCnt) ^ kAppMemXor;
127  else
128    return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk;
129}
130
131static USED uptr UserRegions[] = {
132  kLoAppMemBeg, kLoAppMemEnd,
133  kHiAppMemBeg, kHiAppMemEnd,
134  kHeapMemBeg,  kHeapMemEnd,
135};
136
137#elif defined(SANITIZER_GO) && !SANITIZER_WINDOWS
138
139/* Go on linux, darwin and freebsd
1400000 0000 1000 - 0000 1000 0000: executable
1410000 1000 0000 - 00c0 0000 0000: -
14200c0 0000 0000 - 00e0 0000 0000: heap
14300e0 0000 0000 - 2000 0000 0000: -
1442000 0000 0000 - 2380 0000 0000: shadow
1452380 0000 0000 - 3000 0000 0000: -
1463000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
1474000 0000 0000 - 6000 0000 0000: -
1486000 0000 0000 - 6200 0000 0000: traces
1496200 0000 0000 - 8000 0000 0000: -
150*/
151
152const uptr kMetaShadowBeg = 0x300000000000ull;
153const uptr kMetaShadowEnd = 0x400000000000ull;
154const uptr kTraceMemBeg   = 0x600000000000ull;
155const uptr kTraceMemEnd   = 0x620000000000ull;
156const uptr kShadowBeg     = 0x200000000000ull;
157const uptr kShadowEnd     = 0x238000000000ull;
158const uptr kAppMemBeg     = 0x000000001000ull;
159const uptr kAppMemEnd     = 0x00e000000000ull;
160
161ALWAYS_INLINE
162bool IsAppMem(uptr mem) {
163  return mem >= kAppMemBeg && mem < kAppMemEnd;
164}
165
166ALWAYS_INLINE
167bool IsShadowMem(uptr mem) {
168  return mem >= kShadowBeg && mem <= kShadowEnd;
169}
170
171ALWAYS_INLINE
172bool IsMetaMem(uptr mem) {
173  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
174}
175
176ALWAYS_INLINE
177uptr MemToShadow(uptr x) {
178  DCHECK(IsAppMem(x));
179  return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
180}
181
182ALWAYS_INLINE
183u32 *MemToMeta(uptr x) {
184  DCHECK(IsAppMem(x));
185  return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
186      kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
187}
188
189ALWAYS_INLINE
190uptr ShadowToMem(uptr s) {
191  CHECK(IsShadowMem(s));
192  return (s & ~kShadowBeg) / kShadowCnt;
193}
194
195static USED uptr UserRegions[] = {
196  kAppMemBeg, kAppMemEnd,
197};
198
199#elif defined(SANITIZER_GO) && SANITIZER_WINDOWS
200
201/* Go on windows
2020000 0000 1000 - 0000 1000 0000: executable
2030000 1000 0000 - 00f8 0000 0000: -
20400c0 0000 0000 - 00e0 0000 0000: heap
20500e0 0000 0000 - 0100 0000 0000: -
2060100 0000 0000 - 0500 0000 0000: shadow
2070500 0000 0000 - 0560 0000 0000: -
2080560 0000 0000 - 0760 0000 0000: traces
2090760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
21007d0 0000 0000 - 8000 0000 0000: -
211*/
212
213const uptr kMetaShadowBeg = 0x076000000000ull;
214const uptr kMetaShadowEnd = 0x07d000000000ull;
215const uptr kTraceMemBeg   = 0x056000000000ull;
216const uptr kTraceMemEnd   = 0x076000000000ull;
217const uptr kShadowBeg     = 0x010000000000ull;
218const uptr kShadowEnd     = 0x050000000000ull;
219const uptr kAppMemBeg     = 0x000000001000ull;
220const uptr kAppMemEnd     = 0x00e000000000ull;
221
222ALWAYS_INLINE
223bool IsAppMem(uptr mem) {
224  return mem >= kAppMemBeg && mem < kAppMemEnd;
225}
226
227ALWAYS_INLINE
228bool IsShadowMem(uptr mem) {
229  return mem >= kShadowBeg && mem <= kShadowEnd;
230}
231
232ALWAYS_INLINE
233bool IsMetaMem(uptr mem) {
234  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
235}
236
237ALWAYS_INLINE
238uptr MemToShadow(uptr x) {
239  DCHECK(IsAppMem(x));
240  return ((x & ~(kShadowCell - 1)) * kShadowCnt) + kShadowBeg;
241}
242
243ALWAYS_INLINE
244u32 *MemToMeta(uptr x) {
245  DCHECK(IsAppMem(x));
246  return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
247      kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
248}
249
250ALWAYS_INLINE
251uptr ShadowToMem(uptr s) {
252  CHECK(IsShadowMem(s));
253  // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
254  return (s - kShadowBeg) / kShadowCnt;
255}
256
257static USED uptr UserRegions[] = {
258  kAppMemBeg, kAppMemEnd,
259};
260
261#else
262# error "Unknown platform"
263#endif
264
265// The additional page is to catch shadow stack overflow as paging fault.
266// Windows wants 64K alignment for mmaps.
267const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace)
268    + (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1);
269
270uptr ALWAYS_INLINE GetThreadTrace(int tid) {
271  uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize;
272  DCHECK_LT(p, kTraceMemEnd);
273  return p;
274}
275
276uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
277  uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize
278      + kTraceSize * sizeof(Event);
279  DCHECK_LT(p, kTraceMemEnd);
280  return p;
281}
282
283void InitializePlatform();
284void FlushShadowMemory();
285void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
286
287// Says whether the addr relates to a global var.
288// Guesses with high probability, may yield both false positives and negatives.
289bool IsGlobalVar(uptr addr);
290int ExtractResolvFDs(void *state, int *fds, int nfd);
291int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
292
293int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
294    void *abstime), void *c, void *m, void *abstime,
295    void(*cleanup)(void *arg), void *arg);
296
297}  // namespace __tsan
298
299#endif  // TSAN_PLATFORM_H
300