Home | History | Annotate | Download | only in go
      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