//===-- tsan_go.cc --------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // ThreadSanitizer runtime for Go language. // //===----------------------------------------------------------------------===// #include "tsan_rtl.h" #include "tsan_symbolize.h" #include "sanitizer_common/sanitizer_common.h" #include namespace __tsan { void InitializeInterceptors() { } void InitializeDynamicAnnotations() { } bool IsExpectedReport(uptr addr, uptr size) { return false; } ReportLocation *SymbolizeData(uptr addr) { return 0; } void *internal_alloc(MBlockType typ, uptr sz) { return InternalAlloc(sz); } void internal_free(void *p) { InternalFree(p); } struct SymbolizeContext { uptr pc; char *func; char *file; uptr line; uptr off; uptr res; }; // Callback into Go. static void (*symbolize_cb)(SymbolizeContext *ctx); SymbolizedStack *SymbolizeCode(uptr addr) { SymbolizedStack *s = SymbolizedStack::New(addr); SymbolizeContext ctx; internal_memset(&ctx, 0, sizeof(ctx)); ctx.pc = addr; symbolize_cb(&ctx); if (ctx.res) { AddressInfo &info = s->info; info.module_offset = ctx.off; info.function = internal_strdup(ctx.func ? ctx.func : "??"); info.file = internal_strdup(ctx.file ? ctx.file : "-"); info.line = ctx.line; info.column = 0; } return s; } extern "C" { static ThreadState *main_thr; static bool inited; static ThreadState *AllocGoroutine() { ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex, sizeof(ThreadState)); internal_memset(thr, 0, sizeof(*thr)); return thr; } void __tsan_init(ThreadState **thrp, void (*cb)(SymbolizeContext *cb)) { symbolize_cb = cb; ThreadState *thr = AllocGoroutine(); main_thr = *thrp = thr; Initialize(thr); inited = true; } void __tsan_fini() { // FIXME: Not necessary thread 0. ThreadState *thr = main_thr; int res = Finalize(thr); exit(res); } void __tsan_map_shadow(uptr addr, uptr size) { MapShadow(addr, size); } void __tsan_read(ThreadState *thr, void *addr, void *pc) { MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1); } void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) { if (callpc != 0) FuncEntry(thr, callpc); MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1); if (callpc != 0) FuncExit(thr); } void __tsan_write(ThreadState *thr, void *addr, void *pc) { MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1); } void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) { if (callpc != 0) FuncEntry(thr, callpc); MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1); if (callpc != 0) FuncExit(thr); } void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) { MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false); } void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) { MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true); } void __tsan_func_enter(ThreadState *thr, void *pc) { FuncEntry(thr, (uptr)pc); } void __tsan_func_exit(ThreadState *thr) { FuncExit(thr); } void __tsan_malloc(void *p, uptr sz) { if (!inited) return; MemoryResetRange(0, 0, (uptr)p, sz); } void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) { ThreadState *thr = AllocGoroutine(); *pthr = thr; int goid = ThreadCreate(parent, (uptr)pc, 0, true); ThreadStart(thr, goid, 0); } void __tsan_go_end(ThreadState *thr) { ThreadFinish(thr); internal_free(thr); } void __tsan_acquire(ThreadState *thr, void *addr) { Acquire(thr, 0, (uptr)addr); } void __tsan_release(ThreadState *thr, void *addr) { ReleaseStore(thr, 0, (uptr)addr); } void __tsan_release_merge(ThreadState *thr, void *addr) { Release(thr, 0, (uptr)addr); } void __tsan_finalizer_goroutine(ThreadState *thr) { AcquireGlobal(thr, 0); } void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) { } void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) { if (write) MutexLock(thr, 0, addr); else MutexReadLock(thr, 0, addr); } void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) { if (write) MutexUnlock(thr, 0, addr); else MutexReadUnlock(thr, 0, addr); } void __tsan_go_ignore_sync_begin(ThreadState *thr) { ThreadIgnoreSyncBegin(thr, 0); } void __tsan_go_ignore_sync_end(ThreadState *thr) { ThreadIgnoreSyncEnd(thr, 0); } } // extern "C" } // namespace __tsan namespace __sanitizer { void SymbolizerPrepareForSandboxing() { // Nothing to do here for Go. } } // namespace __sanitizer