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 19 namespace __tsan { 20 21 void InitializeInterceptors() { 22 } 23 24 void InitializeDynamicAnnotations() { 25 } 26 27 bool IsExpectedReport(uptr addr, uptr size) { 28 return false; 29 } 30 31 void *internal_alloc(MBlockType typ, uptr sz) { 32 return InternalAlloc(sz); 33 } 34 35 void internal_free(void *p) { 36 InternalFree(p); 37 } 38 39 // Callback into Go. 40 static void (*go_runtime_cb)(uptr cmd, void *ctx); 41 42 enum { 43 CallbackGetProc = 0, 44 CallbackSymbolizeCode = 1, 45 CallbackSymbolizeData = 2, 46 }; 47 48 struct SymbolizeCodeContext { 49 uptr pc; 50 char *func; 51 char *file; 52 uptr line; 53 uptr off; 54 uptr res; 55 }; 56 57 SymbolizedStack *SymbolizeCode(uptr addr) { 58 SymbolizedStack *s = SymbolizedStack::New(addr); 59 SymbolizeCodeContext cbctx; 60 internal_memset(&cbctx, 0, sizeof(cbctx)); 61 cbctx.pc = addr; 62 go_runtime_cb(CallbackSymbolizeCode, &cbctx); 63 if (cbctx.res) { 64 AddressInfo &info = s->info; 65 info.module_offset = cbctx.off; 66 info.function = internal_strdup(cbctx.func ? cbctx.func : "??"); 67 info.file = internal_strdup(cbctx.file ? cbctx.file : "-"); 68 info.line = cbctx.line; 69 info.column = 0; 70 } 71 return s; 72 } 73 74 struct SymbolizeDataContext { 75 uptr addr; 76 uptr heap; 77 uptr start; 78 uptr size; 79 char *name; 80 char *file; 81 uptr line; 82 uptr res; 83 }; 84 85 ReportLocation *SymbolizeData(uptr addr) { 86 SymbolizeDataContext cbctx; 87 internal_memset(&cbctx, 0, sizeof(cbctx)); 88 cbctx.addr = addr; 89 go_runtime_cb(CallbackSymbolizeData, &cbctx); 90 if (!cbctx.res) 91 return 0; 92 if (cbctx.heap) { 93 MBlock *b = ctx->metamap.GetBlock(cbctx.start); 94 if (!b) 95 return 0; 96 ReportLocation *loc = ReportLocation::New(ReportLocationHeap); 97 loc->heap_chunk_start = cbctx.start; 98 loc->heap_chunk_size = b->siz; 99 loc->tid = b->tid; 100 loc->stack = SymbolizeStackId(b->stk); 101 return loc; 102 } else { 103 ReportLocation *loc = ReportLocation::New(ReportLocationGlobal); 104 loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??"); 105 loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??"); 106 loc->global.line = cbctx.line; 107 loc->global.start = cbctx.start; 108 loc->global.size = cbctx.size; 109 return loc; 110 } 111 } 112 113 static ThreadState *main_thr; 114 static bool inited; 115 116 static Processor* get_cur_proc() { 117 if (UNLIKELY(!inited)) { 118 // Running Initialize(). 119 // We have not yet returned the Processor to Go, so we cannot ask it back. 120 // Currently, Initialize() does not use the Processor, so return nullptr. 121 return nullptr; 122 } 123 Processor *proc; 124 go_runtime_cb(CallbackGetProc, &proc); 125 return proc; 126 } 127 128 Processor *ThreadState::proc() { 129 return get_cur_proc(); 130 } 131 132 extern "C" { 133 134 static ThreadState *AllocGoroutine() { 135 ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex, 136 sizeof(ThreadState)); 137 internal_memset(thr, 0, sizeof(*thr)); 138 return thr; 139 } 140 141 void __tsan_init(ThreadState **thrp, Processor **procp, 142 void (*cb)(uptr cmd, void *cb)) { 143 go_runtime_cb = cb; 144 ThreadState *thr = AllocGoroutine(); 145 main_thr = *thrp = thr; 146 Initialize(thr); 147 *procp = thr->proc1; 148 inited = true; 149 } 150 151 void __tsan_fini() { 152 // FIXME: Not necessary thread 0. 153 ThreadState *thr = main_thr; 154 int res = Finalize(thr); 155 exit(res); 156 } 157 158 void __tsan_map_shadow(uptr addr, uptr size) { 159 MapShadow(addr, size); 160 } 161 162 void __tsan_read(ThreadState *thr, void *addr, void *pc) { 163 MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1); 164 } 165 166 void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) { 167 if (callpc != 0) 168 FuncEntry(thr, callpc); 169 MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1); 170 if (callpc != 0) 171 FuncExit(thr); 172 } 173 174 void __tsan_write(ThreadState *thr, void *addr, void *pc) { 175 MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1); 176 } 177 178 void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) { 179 if (callpc != 0) 180 FuncEntry(thr, callpc); 181 MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1); 182 if (callpc != 0) 183 FuncExit(thr); 184 } 185 186 void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) { 187 MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false); 188 } 189 190 void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) { 191 MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true); 192 } 193 194 void __tsan_func_enter(ThreadState *thr, void *pc) { 195 FuncEntry(thr, (uptr)pc); 196 } 197 198 void __tsan_func_exit(ThreadState *thr) { 199 FuncExit(thr); 200 } 201 202 void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) { 203 CHECK(inited); 204 if (thr && pc) 205 ctx->metamap.AllocBlock(thr, pc, p, sz); 206 MemoryResetRange(0, 0, (uptr)p, sz); 207 } 208 209 void __tsan_free(uptr p, uptr sz) { 210 ctx->metamap.FreeRange(get_cur_proc(), p, sz); 211 } 212 213 void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) { 214 ThreadState *thr = AllocGoroutine(); 215 *pthr = thr; 216 int goid = ThreadCreate(parent, (uptr)pc, 0, true); 217 ThreadStart(thr, goid, 0); 218 } 219 220 void __tsan_go_end(ThreadState *thr) { 221 ThreadFinish(thr); 222 internal_free(thr); 223 } 224 225 void __tsan_proc_create(Processor **pproc) { 226 *pproc = ProcCreate(); 227 } 228 229 void __tsan_proc_destroy(Processor *proc) { 230 ProcDestroy(proc); 231 } 232 233 void __tsan_acquire(ThreadState *thr, void *addr) { 234 Acquire(thr, 0, (uptr)addr); 235 } 236 237 void __tsan_release(ThreadState *thr, void *addr) { 238 ReleaseStore(thr, 0, (uptr)addr); 239 } 240 241 void __tsan_release_merge(ThreadState *thr, void *addr) { 242 Release(thr, 0, (uptr)addr); 243 } 244 245 void __tsan_finalizer_goroutine(ThreadState *thr) { 246 AcquireGlobal(thr, 0); 247 } 248 249 void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) { 250 } 251 252 void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) { 253 if (write) 254 MutexLock(thr, 0, addr); 255 else 256 MutexReadLock(thr, 0, addr); 257 } 258 259 void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) { 260 if (write) 261 MutexUnlock(thr, 0, addr); 262 else 263 MutexReadUnlock(thr, 0, addr); 264 } 265 266 void __tsan_go_ignore_sync_begin(ThreadState *thr) { 267 ThreadIgnoreSyncBegin(thr, 0); 268 } 269 270 void __tsan_go_ignore_sync_end(ThreadState *thr) { 271 ThreadIgnoreSyncEnd(thr, 0); 272 } 273 274 } // extern "C" 275 } // namespace __tsan 276 277 namespace __sanitizer { 278 279 void SymbolizerPrepareForSandboxing() { 280 // Nothing to do here for Go. 281 } 282 283 } // namespace __sanitizer 284