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