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