1//===-- tsan_go.cc --------------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// ThreadSanitizer runtime for Go language. 11// 12//===----------------------------------------------------------------------===// 13 14#include "tsan_rtl.h" 15#include "tsan_symbolize.h" 16#include "sanitizer_common/sanitizer_common.h" 17#include <stdlib.h> 18 19namespace __tsan { 20 21const int kMaxGoroutinesEver = 128*1024; 22 23static ThreadState *goroutines[kMaxGoroutinesEver]; 24 25void InitializeInterceptors() { 26} 27 28void InitializeDynamicAnnotations() { 29} 30 31bool IsExpectedReport(uptr addr, uptr size) { 32 return false; 33} 34 35void internal_start_thread(void(*func)(void*), void *arg) { 36} 37 38ReportStack *SymbolizeData(uptr addr) { 39 return 0; 40} 41 42ReportStack *NewReportStackEntry(uptr addr) { 43 ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack, 44 sizeof(ReportStack)); 45 internal_memset(ent, 0, sizeof(*ent)); 46 ent->pc = addr; 47 return ent; 48} 49 50void *internal_alloc(MBlockType typ, uptr sz) { 51 return InternalAlloc(sz); 52} 53 54void internal_free(void *p) { 55 InternalFree(p); 56} 57 58// Callback into Go. 59extern "C" int __tsan_symbolize(uptr pc, char **func, char **file, 60 int *line, int *off); 61 62ReportStack *SymbolizeCode(uptr addr) { 63 ReportStack *s = (ReportStack*)internal_alloc(MBlockReportStack, 64 sizeof(ReportStack)); 65 internal_memset(s, 0, sizeof(*s)); 66 s->pc = addr; 67 char *func = 0, *file = 0; 68 int line = 0, off = 0; 69 if (__tsan_symbolize(addr, &func, &file, &line, &off)) { 70 s->offset = off; 71 s->func = internal_strdup(func ? func : "??"); 72 s->file = internal_strdup(file ? file : "-"); 73 s->line = line; 74 s->col = 0; 75 free(func); 76 free(file); 77 } 78 return s; 79} 80 81extern "C" { 82 83static void AllocGoroutine(int tid) { 84 if (tid >= kMaxGoroutinesEver) { 85 Printf("FATAL: Reached goroutine limit\n"); 86 Die(); 87 } 88 ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex, 89 sizeof(ThreadState)); 90 internal_memset(thr, 0, sizeof(*thr)); 91 goroutines[tid] = thr; 92} 93 94void __tsan_init() { 95 AllocGoroutine(0); 96 ThreadState *thr = goroutines[0]; 97 thr->in_rtl++; 98 Initialize(thr); 99 thr->in_rtl--; 100} 101 102void __tsan_fini() { 103 // FIXME: Not necessary thread 0. 104 ThreadState *thr = goroutines[0]; 105 thr->in_rtl++; 106 int res = Finalize(thr); 107 thr->in_rtl--; 108 exit(res); 109} 110 111void __tsan_read(int goid, void *addr, void *pc) { 112 ThreadState *thr = goroutines[goid]; 113 MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, false); 114} 115 116void __tsan_write(int goid, void *addr, void *pc) { 117 ThreadState *thr = goroutines[goid]; 118 MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, true); 119} 120 121void __tsan_func_enter(int goid, void *pc) { 122 ThreadState *thr = goroutines[goid]; 123 FuncEntry(thr, (uptr)pc); 124} 125 126void __tsan_func_exit(int goid) { 127 ThreadState *thr = goroutines[goid]; 128 FuncExit(thr); 129} 130 131void __tsan_malloc(int goid, void *p, uptr sz, void *pc) { 132 ThreadState *thr = goroutines[goid]; 133 thr->in_rtl++; 134 MemoryResetRange(thr, (uptr)pc, (uptr)p, sz); 135 MemoryAccessRange(thr, (uptr)pc, (uptr)p, sz, true); 136 thr->in_rtl--; 137} 138 139void __tsan_free(void *p) { 140 (void)p; 141} 142 143void __tsan_go_start(int pgoid, int chgoid, void *pc) { 144 if (chgoid == 0) 145 return; 146 AllocGoroutine(chgoid); 147 ThreadState *thr = goroutines[chgoid]; 148 ThreadState *parent = goroutines[pgoid]; 149 thr->in_rtl++; 150 parent->in_rtl++; 151 int goid2 = ThreadCreate(parent, (uptr)pc, 0, true); 152 ThreadStart(thr, goid2); 153 parent->in_rtl--; 154 thr->in_rtl--; 155} 156 157void __tsan_go_end(int goid) { 158 ThreadState *thr = goroutines[goid]; 159 thr->in_rtl++; 160 ThreadFinish(thr); 161 thr->in_rtl--; 162 internal_free(thr); 163 goroutines[goid] = 0; 164} 165 166void __tsan_acquire(int goid, void *addr) { 167 ThreadState *thr = goroutines[goid]; 168 thr->in_rtl++; 169 Acquire(thr, 0, (uptr)addr); 170 thr->in_rtl--; 171} 172 173void __tsan_release(int goid, void *addr) { 174 ThreadState *thr = goroutines[goid]; 175 thr->in_rtl++; 176 ReleaseStore(thr, 0, (uptr)addr); 177 thr->in_rtl--; 178} 179 180void __tsan_release_merge(int goid, void *addr) { 181 ThreadState *thr = goroutines[goid]; 182 thr->in_rtl++; 183 Release(thr, 0, (uptr)addr); 184 thr->in_rtl--; 185} 186 187void __tsan_finalizer_goroutine(int goid) { 188 ThreadState *thr = goroutines[goid]; 189 ThreadFinalizerGoroutine(thr); 190} 191 192} // extern "C" 193} // namespace __tsan 194