1 //===-- tsan_go.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 // ThreadSanitizer runtime for Go language.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "tsan_rtl.h"
15 #include "tsan_symbolize.h"
16 #include "sanitizer_common/sanitizer_common.h"
17 #include <stdlib.h>
18
19 namespace __tsan {
20
InitializeInterceptors()21 void InitializeInterceptors() {
22 }
23
InitializeDynamicAnnotations()24 void InitializeDynamicAnnotations() {
25 }
26
IsExpectedReport(uptr addr,uptr size)27 bool IsExpectedReport(uptr addr, uptr size) {
28 return false;
29 }
30
internal_alloc(MBlockType typ,uptr sz)31 void *internal_alloc(MBlockType typ, uptr sz) {
32 return InternalAlloc(sz);
33 }
34
internal_free(void * p)35 void internal_free(void *p) {
36 InternalFree(p);
37 }
38
39 // Callback into Go.
40 static void (*go_runtime_cb)(uptr cmd, void *ctx);
41
42 enum {
43 CallbackGetProc = 0,
44 CallbackSymbolizeCode = 1,
45 CallbackSymbolizeData = 2,
46 };
47
48 struct SymbolizeCodeContext {
49 uptr pc;
50 char *func;
51 char *file;
52 uptr line;
53 uptr off;
54 uptr res;
55 };
56
SymbolizeCode(uptr addr)57 SymbolizedStack *SymbolizeCode(uptr addr) {
58 SymbolizedStack *s = SymbolizedStack::New(addr);
59 SymbolizeCodeContext cbctx;
60 internal_memset(&cbctx, 0, sizeof(cbctx));
61 cbctx.pc = addr;
62 go_runtime_cb(CallbackSymbolizeCode, &cbctx);
63 if (cbctx.res) {
64 AddressInfo &info = s->info;
65 info.module_offset = cbctx.off;
66 info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
67 info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
68 info.line = cbctx.line;
69 info.column = 0;
70 }
71 return s;
72 }
73
74 struct SymbolizeDataContext {
75 uptr addr;
76 uptr heap;
77 uptr start;
78 uptr size;
79 char *name;
80 char *file;
81 uptr line;
82 uptr res;
83 };
84
SymbolizeData(uptr addr)85 ReportLocation *SymbolizeData(uptr addr) {
86 SymbolizeDataContext cbctx;
87 internal_memset(&cbctx, 0, sizeof(cbctx));
88 cbctx.addr = addr;
89 go_runtime_cb(CallbackSymbolizeData, &cbctx);
90 if (!cbctx.res)
91 return 0;
92 if (cbctx.heap) {
93 MBlock *b = ctx->metamap.GetBlock(cbctx.start);
94 if (!b)
95 return 0;
96 ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
97 loc->heap_chunk_start = cbctx.start;
98 loc->heap_chunk_size = b->siz;
99 loc->tid = b->tid;
100 loc->stack = SymbolizeStackId(b->stk);
101 return loc;
102 } else {
103 ReportLocation *loc = ReportLocation::New(ReportLocationGlobal);
104 loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??");
105 loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??");
106 loc->global.line = cbctx.line;
107 loc->global.start = cbctx.start;
108 loc->global.size = cbctx.size;
109 return loc;
110 }
111 }
112
113 static ThreadState *main_thr;
114 static bool inited;
115
get_cur_proc()116 static Processor* get_cur_proc() {
117 if (UNLIKELY(!inited)) {
118 // Running Initialize().
119 // We have not yet returned the Processor to Go, so we cannot ask it back.
120 // Currently, Initialize() does not use the Processor, so return nullptr.
121 return nullptr;
122 }
123 Processor *proc;
124 go_runtime_cb(CallbackGetProc, &proc);
125 return proc;
126 }
127
proc()128 Processor *ThreadState::proc() {
129 return get_cur_proc();
130 }
131
132 extern "C" {
133
AllocGoroutine()134 static ThreadState *AllocGoroutine() {
135 ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
136 sizeof(ThreadState));
137 internal_memset(thr, 0, sizeof(*thr));
138 return thr;
139 }
140
__tsan_init(ThreadState ** thrp,Processor ** procp,void (* cb)(uptr cmd,void * cb))141 void __tsan_init(ThreadState **thrp, Processor **procp,
142 void (*cb)(uptr cmd, void *cb)) {
143 go_runtime_cb = cb;
144 ThreadState *thr = AllocGoroutine();
145 main_thr = *thrp = thr;
146 Initialize(thr);
147 *procp = thr->proc1;
148 inited = true;
149 }
150
__tsan_fini()151 void __tsan_fini() {
152 // FIXME: Not necessary thread 0.
153 ThreadState *thr = main_thr;
154 int res = Finalize(thr);
155 exit(res);
156 }
157
__tsan_map_shadow(uptr addr,uptr size)158 void __tsan_map_shadow(uptr addr, uptr size) {
159 MapShadow(addr, size);
160 }
161
__tsan_read(ThreadState * thr,void * addr,void * pc)162 void __tsan_read(ThreadState *thr, void *addr, void *pc) {
163 MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
164 }
165
__tsan_read_pc(ThreadState * thr,void * addr,uptr callpc,uptr pc)166 void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
167 if (callpc != 0)
168 FuncEntry(thr, callpc);
169 MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
170 if (callpc != 0)
171 FuncExit(thr);
172 }
173
__tsan_write(ThreadState * thr,void * addr,void * pc)174 void __tsan_write(ThreadState *thr, void *addr, void *pc) {
175 MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
176 }
177
__tsan_write_pc(ThreadState * thr,void * addr,uptr callpc,uptr pc)178 void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
179 if (callpc != 0)
180 FuncEntry(thr, callpc);
181 MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
182 if (callpc != 0)
183 FuncExit(thr);
184 }
185
__tsan_read_range(ThreadState * thr,void * addr,uptr size,uptr pc)186 void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
187 MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
188 }
189
__tsan_write_range(ThreadState * thr,void * addr,uptr size,uptr pc)190 void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
191 MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
192 }
193
__tsan_func_enter(ThreadState * thr,void * pc)194 void __tsan_func_enter(ThreadState *thr, void *pc) {
195 FuncEntry(thr, (uptr)pc);
196 }
197
__tsan_func_exit(ThreadState * thr)198 void __tsan_func_exit(ThreadState *thr) {
199 FuncExit(thr);
200 }
201
__tsan_malloc(ThreadState * thr,uptr pc,uptr p,uptr sz)202 void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) {
203 CHECK(inited);
204 if (thr && pc)
205 ctx->metamap.AllocBlock(thr, pc, p, sz);
206 MemoryResetRange(0, 0, (uptr)p, sz);
207 }
208
__tsan_free(uptr p,uptr sz)209 void __tsan_free(uptr p, uptr sz) {
210 ctx->metamap.FreeRange(get_cur_proc(), p, sz);
211 }
212
__tsan_go_start(ThreadState * parent,ThreadState ** pthr,void * pc)213 void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
214 ThreadState *thr = AllocGoroutine();
215 *pthr = thr;
216 int goid = ThreadCreate(parent, (uptr)pc, 0, true);
217 ThreadStart(thr, goid, 0);
218 }
219
__tsan_go_end(ThreadState * thr)220 void __tsan_go_end(ThreadState *thr) {
221 ThreadFinish(thr);
222 internal_free(thr);
223 }
224
__tsan_proc_create(Processor ** pproc)225 void __tsan_proc_create(Processor **pproc) {
226 *pproc = ProcCreate();
227 }
228
__tsan_proc_destroy(Processor * proc)229 void __tsan_proc_destroy(Processor *proc) {
230 ProcDestroy(proc);
231 }
232
__tsan_acquire(ThreadState * thr,void * addr)233 void __tsan_acquire(ThreadState *thr, void *addr) {
234 Acquire(thr, 0, (uptr)addr);
235 }
236
__tsan_release(ThreadState * thr,void * addr)237 void __tsan_release(ThreadState *thr, void *addr) {
238 ReleaseStore(thr, 0, (uptr)addr);
239 }
240
__tsan_release_merge(ThreadState * thr,void * addr)241 void __tsan_release_merge(ThreadState *thr, void *addr) {
242 Release(thr, 0, (uptr)addr);
243 }
244
__tsan_finalizer_goroutine(ThreadState * thr)245 void __tsan_finalizer_goroutine(ThreadState *thr) {
246 AcquireGlobal(thr, 0);
247 }
248
__tsan_mutex_before_lock(ThreadState * thr,uptr addr,uptr write)249 void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
250 }
251
__tsan_mutex_after_lock(ThreadState * thr,uptr addr,uptr write)252 void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
253 if (write)
254 MutexLock(thr, 0, addr);
255 else
256 MutexReadLock(thr, 0, addr);
257 }
258
__tsan_mutex_before_unlock(ThreadState * thr,uptr addr,uptr write)259 void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
260 if (write)
261 MutexUnlock(thr, 0, addr);
262 else
263 MutexReadUnlock(thr, 0, addr);
264 }
265
__tsan_go_ignore_sync_begin(ThreadState * thr)266 void __tsan_go_ignore_sync_begin(ThreadState *thr) {
267 ThreadIgnoreSyncBegin(thr, 0);
268 }
269
__tsan_go_ignore_sync_end(ThreadState * thr)270 void __tsan_go_ignore_sync_end(ThreadState *thr) {
271 ThreadIgnoreSyncEnd(thr, 0);
272 }
273
274 } // extern "C"
275 } // namespace __tsan
276
277 namespace __sanitizer {
278
SymbolizerPrepareForSandboxing()279 void SymbolizerPrepareForSandboxing() {
280 // Nothing to do here for Go.
281 }
282
283 } // namespace __sanitizer
284