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_start_thread(void(*func)(void*), void *arg) {
     32 }
     33 
     34 ReportLocation *SymbolizeData(uptr addr) {
     35   return 0;
     36 }
     37 
     38 ReportStack *NewReportStackEntry(uptr addr) {
     39   ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
     40                                                   sizeof(ReportStack));
     41   internal_memset(ent, 0, sizeof(*ent));
     42   ent->pc = addr;
     43   return ent;
     44 }
     45 
     46 void *internal_alloc(MBlockType typ, uptr sz) {
     47   return InternalAlloc(sz);
     48 }
     49 
     50 void internal_free(void *p) {
     51   InternalFree(p);
     52 }
     53 
     54 // Callback into Go.
     55 extern "C" int __tsan_symbolize(uptr pc, char **func, char **file,
     56     int *line, int *off);
     57 
     58 ReportStack *SymbolizeCode(uptr addr) {
     59   ReportStack *s = (ReportStack*)internal_alloc(MBlockReportStack,
     60                                                 sizeof(ReportStack));
     61   internal_memset(s, 0, sizeof(*s));
     62   s->pc = addr;
     63   char *func = 0, *file = 0;
     64   int line = 0, off = 0;
     65   if (__tsan_symbolize(addr, &func, &file, &line, &off)) {
     66     s->offset = off;
     67     s->func = internal_strdup(func ? func : "??");
     68     s->file = internal_strdup(file ? file : "-");
     69     s->line = line;
     70     s->col = 0;
     71     free(func);
     72     free(file);
     73   }
     74   return s;
     75 }
     76 
     77 extern "C" {
     78 
     79 static ThreadState *main_thr;
     80 
     81 static ThreadState *AllocGoroutine() {
     82   ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
     83       sizeof(ThreadState));
     84   internal_memset(thr, 0, sizeof(*thr));
     85   return thr;
     86 }
     87 
     88 void __tsan_init(ThreadState **thrp) {
     89   ThreadState *thr = AllocGoroutine();
     90   main_thr = *thrp = thr;
     91   thr->in_rtl++;
     92   Initialize(thr);
     93   thr->in_rtl--;
     94 }
     95 
     96 void __tsan_fini() {
     97   // FIXME: Not necessary thread 0.
     98   ThreadState *thr = main_thr;
     99   thr->in_rtl++;
    100   int res = Finalize(thr);
    101   thr->in_rtl--;
    102   exit(res);
    103 }
    104 
    105 void __tsan_map_shadow(uptr addr, uptr size) {
    106   MapShadow(addr, size);
    107 }
    108 
    109 void __tsan_read(ThreadState *thr, void *addr, void *pc) {
    110   MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
    111 }
    112 
    113 void __tsan_write(ThreadState *thr, void *addr, void *pc) {
    114   MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
    115 }
    116 
    117 void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr step,
    118                        void *pc) {
    119   (void)step;
    120   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
    121 }
    122 
    123 void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr step,
    124                         void *pc) {
    125   (void)step;
    126   MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
    127 }
    128 
    129 void __tsan_func_enter(ThreadState *thr, void *pc) {
    130   FuncEntry(thr, (uptr)pc);
    131 }
    132 
    133 void __tsan_func_exit(ThreadState *thr) {
    134   FuncExit(thr);
    135 }
    136 
    137 void __tsan_malloc(ThreadState *thr, void *p, uptr sz, void *pc) {
    138   if (thr == 0)  // probably before __tsan_init()
    139     return;
    140   thr->in_rtl++;
    141   MemoryResetRange(thr, (uptr)pc, (uptr)p, sz);
    142   thr->in_rtl--;
    143 }
    144 
    145 void __tsan_free(void *p) {
    146   (void)p;
    147 }
    148 
    149 void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
    150   ThreadState *thr = AllocGoroutine();
    151   *pthr = thr;
    152   thr->in_rtl++;
    153   parent->in_rtl++;
    154   int goid = ThreadCreate(parent, (uptr)pc, 0, true);
    155   ThreadStart(thr, goid, 0);
    156   parent->in_rtl--;
    157   thr->in_rtl--;
    158 }
    159 
    160 void __tsan_go_end(ThreadState *thr) {
    161   thr->in_rtl++;
    162   ThreadFinish(thr);
    163   thr->in_rtl--;
    164   internal_free(thr);
    165 }
    166 
    167 void __tsan_acquire(ThreadState *thr, void *addr) {
    168   thr->in_rtl++;
    169   Acquire(thr, 0, (uptr)addr);
    170   thr->in_rtl--;
    171 }
    172 
    173 void __tsan_release(ThreadState *thr, void *addr) {
    174   thr->in_rtl++;
    175   ReleaseStore(thr, 0, (uptr)addr);
    176   thr->in_rtl--;
    177 }
    178 
    179 void __tsan_release_merge(ThreadState *thr, void *addr) {
    180   thr->in_rtl++;
    181   Release(thr, 0, (uptr)addr);
    182   thr->in_rtl--;
    183 }
    184 
    185 void __tsan_finalizer_goroutine(ThreadState *thr) {
    186   AcquireGlobal(thr, 0);
    187 }
    188 
    189 #if SANITIZER_WINDOWS
    190 // MinGW gcc emits calls to the function.
    191 void ___chkstk_ms(void) {
    192 // The implementation must be along the lines of:
    193 // .code64
    194 // PUBLIC ___chkstk_ms
    195 //     //cfi_startproc()
    196 // ___chkstk_ms:
    197 //     push rcx
    198 //     //cfi_push(%rcx)
    199 //     push rax
    200 //     //cfi_push(%rax)
    201 //     cmp rax, PAGE_SIZE
    202 //     lea rcx, [rsp + 24]
    203 //     jb l_LessThanAPage
    204 // .l_MoreThanAPage:
    205 //     sub rcx, PAGE_SIZE
    206 //     or rcx, 0
    207 //     sub rax, PAGE_SIZE
    208 //     cmp rax, PAGE_SIZE
    209 //     ja l_MoreThanAPage
    210 // .l_LessThanAPage:
    211 //     sub rcx, rax
    212 //     or [rcx], 0
    213 //     pop rax
    214 //     //cfi_pop(%rax)
    215 //     pop rcx
    216 //     //cfi_pop(%rcx)
    217 //     ret
    218 //     //cfi_endproc()
    219 // END
    220 }
    221 #endif
    222 
    223 }  // extern "C"
    224 }  // namespace __tsan
    225 
    226 namespace __sanitizer {
    227 
    228 void SymbolizerPrepareForSandboxing() {
    229   // Nothing to do here for Go.
    230 }
    231 
    232 }  // namespace __sanitizer
    233