xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/go/tsan_go.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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 
2068d75effSDimitry Andric void InitializeInterceptors() {
2168d75effSDimitry Andric }
2268d75effSDimitry Andric 
2368d75effSDimitry Andric void InitializeDynamicAnnotations() {
2468d75effSDimitry Andric }
2568d75effSDimitry Andric 
2668d75effSDimitry Andric bool IsExpectedReport(uptr addr, uptr size) {
2768d75effSDimitry Andric   return false;
2868d75effSDimitry Andric }
2968d75effSDimitry Andric 
3068d75effSDimitry Andric void *internal_alloc(MBlockType typ, uptr sz) {
3168d75effSDimitry Andric   return InternalAlloc(sz);
3268d75effSDimitry Andric }
3368d75effSDimitry Andric 
3468d75effSDimitry Andric void internal_free(void *p) {
3568d75effSDimitry Andric   InternalFree(p);
3668d75effSDimitry Andric }
3768d75effSDimitry Andric 
3868d75effSDimitry Andric // Callback into Go.
3968d75effSDimitry Andric static void (*go_runtime_cb)(uptr cmd, void *ctx);
4068d75effSDimitry Andric 
4168d75effSDimitry Andric enum {
4268d75effSDimitry Andric   CallbackGetProc = 0,
4368d75effSDimitry Andric   CallbackSymbolizeCode = 1,
4468d75effSDimitry Andric   CallbackSymbolizeData = 2,
4568d75effSDimitry Andric };
4668d75effSDimitry Andric 
4768d75effSDimitry Andric struct SymbolizeCodeContext {
4868d75effSDimitry Andric   uptr pc;
4968d75effSDimitry Andric   char *func;
5068d75effSDimitry Andric   char *file;
5168d75effSDimitry Andric   uptr line;
5268d75effSDimitry Andric   uptr off;
5368d75effSDimitry Andric   uptr res;
5468d75effSDimitry Andric };
5568d75effSDimitry Andric 
5668d75effSDimitry Andric SymbolizedStack *SymbolizeCode(uptr addr) {
5768d75effSDimitry Andric   SymbolizedStack *first = SymbolizedStack::New(addr);
5868d75effSDimitry Andric   SymbolizedStack *s = first;
5968d75effSDimitry Andric   for (;;) {
6068d75effSDimitry Andric     SymbolizeCodeContext cbctx;
6168d75effSDimitry Andric     internal_memset(&cbctx, 0, sizeof(cbctx));
6268d75effSDimitry Andric     cbctx.pc = addr;
6368d75effSDimitry Andric     go_runtime_cb(CallbackSymbolizeCode, &cbctx);
6468d75effSDimitry Andric     if (cbctx.res == 0)
6568d75effSDimitry Andric       break;
6668d75effSDimitry Andric     AddressInfo &info = s->info;
6768d75effSDimitry Andric     info.module_offset = cbctx.off;
6868d75effSDimitry Andric     info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
6968d75effSDimitry Andric     info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
7068d75effSDimitry Andric     info.line = cbctx.line;
7168d75effSDimitry Andric     info.column = 0;
7268d75effSDimitry Andric 
7368d75effSDimitry Andric     if (cbctx.pc == addr) // outermost (non-inlined) function
7468d75effSDimitry Andric       break;
7568d75effSDimitry Andric     addr = cbctx.pc;
7668d75effSDimitry Andric     // Allocate a stack entry for the parent of the inlined function.
7768d75effSDimitry Andric     SymbolizedStack *s2 = SymbolizedStack::New(addr);
7868d75effSDimitry Andric     s->next = s2;
7968d75effSDimitry Andric     s = s2;
8068d75effSDimitry Andric   }
8168d75effSDimitry Andric   return first;
8268d75effSDimitry Andric }
8368d75effSDimitry Andric 
8468d75effSDimitry Andric struct SymbolizeDataContext {
8568d75effSDimitry Andric   uptr addr;
8668d75effSDimitry Andric   uptr heap;
8768d75effSDimitry Andric   uptr start;
8868d75effSDimitry Andric   uptr size;
8968d75effSDimitry Andric   char *name;
9068d75effSDimitry Andric   char *file;
9168d75effSDimitry Andric   uptr line;
9268d75effSDimitry Andric   uptr res;
9368d75effSDimitry Andric };
9468d75effSDimitry Andric 
9568d75effSDimitry Andric ReportLocation *SymbolizeData(uptr addr) {
9668d75effSDimitry Andric   SymbolizeDataContext cbctx;
9768d75effSDimitry Andric   internal_memset(&cbctx, 0, sizeof(cbctx));
9868d75effSDimitry Andric   cbctx.addr = addr;
9968d75effSDimitry Andric   go_runtime_cb(CallbackSymbolizeData, &cbctx);
10068d75effSDimitry Andric   if (!cbctx.res)
10168d75effSDimitry Andric     return 0;
10268d75effSDimitry Andric   if (cbctx.heap) {
10368d75effSDimitry Andric     MBlock *b = ctx->metamap.GetBlock(cbctx.start);
10468d75effSDimitry Andric     if (!b)
10568d75effSDimitry Andric       return 0;
10668d75effSDimitry Andric     ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
10768d75effSDimitry Andric     loc->heap_chunk_start = cbctx.start;
10868d75effSDimitry Andric     loc->heap_chunk_size = b->siz;
10968d75effSDimitry Andric     loc->tid = b->tid;
11068d75effSDimitry Andric     loc->stack = SymbolizeStackId(b->stk);
11168d75effSDimitry Andric     return loc;
11268d75effSDimitry Andric   } else {
11368d75effSDimitry Andric     ReportLocation *loc = ReportLocation::New(ReportLocationGlobal);
11468d75effSDimitry Andric     loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??");
11568d75effSDimitry Andric     loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??");
11668d75effSDimitry Andric     loc->global.line = cbctx.line;
11768d75effSDimitry Andric     loc->global.start = cbctx.start;
11868d75effSDimitry Andric     loc->global.size = cbctx.size;
11968d75effSDimitry Andric     return loc;
12068d75effSDimitry Andric   }
12168d75effSDimitry Andric }
12268d75effSDimitry Andric 
12368d75effSDimitry Andric static ThreadState *main_thr;
12468d75effSDimitry Andric static bool inited;
12568d75effSDimitry Andric 
12668d75effSDimitry Andric static Processor* get_cur_proc() {
12768d75effSDimitry Andric   if (UNLIKELY(!inited)) {
12868d75effSDimitry Andric     // Running Initialize().
12968d75effSDimitry Andric     // We have not yet returned the Processor to Go, so we cannot ask it back.
13068d75effSDimitry Andric     // Currently, Initialize() does not use the Processor, so return nullptr.
13168d75effSDimitry Andric     return nullptr;
13268d75effSDimitry Andric   }
13368d75effSDimitry Andric   Processor *proc;
13468d75effSDimitry Andric   go_runtime_cb(CallbackGetProc, &proc);
13568d75effSDimitry Andric   return proc;
13668d75effSDimitry Andric }
13768d75effSDimitry Andric 
13868d75effSDimitry Andric Processor *ThreadState::proc() {
13968d75effSDimitry Andric   return get_cur_proc();
14068d75effSDimitry Andric }
14168d75effSDimitry Andric 
14268d75effSDimitry Andric extern "C" {
14368d75effSDimitry Andric 
14468d75effSDimitry Andric static ThreadState *AllocGoroutine() {
14568d75effSDimitry Andric   ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
14668d75effSDimitry Andric       sizeof(ThreadState));
14768d75effSDimitry Andric   internal_memset(thr, 0, sizeof(*thr));
14868d75effSDimitry Andric   return thr;
14968d75effSDimitry Andric }
15068d75effSDimitry Andric 
15168d75effSDimitry Andric void __tsan_init(ThreadState **thrp, Processor **procp,
15268d75effSDimitry Andric                  void (*cb)(uptr cmd, void *cb)) {
15368d75effSDimitry Andric   go_runtime_cb = cb;
15468d75effSDimitry Andric   ThreadState *thr = AllocGoroutine();
15568d75effSDimitry Andric   main_thr = *thrp = thr;
15668d75effSDimitry Andric   Initialize(thr);
15768d75effSDimitry Andric   *procp = thr->proc1;
15868d75effSDimitry Andric   inited = true;
15968d75effSDimitry Andric }
16068d75effSDimitry Andric 
16168d75effSDimitry Andric void __tsan_fini() {
16268d75effSDimitry Andric   // FIXME: Not necessary thread 0.
16368d75effSDimitry Andric   ThreadState *thr = main_thr;
16468d75effSDimitry Andric   int res = Finalize(thr);
16568d75effSDimitry Andric   exit(res);
16668d75effSDimitry Andric }
16768d75effSDimitry Andric 
16868d75effSDimitry Andric void __tsan_map_shadow(uptr addr, uptr size) {
16968d75effSDimitry Andric   MapShadow(addr, size);
17068d75effSDimitry Andric }
17168d75effSDimitry Andric 
17268d75effSDimitry Andric void __tsan_read(ThreadState *thr, void *addr, void *pc) {
17368d75effSDimitry Andric   MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
17468d75effSDimitry Andric }
17568d75effSDimitry Andric 
17668d75effSDimitry Andric void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
17768d75effSDimitry Andric   if (callpc != 0)
17868d75effSDimitry Andric     FuncEntry(thr, callpc);
17968d75effSDimitry Andric   MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
18068d75effSDimitry Andric   if (callpc != 0)
18168d75effSDimitry Andric     FuncExit(thr);
18268d75effSDimitry Andric }
18368d75effSDimitry Andric 
18468d75effSDimitry Andric void __tsan_write(ThreadState *thr, void *addr, void *pc) {
18568d75effSDimitry Andric   MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
18668d75effSDimitry Andric }
18768d75effSDimitry Andric 
18868d75effSDimitry Andric void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
18968d75effSDimitry Andric   if (callpc != 0)
19068d75effSDimitry Andric     FuncEntry(thr, callpc);
19168d75effSDimitry Andric   MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
19268d75effSDimitry Andric   if (callpc != 0)
19368d75effSDimitry Andric     FuncExit(thr);
19468d75effSDimitry Andric }
19568d75effSDimitry Andric 
19668d75effSDimitry Andric void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
19768d75effSDimitry Andric   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
19868d75effSDimitry Andric }
19968d75effSDimitry Andric 
20068d75effSDimitry Andric void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
20168d75effSDimitry Andric   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
20268d75effSDimitry Andric }
20368d75effSDimitry Andric 
20468d75effSDimitry Andric void __tsan_func_enter(ThreadState *thr, void *pc) {
20568d75effSDimitry Andric   FuncEntry(thr, (uptr)pc);
20668d75effSDimitry Andric }
20768d75effSDimitry Andric 
20868d75effSDimitry Andric void __tsan_func_exit(ThreadState *thr) {
20968d75effSDimitry Andric   FuncExit(thr);
21068d75effSDimitry Andric }
21168d75effSDimitry Andric 
21268d75effSDimitry Andric void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) {
21368d75effSDimitry Andric   CHECK(inited);
21468d75effSDimitry Andric   if (thr && pc)
21568d75effSDimitry Andric     ctx->metamap.AllocBlock(thr, pc, p, sz);
21668d75effSDimitry Andric   MemoryResetRange(0, 0, (uptr)p, sz);
21768d75effSDimitry Andric }
21868d75effSDimitry Andric 
21968d75effSDimitry Andric void __tsan_free(uptr p, uptr sz) {
22068d75effSDimitry Andric   ctx->metamap.FreeRange(get_cur_proc(), p, sz);
22168d75effSDimitry Andric }
22268d75effSDimitry Andric 
22368d75effSDimitry Andric void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
22468d75effSDimitry Andric   ThreadState *thr = AllocGoroutine();
22568d75effSDimitry Andric   *pthr = thr;
22668d75effSDimitry Andric   int goid = ThreadCreate(parent, (uptr)pc, 0, true);
22768d75effSDimitry Andric   ThreadStart(thr, goid, 0, ThreadType::Regular);
22868d75effSDimitry Andric }
22968d75effSDimitry Andric 
23068d75effSDimitry Andric void __tsan_go_end(ThreadState *thr) {
23168d75effSDimitry Andric   ThreadFinish(thr);
23268d75effSDimitry Andric   internal_free(thr);
23368d75effSDimitry Andric }
23468d75effSDimitry Andric 
23568d75effSDimitry Andric void __tsan_proc_create(Processor **pproc) {
23668d75effSDimitry Andric   *pproc = ProcCreate();
23768d75effSDimitry Andric }
23868d75effSDimitry Andric 
23968d75effSDimitry Andric void __tsan_proc_destroy(Processor *proc) {
24068d75effSDimitry Andric   ProcDestroy(proc);
24168d75effSDimitry Andric }
24268d75effSDimitry Andric 
24368d75effSDimitry Andric void __tsan_acquire(ThreadState *thr, void *addr) {
24468d75effSDimitry Andric   Acquire(thr, 0, (uptr)addr);
24568d75effSDimitry Andric }
24668d75effSDimitry Andric 
247*5ffd83dbSDimitry Andric void __tsan_release_acquire(ThreadState *thr, void *addr) {
248*5ffd83dbSDimitry Andric   ReleaseStoreAcquire(thr, 0, (uptr)addr);
249*5ffd83dbSDimitry Andric }
250*5ffd83dbSDimitry Andric 
25168d75effSDimitry Andric void __tsan_release(ThreadState *thr, void *addr) {
25268d75effSDimitry Andric   ReleaseStore(thr, 0, (uptr)addr);
25368d75effSDimitry Andric }
25468d75effSDimitry Andric 
25568d75effSDimitry Andric void __tsan_release_merge(ThreadState *thr, void *addr) {
25668d75effSDimitry Andric   Release(thr, 0, (uptr)addr);
25768d75effSDimitry Andric }
25868d75effSDimitry Andric 
25968d75effSDimitry Andric void __tsan_finalizer_goroutine(ThreadState *thr) {
26068d75effSDimitry Andric   AcquireGlobal(thr, 0);
26168d75effSDimitry Andric }
26268d75effSDimitry Andric 
26368d75effSDimitry Andric void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
26468d75effSDimitry Andric   if (write)
26568d75effSDimitry Andric     MutexPreLock(thr, 0, addr);
26668d75effSDimitry Andric   else
26768d75effSDimitry Andric     MutexPreReadLock(thr, 0, addr);
26868d75effSDimitry Andric }
26968d75effSDimitry Andric 
27068d75effSDimitry Andric void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
27168d75effSDimitry Andric   if (write)
27268d75effSDimitry Andric     MutexPostLock(thr, 0, addr);
27368d75effSDimitry Andric   else
27468d75effSDimitry Andric     MutexPostReadLock(thr, 0, addr);
27568d75effSDimitry Andric }
27668d75effSDimitry Andric 
27768d75effSDimitry Andric void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
27868d75effSDimitry Andric   if (write)
27968d75effSDimitry Andric     MutexUnlock(thr, 0, addr);
28068d75effSDimitry Andric   else
28168d75effSDimitry Andric     MutexReadUnlock(thr, 0, addr);
28268d75effSDimitry Andric }
28368d75effSDimitry Andric 
28468d75effSDimitry Andric void __tsan_go_ignore_sync_begin(ThreadState *thr) {
28568d75effSDimitry Andric   ThreadIgnoreSyncBegin(thr, 0);
28668d75effSDimitry Andric }
28768d75effSDimitry Andric 
28868d75effSDimitry Andric void __tsan_go_ignore_sync_end(ThreadState *thr) {
28968d75effSDimitry Andric   ThreadIgnoreSyncEnd(thr, 0);
29068d75effSDimitry Andric }
29168d75effSDimitry Andric 
29268d75effSDimitry Andric void __tsan_report_count(u64 *pn) {
29368d75effSDimitry Andric   Lock lock(&ctx->report_mtx);
29468d75effSDimitry Andric   *pn = ctx->nreported;
29568d75effSDimitry Andric }
29668d75effSDimitry Andric 
29768d75effSDimitry Andric }  // extern "C"
29868d75effSDimitry Andric }  // namespace __tsan
299