xref: /openbsd-src/gnu/llvm/compiler-rt/lib/tsan/go/tsan_go.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- tsan_go.cpp -------------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // ThreadSanitizer runtime for Go language.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick 
133cab2bb3Spatrick #include "tsan_rtl.h"
143cab2bb3Spatrick #include "tsan_symbolize.h"
153cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
163cab2bb3Spatrick #include <stdlib.h>
173cab2bb3Spatrick 
183cab2bb3Spatrick namespace __tsan {
193cab2bb3Spatrick 
InitializeInterceptors()203cab2bb3Spatrick void InitializeInterceptors() {
213cab2bb3Spatrick }
223cab2bb3Spatrick 
InitializeDynamicAnnotations()233cab2bb3Spatrick void InitializeDynamicAnnotations() {
243cab2bb3Spatrick }
253cab2bb3Spatrick 
IsExpectedReport(uptr addr,uptr size)263cab2bb3Spatrick bool IsExpectedReport(uptr addr, uptr size) {
273cab2bb3Spatrick   return false;
283cab2bb3Spatrick }
293cab2bb3Spatrick 
Alloc(uptr sz)30*810390e3Srobert void *Alloc(uptr sz) { return InternalAlloc(sz); }
313cab2bb3Spatrick 
FreeImpl(void * p)32*810390e3Srobert void FreeImpl(void *p) { InternalFree(p); }
333cab2bb3Spatrick 
343cab2bb3Spatrick // Callback into Go.
353cab2bb3Spatrick static void (*go_runtime_cb)(uptr cmd, void *ctx);
363cab2bb3Spatrick 
373cab2bb3Spatrick enum {
383cab2bb3Spatrick   CallbackGetProc = 0,
393cab2bb3Spatrick   CallbackSymbolizeCode = 1,
403cab2bb3Spatrick   CallbackSymbolizeData = 2,
413cab2bb3Spatrick };
423cab2bb3Spatrick 
433cab2bb3Spatrick struct SymbolizeCodeContext {
443cab2bb3Spatrick   uptr pc;
453cab2bb3Spatrick   char *func;
463cab2bb3Spatrick   char *file;
473cab2bb3Spatrick   uptr line;
483cab2bb3Spatrick   uptr off;
493cab2bb3Spatrick   uptr res;
503cab2bb3Spatrick };
513cab2bb3Spatrick 
SymbolizeCode(uptr addr)523cab2bb3Spatrick SymbolizedStack *SymbolizeCode(uptr addr) {
533cab2bb3Spatrick   SymbolizedStack *first = SymbolizedStack::New(addr);
543cab2bb3Spatrick   SymbolizedStack *s = first;
553cab2bb3Spatrick   for (;;) {
563cab2bb3Spatrick     SymbolizeCodeContext cbctx;
573cab2bb3Spatrick     internal_memset(&cbctx, 0, sizeof(cbctx));
583cab2bb3Spatrick     cbctx.pc = addr;
593cab2bb3Spatrick     go_runtime_cb(CallbackSymbolizeCode, &cbctx);
603cab2bb3Spatrick     if (cbctx.res == 0)
613cab2bb3Spatrick       break;
623cab2bb3Spatrick     AddressInfo &info = s->info;
633cab2bb3Spatrick     info.module_offset = cbctx.off;
643cab2bb3Spatrick     info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
653cab2bb3Spatrick     info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
663cab2bb3Spatrick     info.line = cbctx.line;
673cab2bb3Spatrick     info.column = 0;
683cab2bb3Spatrick 
693cab2bb3Spatrick     if (cbctx.pc == addr) // outermost (non-inlined) function
703cab2bb3Spatrick       break;
713cab2bb3Spatrick     addr = cbctx.pc;
723cab2bb3Spatrick     // Allocate a stack entry for the parent of the inlined function.
733cab2bb3Spatrick     SymbolizedStack *s2 = SymbolizedStack::New(addr);
743cab2bb3Spatrick     s->next = s2;
753cab2bb3Spatrick     s = s2;
763cab2bb3Spatrick   }
773cab2bb3Spatrick   return first;
783cab2bb3Spatrick }
793cab2bb3Spatrick 
803cab2bb3Spatrick struct SymbolizeDataContext {
813cab2bb3Spatrick   uptr addr;
823cab2bb3Spatrick   uptr heap;
833cab2bb3Spatrick   uptr start;
843cab2bb3Spatrick   uptr size;
853cab2bb3Spatrick   char *name;
863cab2bb3Spatrick   char *file;
873cab2bb3Spatrick   uptr line;
883cab2bb3Spatrick   uptr res;
893cab2bb3Spatrick };
903cab2bb3Spatrick 
SymbolizeData(uptr addr)913cab2bb3Spatrick ReportLocation *SymbolizeData(uptr addr) {
923cab2bb3Spatrick   SymbolizeDataContext cbctx;
933cab2bb3Spatrick   internal_memset(&cbctx, 0, sizeof(cbctx));
943cab2bb3Spatrick   cbctx.addr = addr;
953cab2bb3Spatrick   go_runtime_cb(CallbackSymbolizeData, &cbctx);
963cab2bb3Spatrick   if (!cbctx.res)
973cab2bb3Spatrick     return 0;
983cab2bb3Spatrick   if (cbctx.heap) {
993cab2bb3Spatrick     MBlock *b = ctx->metamap.GetBlock(cbctx.start);
1003cab2bb3Spatrick     if (!b)
1013cab2bb3Spatrick       return 0;
102*810390e3Srobert     auto *loc = New<ReportLocation>();
103*810390e3Srobert     loc->type = ReportLocationHeap;
1043cab2bb3Spatrick     loc->heap_chunk_start = cbctx.start;
1053cab2bb3Spatrick     loc->heap_chunk_size = b->siz;
1063cab2bb3Spatrick     loc->tid = b->tid;
1073cab2bb3Spatrick     loc->stack = SymbolizeStackId(b->stk);
1083cab2bb3Spatrick     return loc;
1093cab2bb3Spatrick   } else {
110*810390e3Srobert     auto *loc = New<ReportLocation>();
111*810390e3Srobert     loc->type = ReportLocationGlobal;
1123cab2bb3Spatrick     loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??");
1133cab2bb3Spatrick     loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??");
1143cab2bb3Spatrick     loc->global.line = cbctx.line;
1153cab2bb3Spatrick     loc->global.start = cbctx.start;
1163cab2bb3Spatrick     loc->global.size = cbctx.size;
1173cab2bb3Spatrick     return loc;
1183cab2bb3Spatrick   }
1193cab2bb3Spatrick }
1203cab2bb3Spatrick 
1213cab2bb3Spatrick static ThreadState *main_thr;
1223cab2bb3Spatrick static bool inited;
1233cab2bb3Spatrick 
get_cur_proc()1243cab2bb3Spatrick static Processor* get_cur_proc() {
1253cab2bb3Spatrick   if (UNLIKELY(!inited)) {
1263cab2bb3Spatrick     // Running Initialize().
1273cab2bb3Spatrick     // We have not yet returned the Processor to Go, so we cannot ask it back.
1283cab2bb3Spatrick     // Currently, Initialize() does not use the Processor, so return nullptr.
1293cab2bb3Spatrick     return nullptr;
1303cab2bb3Spatrick   }
1313cab2bb3Spatrick   Processor *proc;
1323cab2bb3Spatrick   go_runtime_cb(CallbackGetProc, &proc);
1333cab2bb3Spatrick   return proc;
1343cab2bb3Spatrick }
1353cab2bb3Spatrick 
proc()1363cab2bb3Spatrick Processor *ThreadState::proc() {
1373cab2bb3Spatrick   return get_cur_proc();
1383cab2bb3Spatrick }
1393cab2bb3Spatrick 
1403cab2bb3Spatrick extern "C" {
1413cab2bb3Spatrick 
AllocGoroutine()1423cab2bb3Spatrick static ThreadState *AllocGoroutine() {
143*810390e3Srobert   auto *thr = (ThreadState *)Alloc(sizeof(ThreadState));
1443cab2bb3Spatrick   internal_memset(thr, 0, sizeof(*thr));
1453cab2bb3Spatrick   return thr;
1463cab2bb3Spatrick }
1473cab2bb3Spatrick 
__tsan_init(ThreadState ** thrp,Processor ** procp,void (* cb)(uptr cmd,void * cb))1483cab2bb3Spatrick void __tsan_init(ThreadState **thrp, Processor **procp,
1493cab2bb3Spatrick                  void (*cb)(uptr cmd, void *cb)) {
1503cab2bb3Spatrick   go_runtime_cb = cb;
1513cab2bb3Spatrick   ThreadState *thr = AllocGoroutine();
1523cab2bb3Spatrick   main_thr = *thrp = thr;
1533cab2bb3Spatrick   Initialize(thr);
1543cab2bb3Spatrick   *procp = thr->proc1;
1553cab2bb3Spatrick   inited = true;
1563cab2bb3Spatrick }
1573cab2bb3Spatrick 
__tsan_fini()1583cab2bb3Spatrick void __tsan_fini() {
1593cab2bb3Spatrick   // FIXME: Not necessary thread 0.
1603cab2bb3Spatrick   ThreadState *thr = main_thr;
1613cab2bb3Spatrick   int res = Finalize(thr);
1623cab2bb3Spatrick   exit(res);
1633cab2bb3Spatrick }
1643cab2bb3Spatrick 
__tsan_map_shadow(uptr addr,uptr size)1653cab2bb3Spatrick void __tsan_map_shadow(uptr addr, uptr size) {
1663cab2bb3Spatrick   MapShadow(addr, size);
1673cab2bb3Spatrick }
1683cab2bb3Spatrick 
__tsan_read(ThreadState * thr,void * addr,void * pc)1693cab2bb3Spatrick void __tsan_read(ThreadState *thr, void *addr, void *pc) {
170*810390e3Srobert   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessRead);
1713cab2bb3Spatrick }
1723cab2bb3Spatrick 
__tsan_read_pc(ThreadState * thr,void * addr,uptr callpc,uptr pc)1733cab2bb3Spatrick void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
1743cab2bb3Spatrick   if (callpc != 0)
1753cab2bb3Spatrick     FuncEntry(thr, callpc);
176*810390e3Srobert   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessRead);
1773cab2bb3Spatrick   if (callpc != 0)
1783cab2bb3Spatrick     FuncExit(thr);
1793cab2bb3Spatrick }
1803cab2bb3Spatrick 
__tsan_write(ThreadState * thr,void * addr,void * pc)1813cab2bb3Spatrick void __tsan_write(ThreadState *thr, void *addr, void *pc) {
182*810390e3Srobert   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessWrite);
1833cab2bb3Spatrick }
1843cab2bb3Spatrick 
__tsan_write_pc(ThreadState * thr,void * addr,uptr callpc,uptr pc)1853cab2bb3Spatrick void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
1863cab2bb3Spatrick   if (callpc != 0)
1873cab2bb3Spatrick     FuncEntry(thr, callpc);
188*810390e3Srobert   MemoryAccess(thr, (uptr)pc, (uptr)addr, 1, kAccessWrite);
1893cab2bb3Spatrick   if (callpc != 0)
1903cab2bb3Spatrick     FuncExit(thr);
1913cab2bb3Spatrick }
1923cab2bb3Spatrick 
__tsan_read_range(ThreadState * thr,void * addr,uptr size,uptr pc)1933cab2bb3Spatrick void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
1943cab2bb3Spatrick   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
1953cab2bb3Spatrick }
1963cab2bb3Spatrick 
__tsan_write_range(ThreadState * thr,void * addr,uptr size,uptr pc)1973cab2bb3Spatrick void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
1983cab2bb3Spatrick   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
1993cab2bb3Spatrick }
2003cab2bb3Spatrick 
__tsan_func_enter(ThreadState * thr,void * pc)2013cab2bb3Spatrick void __tsan_func_enter(ThreadState *thr, void *pc) {
2023cab2bb3Spatrick   FuncEntry(thr, (uptr)pc);
2033cab2bb3Spatrick }
2043cab2bb3Spatrick 
__tsan_func_exit(ThreadState * thr)2053cab2bb3Spatrick void __tsan_func_exit(ThreadState *thr) {
2063cab2bb3Spatrick   FuncExit(thr);
2073cab2bb3Spatrick }
2083cab2bb3Spatrick 
__tsan_malloc(ThreadState * thr,uptr pc,uptr p,uptr sz)2093cab2bb3Spatrick void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) {
2103cab2bb3Spatrick   CHECK(inited);
2113cab2bb3Spatrick   if (thr && pc)
2123cab2bb3Spatrick     ctx->metamap.AllocBlock(thr, pc, p, sz);
213*810390e3Srobert   MemoryResetRange(thr, pc, (uptr)p, sz);
2143cab2bb3Spatrick }
2153cab2bb3Spatrick 
__tsan_free(uptr p,uptr sz)2163cab2bb3Spatrick void __tsan_free(uptr p, uptr sz) {
217*810390e3Srobert   ctx->metamap.FreeRange(get_cur_proc(), p, sz, false);
2183cab2bb3Spatrick }
2193cab2bb3Spatrick 
__tsan_go_start(ThreadState * parent,ThreadState ** pthr,void * pc)2203cab2bb3Spatrick void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
2213cab2bb3Spatrick   ThreadState *thr = AllocGoroutine();
2223cab2bb3Spatrick   *pthr = thr;
223*810390e3Srobert   Tid goid = ThreadCreate(parent, (uptr)pc, 0, true);
2243cab2bb3Spatrick   ThreadStart(thr, goid, 0, ThreadType::Regular);
2253cab2bb3Spatrick }
2263cab2bb3Spatrick 
__tsan_go_end(ThreadState * thr)2273cab2bb3Spatrick void __tsan_go_end(ThreadState *thr) {
2283cab2bb3Spatrick   ThreadFinish(thr);
229*810390e3Srobert   Free(thr);
2303cab2bb3Spatrick }
2313cab2bb3Spatrick 
__tsan_proc_create(Processor ** pproc)2323cab2bb3Spatrick void __tsan_proc_create(Processor **pproc) {
2333cab2bb3Spatrick   *pproc = ProcCreate();
2343cab2bb3Spatrick }
2353cab2bb3Spatrick 
__tsan_proc_destroy(Processor * proc)2363cab2bb3Spatrick void __tsan_proc_destroy(Processor *proc) {
2373cab2bb3Spatrick   ProcDestroy(proc);
2383cab2bb3Spatrick }
2393cab2bb3Spatrick 
__tsan_acquire(ThreadState * thr,void * addr)2403cab2bb3Spatrick void __tsan_acquire(ThreadState *thr, void *addr) {
2413cab2bb3Spatrick   Acquire(thr, 0, (uptr)addr);
2423cab2bb3Spatrick }
2433cab2bb3Spatrick 
__tsan_release_acquire(ThreadState * thr,void * addr)2441f9cb04fSpatrick void __tsan_release_acquire(ThreadState *thr, void *addr) {
2451f9cb04fSpatrick   ReleaseStoreAcquire(thr, 0, (uptr)addr);
2461f9cb04fSpatrick }
2471f9cb04fSpatrick 
__tsan_release(ThreadState * thr,void * addr)2483cab2bb3Spatrick void __tsan_release(ThreadState *thr, void *addr) {
2493cab2bb3Spatrick   ReleaseStore(thr, 0, (uptr)addr);
2503cab2bb3Spatrick }
2513cab2bb3Spatrick 
__tsan_release_merge(ThreadState * thr,void * addr)2523cab2bb3Spatrick void __tsan_release_merge(ThreadState *thr, void *addr) {
2533cab2bb3Spatrick   Release(thr, 0, (uptr)addr);
2543cab2bb3Spatrick }
2553cab2bb3Spatrick 
__tsan_finalizer_goroutine(ThreadState * thr)256*810390e3Srobert void __tsan_finalizer_goroutine(ThreadState *thr) { AcquireGlobal(thr); }
2573cab2bb3Spatrick 
__tsan_mutex_before_lock(ThreadState * thr,uptr addr,uptr write)2583cab2bb3Spatrick void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
2593cab2bb3Spatrick   if (write)
2603cab2bb3Spatrick     MutexPreLock(thr, 0, addr);
2613cab2bb3Spatrick   else
2623cab2bb3Spatrick     MutexPreReadLock(thr, 0, addr);
2633cab2bb3Spatrick }
2643cab2bb3Spatrick 
__tsan_mutex_after_lock(ThreadState * thr,uptr addr,uptr write)2653cab2bb3Spatrick void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
2663cab2bb3Spatrick   if (write)
2673cab2bb3Spatrick     MutexPostLock(thr, 0, addr);
2683cab2bb3Spatrick   else
2693cab2bb3Spatrick     MutexPostReadLock(thr, 0, addr);
2703cab2bb3Spatrick }
2713cab2bb3Spatrick 
__tsan_mutex_before_unlock(ThreadState * thr,uptr addr,uptr write)2723cab2bb3Spatrick void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
2733cab2bb3Spatrick   if (write)
2743cab2bb3Spatrick     MutexUnlock(thr, 0, addr);
2753cab2bb3Spatrick   else
2763cab2bb3Spatrick     MutexReadUnlock(thr, 0, addr);
2773cab2bb3Spatrick }
2783cab2bb3Spatrick 
__tsan_go_ignore_sync_begin(ThreadState * thr)2793cab2bb3Spatrick void __tsan_go_ignore_sync_begin(ThreadState *thr) {
2803cab2bb3Spatrick   ThreadIgnoreSyncBegin(thr, 0);
2813cab2bb3Spatrick }
2823cab2bb3Spatrick 
__tsan_go_ignore_sync_end(ThreadState * thr)283*810390e3Srobert void __tsan_go_ignore_sync_end(ThreadState *thr) { ThreadIgnoreSyncEnd(thr); }
2843cab2bb3Spatrick 
__tsan_report_count(u64 * pn)2853cab2bb3Spatrick void __tsan_report_count(u64 *pn) {
2863cab2bb3Spatrick   Lock lock(&ctx->report_mtx);
2873cab2bb3Spatrick   *pn = ctx->nreported;
2883cab2bb3Spatrick }
2893cab2bb3Spatrick 
2903cab2bb3Spatrick }  // extern "C"
2913cab2bb3Spatrick }  // namespace __tsan
292