168d75effSDimitry Andric //===-- tsan_go.cpp -------------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // ThreadSanitizer runtime for Go language.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "tsan_rtl.h"
1468d75effSDimitry Andric #include "tsan_symbolize.h"
1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1668d75effSDimitry Andric #include <stdlib.h>
1768d75effSDimitry Andric 
1868d75effSDimitry Andric namespace __tsan {
1968d75effSDimitry Andric 
InitializeInterceptors()2068d75effSDimitry Andric void InitializeInterceptors() {
2168d75effSDimitry Andric }
2268d75effSDimitry Andric 
InitializeDynamicAnnotations()2368d75effSDimitry Andric void InitializeDynamicAnnotations() {
2468d75effSDimitry Andric }
2568d75effSDimitry Andric 
IsExpectedReport(uptr addr,uptr size)2668d75effSDimitry Andric bool IsExpectedReport(uptr addr, uptr size) {
2768d75effSDimitry Andric   return false;
2868d75effSDimitry Andric }
2968d75effSDimitry Andric 
Alloc(uptr sz)30349cc55cSDimitry Andric void *Alloc(uptr sz) { return InternalAlloc(sz); }
3168d75effSDimitry Andric 
FreeImpl(void * p)32349cc55cSDimitry Andric void FreeImpl(void *p) { InternalFree(p); }
3368d75effSDimitry Andric 
3468d75effSDimitry Andric // Callback into Go.
3568d75effSDimitry Andric static void (*go_runtime_cb)(uptr cmd, void *ctx);
3668d75effSDimitry Andric 
3768d75effSDimitry Andric enum {
3868d75effSDimitry Andric   CallbackGetProc = 0,
3968d75effSDimitry Andric   CallbackSymbolizeCode = 1,
4068d75effSDimitry Andric   CallbackSymbolizeData = 2,
4168d75effSDimitry Andric };
4268d75effSDimitry Andric 
4368d75effSDimitry Andric struct SymbolizeCodeContext {
4468d75effSDimitry Andric   uptr pc;
4568d75effSDimitry Andric   char *func;
4668d75effSDimitry Andric   char *file;
4768d75effSDimitry Andric   uptr line;
4868d75effSDimitry Andric   uptr off;
4968d75effSDimitry Andric   uptr res;
5068d75effSDimitry Andric };
5168d75effSDimitry Andric 
SymbolizeCode(uptr addr)5268d75effSDimitry Andric SymbolizedStack *SymbolizeCode(uptr addr) {
5368d75effSDimitry Andric   SymbolizedStack *first = SymbolizedStack::New(addr);
5468d75effSDimitry Andric   SymbolizedStack *s = first;
5568d75effSDimitry Andric   for (;;) {
5668d75effSDimitry Andric     SymbolizeCodeContext cbctx;
5768d75effSDimitry Andric     internal_memset(&cbctx, 0, sizeof(cbctx));
5868d75effSDimitry Andric     cbctx.pc = addr;
5968d75effSDimitry Andric     go_runtime_cb(CallbackSymbolizeCode, &cbctx);
6068d75effSDimitry Andric     if (cbctx.res == 0)
6168d75effSDimitry Andric       break;
6268d75effSDimitry Andric     AddressInfo &info = s->info;
6368d75effSDimitry Andric     info.module_offset = cbctx.off;
6468d75effSDimitry Andric     info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
6568d75effSDimitry Andric     info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
6668d75effSDimitry Andric     info.line = cbctx.line;
6768d75effSDimitry Andric     info.column = 0;
6868d75effSDimitry Andric 
6968d75effSDimitry Andric     if (cbctx.pc == addr) // outermost (non-inlined) function
7068d75effSDimitry Andric       break;
7168d75effSDimitry Andric     addr = cbctx.pc;
7268d75effSDimitry Andric     // Allocate a stack entry for the parent of the inlined function.
7368d75effSDimitry Andric     SymbolizedStack *s2 = SymbolizedStack::New(addr);
7468d75effSDimitry Andric     s->next = s2;
7568d75effSDimitry Andric     s = s2;
7668d75effSDimitry Andric   }
7768d75effSDimitry Andric   return first;
7868d75effSDimitry Andric }
7968d75effSDimitry Andric 
8068d75effSDimitry Andric struct SymbolizeDataContext {
8168d75effSDimitry Andric   uptr addr;
8268d75effSDimitry Andric   uptr heap;
8368d75effSDimitry Andric   uptr start;
8468d75effSDimitry Andric   uptr size;
8568d75effSDimitry Andric   char *name;
8668d75effSDimitry Andric   char *file;
8768d75effSDimitry Andric   uptr line;
8868d75effSDimitry Andric   uptr res;
8968d75effSDimitry Andric };
9068d75effSDimitry Andric 
SymbolizeData(uptr addr)9168d75effSDimitry Andric ReportLocation *SymbolizeData(uptr addr) {
9268d75effSDimitry Andric   SymbolizeDataContext cbctx;
9368d75effSDimitry Andric   internal_memset(&cbctx, 0, sizeof(cbctx));
9468d75effSDimitry Andric   cbctx.addr = addr;
9568d75effSDimitry Andric   go_runtime_cb(CallbackSymbolizeData, &cbctx);
9668d75effSDimitry Andric   if (!cbctx.res)
9768d75effSDimitry Andric     return 0;
9868d75effSDimitry Andric   if (cbctx.heap) {
9968d75effSDimitry Andric     MBlock *b = ctx->metamap.GetBlock(cbctx.start);
10068d75effSDimitry Andric     if (!b)
10168d75effSDimitry Andric       return 0;
102349cc55cSDimitry Andric     auto *loc = New<ReportLocation>();
103349cc55cSDimitry Andric     loc->type = ReportLocationHeap;
10468d75effSDimitry Andric     loc->heap_chunk_start = cbctx.start;
10568d75effSDimitry Andric     loc->heap_chunk_size = b->siz;
10668d75effSDimitry Andric     loc->tid = b->tid;
10768d75effSDimitry Andric     loc->stack = SymbolizeStackId(b->stk);
10868d75effSDimitry Andric     return loc;
10968d75effSDimitry Andric   } else {
110349cc55cSDimitry Andric     auto *loc = New<ReportLocation>();
111349cc55cSDimitry Andric     loc->type = ReportLocationGlobal;
11268d75effSDimitry Andric     loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??");
11368d75effSDimitry Andric     loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??");
11468d75effSDimitry Andric     loc->global.line = cbctx.line;
11568d75effSDimitry Andric     loc->global.start = cbctx.start;
11668d75effSDimitry Andric     loc->global.size = cbctx.size;
11768d75effSDimitry Andric     return loc;
11868d75effSDimitry Andric   }
11968d75effSDimitry Andric }
12068d75effSDimitry Andric 
12168d75effSDimitry Andric static ThreadState *main_thr;
12268d75effSDimitry Andric static bool inited;
12368d75effSDimitry Andric 
get_cur_proc()12468d75effSDimitry Andric static Processor* get_cur_proc() {
12568d75effSDimitry Andric   if (UNLIKELY(!inited)) {
12668d75effSDimitry Andric     // Running Initialize().
12768d75effSDimitry Andric     // We have not yet returned the Processor to Go, so we cannot ask it back.
12868d75effSDimitry Andric     // Currently, Initialize() does not use the Processor, so return nullptr.
12968d75effSDimitry Andric     return nullptr;
13068d75effSDimitry Andric   }
13168d75effSDimitry Andric   Processor *proc;
13268d75effSDimitry Andric   go_runtime_cb(CallbackGetProc, &proc);
13368d75effSDimitry Andric   return proc;
13468d75effSDimitry Andric }
13568d75effSDimitry Andric 
proc()13668d75effSDimitry Andric Processor *ThreadState::proc() {
13768d75effSDimitry Andric   return get_cur_proc();
13868d75effSDimitry Andric }
13968d75effSDimitry Andric 
14068d75effSDimitry Andric extern "C" {
14168d75effSDimitry Andric 
AllocGoroutine()14268d75effSDimitry Andric static ThreadState *AllocGoroutine() {
143349cc55cSDimitry Andric   auto *thr = (ThreadState *)Alloc(sizeof(ThreadState));
14468d75effSDimitry Andric   internal_memset(thr, 0, sizeof(*thr));
14568d75effSDimitry Andric   return thr;
14668d75effSDimitry Andric }
14768d75effSDimitry Andric 
__tsan_init(ThreadState ** thrp,Processor ** procp,void (* cb)(uptr cmd,void * cb))14868d75effSDimitry Andric void __tsan_init(ThreadState **thrp, Processor **procp,
14968d75effSDimitry Andric                  void (*cb)(uptr cmd, void *cb)) {
15068d75effSDimitry Andric   go_runtime_cb = cb;
15168d75effSDimitry Andric   ThreadState *thr = AllocGoroutine();
15268d75effSDimitry Andric   main_thr = *thrp = thr;
15368d75effSDimitry Andric   Initialize(thr);
15468d75effSDimitry Andric   *procp = thr->proc1;
15568d75effSDimitry Andric   inited = true;
15668d75effSDimitry Andric }
15768d75effSDimitry Andric 
__tsan_fini()15868d75effSDimitry Andric void __tsan_fini() {
15968d75effSDimitry Andric   // FIXME: Not necessary thread 0.
16068d75effSDimitry Andric   ThreadState *thr = main_thr;
16168d75effSDimitry Andric   int res = Finalize(thr);
16268d75effSDimitry Andric   exit(res);
16368d75effSDimitry Andric }
16468d75effSDimitry Andric 
__tsan_map_shadow(uptr addr,uptr size)16568d75effSDimitry Andric void __tsan_map_shadow(uptr addr, uptr size) {
16668d75effSDimitry Andric   MapShadow(addr, size);
16768d75effSDimitry Andric }
16868d75effSDimitry Andric 
__tsan_read(ThreadState * thr,void * addr,void * pc)16968d75effSDimitry Andric void __tsan_read(ThreadState *thr, void *addr, void *pc) {
170349cc55cSDimitry Andric   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessRead);
17168d75effSDimitry Andric }
17268d75effSDimitry Andric 
__tsan_read_pc(ThreadState * thr,void * addr,uptr callpc,uptr pc)17368d75effSDimitry Andric void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
17468d75effSDimitry Andric   if (callpc != 0)
17568d75effSDimitry Andric     FuncEntry(thr, callpc);
176349cc55cSDimitry Andric   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessRead);
17768d75effSDimitry Andric   if (callpc != 0)
17868d75effSDimitry Andric     FuncExit(thr);
17968d75effSDimitry Andric }
18068d75effSDimitry Andric 
__tsan_write(ThreadState * thr,void * addr,void * pc)18168d75effSDimitry Andric void __tsan_write(ThreadState *thr, void *addr, void *pc) {
182349cc55cSDimitry Andric   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessWrite);
18368d75effSDimitry Andric }
18468d75effSDimitry Andric 
__tsan_write_pc(ThreadState * thr,void * addr,uptr callpc,uptr pc)18568d75effSDimitry Andric void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
18668d75effSDimitry Andric   if (callpc != 0)
18768d75effSDimitry Andric     FuncEntry(thr, callpc);
188349cc55cSDimitry Andric   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessWrite);
18968d75effSDimitry Andric   if (callpc != 0)
19068d75effSDimitry Andric     FuncExit(thr);
19168d75effSDimitry Andric }
19268d75effSDimitry Andric 
__tsan_read_range(ThreadState * thr,void * addr,uptr size,uptr pc)19368d75effSDimitry Andric void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
19468d75effSDimitry Andric   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
19568d75effSDimitry Andric }
19668d75effSDimitry Andric 
__tsan_write_range(ThreadState * thr,void * addr,uptr size,uptr pc)19768d75effSDimitry Andric void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
19868d75effSDimitry Andric   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
19968d75effSDimitry Andric }
20068d75effSDimitry Andric 
__tsan_func_enter(ThreadState * thr,void * pc)20168d75effSDimitry Andric void __tsan_func_enter(ThreadState *thr, void *pc) {
20268d75effSDimitry Andric   FuncEntry(thr, (uptr)pc);
20368d75effSDimitry Andric }
20468d75effSDimitry Andric 
__tsan_func_exit(ThreadState * thr)20568d75effSDimitry Andric void __tsan_func_exit(ThreadState *thr) {
20668d75effSDimitry Andric   FuncExit(thr);
20768d75effSDimitry Andric }
20868d75effSDimitry Andric 
__tsan_malloc(ThreadState * thr,uptr pc,uptr p,uptr sz)20968d75effSDimitry Andric void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) {
21068d75effSDimitry Andric   CHECK(inited);
21168d75effSDimitry Andric   if (thr && pc)
21268d75effSDimitry Andric     ctx->metamap.AllocBlock(thr, pc, p, sz);
213349cc55cSDimitry Andric   MemoryResetRange(thr, pc, (uptr)p, sz);
21468d75effSDimitry Andric }
21568d75effSDimitry Andric 
__tsan_free(uptr p,uptr sz)21668d75effSDimitry Andric void __tsan_free(uptr p, uptr sz) {
217*0eae32dcSDimitry Andric   ctx->metamap.FreeRange(get_cur_proc(), p, sz, false);
21868d75effSDimitry Andric }
21968d75effSDimitry Andric 
__tsan_go_start(ThreadState * parent,ThreadState ** pthr,void * pc)22068d75effSDimitry Andric void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
22168d75effSDimitry Andric   ThreadState *thr = AllocGoroutine();
22268d75effSDimitry Andric   *pthr = thr;
223349cc55cSDimitry Andric   Tid goid = ThreadCreate(parent, (uptr)pc, 0, true);
22468d75effSDimitry Andric   ThreadStart(thr, goid, 0, ThreadType::Regular);
22568d75effSDimitry Andric }
22668d75effSDimitry Andric 
__tsan_go_end(ThreadState * thr)22768d75effSDimitry Andric void __tsan_go_end(ThreadState *thr) {
22868d75effSDimitry Andric   ThreadFinish(thr);
229349cc55cSDimitry Andric   Free(thr);
23068d75effSDimitry Andric }
23168d75effSDimitry Andric 
__tsan_proc_create(Processor ** pproc)23268d75effSDimitry Andric void __tsan_proc_create(Processor **pproc) {
23368d75effSDimitry Andric   *pproc = ProcCreate();
23468d75effSDimitry Andric }
23568d75effSDimitry Andric 
__tsan_proc_destroy(Processor * proc)23668d75effSDimitry Andric void __tsan_proc_destroy(Processor *proc) {
23768d75effSDimitry Andric   ProcDestroy(proc);
23868d75effSDimitry Andric }
23968d75effSDimitry Andric 
__tsan_acquire(ThreadState * thr,void * addr)24068d75effSDimitry Andric void __tsan_acquire(ThreadState *thr, void *addr) {
24168d75effSDimitry Andric   Acquire(thr, 0, (uptr)addr);
24268d75effSDimitry Andric }
24368d75effSDimitry Andric 
__tsan_release_acquire(ThreadState * thr,void * addr)2445ffd83dbSDimitry Andric void __tsan_release_acquire(ThreadState *thr, void *addr) {
2455ffd83dbSDimitry Andric   ReleaseStoreAcquire(thr, 0, (uptr)addr);
2465ffd83dbSDimitry Andric }
2475ffd83dbSDimitry Andric 
__tsan_release(ThreadState * thr,void * addr)24868d75effSDimitry Andric void __tsan_release(ThreadState *thr, void *addr) {
24968d75effSDimitry Andric   ReleaseStore(thr, 0, (uptr)addr);
25068d75effSDimitry Andric }
25168d75effSDimitry Andric 
__tsan_release_merge(ThreadState * thr,void * addr)25268d75effSDimitry Andric void __tsan_release_merge(ThreadState *thr, void *addr) {
25368d75effSDimitry Andric   Release(thr, 0, (uptr)addr);
25468d75effSDimitry Andric }
25568d75effSDimitry Andric 
__tsan_finalizer_goroutine(ThreadState * thr)256349cc55cSDimitry Andric void __tsan_finalizer_goroutine(ThreadState *thr) { AcquireGlobal(thr); }
25768d75effSDimitry Andric 
__tsan_mutex_before_lock(ThreadState * thr,uptr addr,uptr write)25868d75effSDimitry Andric void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
25968d75effSDimitry Andric   if (write)
26068d75effSDimitry Andric     MutexPreLock(thr, 0, addr);
26168d75effSDimitry Andric   else
26268d75effSDimitry Andric     MutexPreReadLock(thr, 0, addr);
26368d75effSDimitry Andric }
26468d75effSDimitry Andric 
__tsan_mutex_after_lock(ThreadState * thr,uptr addr,uptr write)26568d75effSDimitry Andric void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
26668d75effSDimitry Andric   if (write)
26768d75effSDimitry Andric     MutexPostLock(thr, 0, addr);
26868d75effSDimitry Andric   else
26968d75effSDimitry Andric     MutexPostReadLock(thr, 0, addr);
27068d75effSDimitry Andric }
27168d75effSDimitry Andric 
__tsan_mutex_before_unlock(ThreadState * thr,uptr addr,uptr write)27268d75effSDimitry Andric void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
27368d75effSDimitry Andric   if (write)
27468d75effSDimitry Andric     MutexUnlock(thr, 0, addr);
27568d75effSDimitry Andric   else
27668d75effSDimitry Andric     MutexReadUnlock(thr, 0, addr);
27768d75effSDimitry Andric }
27868d75effSDimitry Andric 
__tsan_go_ignore_sync_begin(ThreadState * thr)27968d75effSDimitry Andric void __tsan_go_ignore_sync_begin(ThreadState *thr) {
28068d75effSDimitry Andric   ThreadIgnoreSyncBegin(thr, 0);
28168d75effSDimitry Andric }
28268d75effSDimitry Andric 
__tsan_go_ignore_sync_end(ThreadState * thr)283349cc55cSDimitry Andric void __tsan_go_ignore_sync_end(ThreadState *thr) { ThreadIgnoreSyncEnd(thr); }
28468d75effSDimitry Andric 
__tsan_report_count(u64 * pn)28568d75effSDimitry Andric void __tsan_report_count(u64 *pn) {
28668d75effSDimitry Andric   Lock lock(&ctx->report_mtx);
28768d75effSDimitry Andric   *pn = ctx->nreported;
28868d75effSDimitry Andric }
28968d75effSDimitry Andric 
29068d75effSDimitry Andric }  // extern "C"
29168d75effSDimitry Andric }  // namespace __tsan
292