| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 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 | struct ThreadStatePlaceholder { | 
|  | 22 | uptr opaque[sizeof(ThreadState) / sizeof(uptr) + kCacheLineSize]; | 
|  | 23 | }; | 
|  | 24 |  | 
| Dmitry Vyukov | 239ae71 | 2012-07-06 20:23:59 +0000 | [diff] [blame] | 25 | static ThreadState *goroutines[kMaxTid]; | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 26 |  | 
|  | 27 | void InitializeInterceptors() { | 
|  | 28 | } | 
|  | 29 |  | 
|  | 30 | void InitializeDynamicAnnotations() { | 
|  | 31 | } | 
|  | 32 |  | 
|  | 33 | bool IsExpectedReport(uptr addr, uptr size) { | 
|  | 34 | return false; | 
|  | 35 | } | 
|  | 36 |  | 
|  | 37 | void internal_start_thread(void(*func)(void*), void *arg) { | 
|  | 38 | } | 
|  | 39 |  | 
| Dmitry Vyukov | bcf0b70 | 2012-07-24 12:29:43 +0000 | [diff] [blame] | 40 | extern "C" int __tsan_symbolize(uptr pc, char **func, char **file, | 
|  | 41 | int *line, int *off); | 
| Dmitry Vyukov | c40c007 | 2012-07-16 13:02:40 +0000 | [diff] [blame] | 42 | extern "C" void free(void *p); | 
| Dmitry Vyukov | e0d31e9 | 2012-07-06 14:54:25 +0000 | [diff] [blame] | 43 |  | 
|  | 44 | ReportStack *SymbolizeCode(uptr addr) { | 
|  | 45 | ReportStack *s = NewReportStackEntry(addr); | 
| Dmitry Vyukov | d654f06 | 2012-07-25 11:50:37 +0000 | [diff] [blame^] | 46 | char *func = 0, *file = 0; | 
|  | 47 | int line = 0, off = 0; | 
| Dmitry Vyukov | bcf0b70 | 2012-07-24 12:29:43 +0000 | [diff] [blame] | 48 | if (__tsan_symbolize(addr, &func, &file, &line, &off)) { | 
|  | 49 | s->offset = off; | 
| Dmitry Vyukov | d654f06 | 2012-07-25 11:50:37 +0000 | [diff] [blame^] | 50 | s->func = internal_strdup(func ? func : "??"); | 
|  | 51 | s->file = internal_strdup(file ? file : "-"); | 
| Dmitry Vyukov | bcf0b70 | 2012-07-24 12:29:43 +0000 | [diff] [blame] | 52 | s->line = line; | 
| Dmitry Vyukov | e0d31e9 | 2012-07-06 14:54:25 +0000 | [diff] [blame] | 53 | s->col = 0; | 
| Dmitry Vyukov | bcf0b70 | 2012-07-24 12:29:43 +0000 | [diff] [blame] | 54 | free(func); | 
|  | 55 | free(file); | 
| Dmitry Vyukov | e0d31e9 | 2012-07-06 14:54:25 +0000 | [diff] [blame] | 56 | } | 
|  | 57 | return s; | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 58 | } | 
|  | 59 |  | 
| Dmitry Vyukov | e0d31e9 | 2012-07-06 14:54:25 +0000 | [diff] [blame] | 60 | ReportStack *SymbolizeData(uptr addr) { | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 61 | return 0; | 
|  | 62 | } | 
|  | 63 |  | 
| Dmitry Vyukov | e0d31e9 | 2012-07-06 14:54:25 +0000 | [diff] [blame] | 64 | ReportStack *NewReportStackEntry(uptr addr) { | 
|  | 65 | ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack, | 
|  | 66 | sizeof(ReportStack)); | 
|  | 67 | internal_memset(ent, 0, sizeof(*ent)); | 
|  | 68 | ent->pc = addr; | 
|  | 69 | return ent; | 
|  | 70 | } | 
|  | 71 |  | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 72 | void *internal_alloc(MBlockType typ, uptr sz) { | 
|  | 73 | return InternalAlloc(sz); | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | void internal_free(void *p) { | 
|  | 77 | InternalFree(p); | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | extern "C" { | 
|  | 81 |  | 
|  | 82 | enum Tsan1EventType { | 
|  | 83 | NOOP,               // Should not appear. | 
|  | 84 | READ,               // {tid, pc, addr, size} | 
|  | 85 | WRITE,              // {tid, pc, addr, size} | 
|  | 86 | READER_LOCK,        // {tid, pc, lock, 0} | 
|  | 87 | WRITER_LOCK,        // {tid, pc, lock, 0} | 
|  | 88 | UNLOCK,             // {tid, pc, lock, 0} | 
|  | 89 | UNLOCK_OR_INIT,     // {tid, pc, lock, 0} | 
|  | 90 | LOCK_CREATE,        // {tid, pc, lock, 0} | 
|  | 91 | LOCK_DESTROY,       // {tid, pc, lock, 0} | 
|  | 92 | THR_CREATE_BEFORE,  // Parent thread's event. {tid, pc, 0, 0} | 
|  | 93 | THR_CREATE_AFTER,   // Parent thread's event. {tid, 0, 0, child_tid}/* 10 */ | 
|  | 94 | THR_START,          // Child thread's event {tid, CallStack, 0, parent_tid} | 
|  | 95 | THR_FIRST_INSN,     // Used only by valgrind. | 
|  | 96 | THR_END,            // {tid, 0, 0, 0} | 
|  | 97 | THR_JOIN_AFTER,     // {tid, pc, joined_tid} | 
|  | 98 | THR_STACK_TOP,      // {tid, pc, stack_top, stack_size_if_known} | 
|  | 99 | RTN_EXIT,           // {tid, 0, 0, 0} | 
|  | 100 | RTN_CALL,           // {tid, pc, 0, 0} | 
|  | 101 | SBLOCK_ENTER,       // {tid, pc, 0, 0} | 
|  | 102 | SIGNAL,             // {tid, pc, obj, 0} | 
|  | 103 | WAIT,               // {tid, pc, obj, 0} /* 20 */ | 
|  | 104 | CYCLIC_BARRIER_INIT,         // {tid, pc, obj, n} | 
|  | 105 | CYCLIC_BARRIER_WAIT_BEFORE,  // {tid, pc, obj, 0} | 
|  | 106 | CYCLIC_BARRIER_WAIT_AFTER,   // {tid, pc, obj, 0} | 
|  | 107 | PCQ_CREATE,         // {tid, pc, pcq_addr, 0} | 
|  | 108 | PCQ_DESTROY,        // {tid, pc, pcq_addr, 0} | 
|  | 109 | PCQ_PUT,            // {tid, pc, pcq_addr, 0} | 
|  | 110 | PCQ_GET,            // {tid, pc, pcq_addr, 0} | 
|  | 111 | STACK_MEM_DIE,      // deprecated. | 
|  | 112 | MALLOC,             // {tid, pc, addr, size} | 
|  | 113 | FREE,               // {tid, pc, addr, 0} /* 30 */ | 
|  | 114 | MMAP,               // {tid, pc, addr, size} | 
|  | 115 | MUNMAP,             // {tid, pc, addr, size} | 
|  | 116 | PUBLISH_RANGE,      // may be deprecated later. | 
|  | 117 | UNPUBLISH_RANGE,    // deprecated. TODO(kcc): get rid of this. | 
|  | 118 | HB_LOCK,            // {tid, pc, addr, 0} | 
|  | 119 | NON_HB_LOCK,        // {tid, pc, addr, 0} | 
|  | 120 | IGNORE_READS_BEG,   // {tid, pc, 0, 0} | 
|  | 121 | IGNORE_READS_END,   // {tid, pc, 0, 0} | 
|  | 122 | IGNORE_WRITES_BEG,  // {tid, pc, 0, 0} | 
|  | 123 | IGNORE_WRITES_END,  // {tid, pc, 0, 0} | 
|  | 124 | SET_THREAD_NAME,    // {tid, pc, name_str, 0} | 
|  | 125 | SET_LOCK_NAME,      // {tid, pc, lock, lock_name_str} | 
|  | 126 | TRACE_MEM,          // {tid, pc, addr, 0} | 
|  | 127 | EXPECT_RACE,        // {tid, descr_str, ptr, size} | 
|  | 128 | BENIGN_RACE,        // {tid, descr_str, ptr, size} | 
|  | 129 | EXPECT_RACE_BEGIN,  // {tid, pc, 0, 0} | 
|  | 130 | EXPECT_RACE_END,    // {tid, pc, 0, 0} | 
|  | 131 | VERBOSITY,          // Used for debugging. | 
|  | 132 | STACK_TRACE,        // {tid, pc, 0, 0}, for debugging. | 
|  | 133 | FLUSH_STATE,        // {tid, pc, 0, 0} | 
|  | 134 | PC_DESCRIPTION,     // {0, pc, descr_str, 0}, for ts_offline. | 
|  | 135 | PRINT_MESSAGE,      // {tid, pc, message_str, 0}, for ts_offline. | 
|  | 136 | FLUSH_EXPECTED_RACES,  // {0, 0, 0, 0} | 
|  | 137 | LAST_EVENT          // Should not appear. | 
|  | 138 | }; | 
|  | 139 |  | 
| Dmitry Vyukov | 239ae71 | 2012-07-06 20:23:59 +0000 | [diff] [blame] | 140 | static void AllocGoroutine(int tid) { | 
|  | 141 | goroutines[tid] = (ThreadState*)internal_alloc(MBlockThreadContex, | 
|  | 142 | sizeof(ThreadState)); | 
|  | 143 | internal_memset(goroutines[tid], 0, sizeof(ThreadState)); | 
|  | 144 | } | 
|  | 145 |  | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 146 | void __tsan_init() { | 
| Dmitry Vyukov | 239ae71 | 2012-07-06 20:23:59 +0000 | [diff] [blame] | 147 | AllocGoroutine(0); | 
|  | 148 | ThreadState *thr = goroutines[0]; | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 149 | thr->in_rtl++; | 
|  | 150 | Initialize(thr); | 
|  | 151 | thr->in_rtl--; | 
|  | 152 | } | 
|  | 153 |  | 
|  | 154 | void __tsan_fini() { | 
|  | 155 | // FIXME: Not necessary thread 0. | 
| Dmitry Vyukov | 239ae71 | 2012-07-06 20:23:59 +0000 | [diff] [blame] | 156 | ThreadState *thr = goroutines[0]; | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 157 | thr->in_rtl++; | 
|  | 158 | int res = Finalize(thr); | 
|  | 159 | thr->in_rtl--; | 
|  | 160 | exit(res); | 
|  | 161 | } | 
|  | 162 |  | 
|  | 163 | void __tsan_event(int typ, int tid, void *pc, void *addr, int info) { | 
| Dmitry Vyukov | 239ae71 | 2012-07-06 20:23:59 +0000 | [diff] [blame] | 164 | ThreadState *thr = goroutines[tid]; | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 165 | switch (typ) { | 
|  | 166 | case READ: | 
|  | 167 | MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, false); | 
|  | 168 | break; | 
|  | 169 | case WRITE: | 
|  | 170 | MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, true); | 
|  | 171 | break; | 
|  | 172 | case RTN_EXIT: | 
|  | 173 | FuncExit(thr); | 
|  | 174 | break; | 
|  | 175 | case RTN_CALL: | 
|  | 176 | FuncEntry(thr, (uptr)pc); | 
|  | 177 | break; | 
|  | 178 | case SBLOCK_ENTER: | 
|  | 179 | break; | 
|  | 180 | case SIGNAL: | 
|  | 181 | thr->in_rtl++; | 
|  | 182 | Release(thr, (uptr)pc, (uptr)addr); | 
|  | 183 | thr->in_rtl--; | 
|  | 184 | break; | 
|  | 185 | case WAIT: | 
|  | 186 | thr->in_rtl++; | 
|  | 187 | Acquire(thr, (uptr)pc, (uptr)addr); | 
|  | 188 | thr->in_rtl--; | 
|  | 189 | break; | 
|  | 190 | case MALLOC: | 
|  | 191 | thr->in_rtl++; | 
|  | 192 | MemoryResetRange(thr, (uptr)pc, (uptr)addr, (uptr)info); | 
| Dmitry Vyukov | 3abd096 | 2012-07-16 16:55:01 +0000 | [diff] [blame] | 193 | MemoryAccessRange(thr, (uptr)pc, (uptr)addr, (uptr)info, true); | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 194 | thr->in_rtl--; | 
|  | 195 | break; | 
|  | 196 | case FREE: | 
|  | 197 | break; | 
|  | 198 | case THR_START: { | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 199 | if (tid == 0) | 
|  | 200 | return; | 
| Dmitry Vyukov | 239ae71 | 2012-07-06 20:23:59 +0000 | [diff] [blame] | 201 | ThreadState *parent = goroutines[info]; | 
|  | 202 | AllocGoroutine(tid); | 
|  | 203 | thr = goroutines[tid]; | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 204 | thr->in_rtl++; | 
|  | 205 | parent->in_rtl++; | 
|  | 206 | int tid2 = ThreadCreate(parent, (uptr)pc, 0, true); | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 207 | ThreadStart(thr, tid2); | 
|  | 208 | parent->in_rtl--; | 
|  | 209 | thr->in_rtl--; | 
|  | 210 | break; | 
|  | 211 | } | 
| Dmitry Vyukov | 9270eaf | 2012-07-16 16:01:08 +0000 | [diff] [blame] | 212 | case THR_END: { | 
|  | 213 | thr->in_rtl++; | 
|  | 214 | ThreadFinish(thr); | 
|  | 215 | thr->in_rtl--; | 
|  | 216 | break; | 
|  | 217 | } | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 218 | default: | 
| Dmitry Vyukov | 239ae71 | 2012-07-06 20:23:59 +0000 | [diff] [blame] | 219 | Printf("Unknown event type %d\n", typ); | 
|  | 220 | Die(); | 
| Dmitry Vyukov | 03d32ec | 2012-07-05 16:18:28 +0000 | [diff] [blame] | 221 | } | 
|  | 222 | } | 
|  | 223 |  | 
|  | 224 | }  // extern "C" | 
|  | 225 | }  // namespace __tsan |