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
19namespace __tsan {
20
21void InitializeInterceptors() {
22}
23
24void InitializeDynamicAnnotations() {
25}
26
27bool IsExpectedReport(uptr addr, uptr size) {
28  return false;
29}
30
31ReportLocation *SymbolizeData(uptr addr) {
32  return 0;
33}
34
35void *internal_alloc(MBlockType typ, uptr sz) {
36  return InternalAlloc(sz);
37}
38
39void internal_free(void *p) {
40  InternalFree(p);
41}
42
43struct SymbolizeContext {
44  uptr pc;
45  char *func;
46  char *file;
47  uptr line;
48  uptr off;
49  uptr res;
50};
51
52// Callback into Go.
53static void (*symbolize_cb)(SymbolizeContext *ctx);
54
55SymbolizedStack *SymbolizeCode(uptr addr) {
56  SymbolizedStack *s = SymbolizedStack::New(addr);
57  SymbolizeContext ctx;
58  internal_memset(&ctx, 0, sizeof(ctx));
59  ctx.pc = addr;
60  symbolize_cb(&ctx);
61  if (ctx.res) {
62    AddressInfo &info = s->info;
63    info.module_offset = ctx.off;
64    info.function = internal_strdup(ctx.func ? ctx.func : "??");
65    info.file = internal_strdup(ctx.file ? ctx.file : "-");
66    info.line = ctx.line;
67    info.column = 0;
68  }
69  return s;
70}
71
72extern "C" {
73
74static ThreadState *main_thr;
75static bool inited;
76
77static ThreadState *AllocGoroutine() {
78  ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
79      sizeof(ThreadState));
80  internal_memset(thr, 0, sizeof(*thr));
81  return thr;
82}
83
84void __tsan_init(ThreadState **thrp, void (*cb)(SymbolizeContext *cb)) {
85  symbolize_cb = cb;
86  ThreadState *thr = AllocGoroutine();
87  main_thr = *thrp = thr;
88  Initialize(thr);
89  inited = true;
90}
91
92void __tsan_fini() {
93  // FIXME: Not necessary thread 0.
94  ThreadState *thr = main_thr;
95  int res = Finalize(thr);
96  exit(res);
97}
98
99void __tsan_map_shadow(uptr addr, uptr size) {
100  MapShadow(addr, size);
101}
102
103void __tsan_read(ThreadState *thr, void *addr, void *pc) {
104  MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
105}
106
107void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
108  if (callpc != 0)
109    FuncEntry(thr, callpc);
110  MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
111  if (callpc != 0)
112    FuncExit(thr);
113}
114
115void __tsan_write(ThreadState *thr, void *addr, void *pc) {
116  MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
117}
118
119void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
120  if (callpc != 0)
121    FuncEntry(thr, callpc);
122  MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
123  if (callpc != 0)
124    FuncExit(thr);
125}
126
127void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
128  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
129}
130
131void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
132  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
133}
134
135void __tsan_func_enter(ThreadState *thr, void *pc) {
136  FuncEntry(thr, (uptr)pc);
137}
138
139void __tsan_func_exit(ThreadState *thr) {
140  FuncExit(thr);
141}
142
143void __tsan_malloc(void *p, uptr sz) {
144  if (!inited)
145    return;
146  MemoryResetRange(0, 0, (uptr)p, sz);
147}
148
149void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
150  ThreadState *thr = AllocGoroutine();
151  *pthr = thr;
152  int goid = ThreadCreate(parent, (uptr)pc, 0, true);
153  ThreadStart(thr, goid, 0);
154}
155
156void __tsan_go_end(ThreadState *thr) {
157  ThreadFinish(thr);
158  internal_free(thr);
159}
160
161void __tsan_acquire(ThreadState *thr, void *addr) {
162  Acquire(thr, 0, (uptr)addr);
163}
164
165void __tsan_release(ThreadState *thr, void *addr) {
166  ReleaseStore(thr, 0, (uptr)addr);
167}
168
169void __tsan_release_merge(ThreadState *thr, void *addr) {
170  Release(thr, 0, (uptr)addr);
171}
172
173void __tsan_finalizer_goroutine(ThreadState *thr) {
174  AcquireGlobal(thr, 0);
175}
176
177void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
178}
179
180void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
181  if (write)
182    MutexLock(thr, 0, addr);
183  else
184    MutexReadLock(thr, 0, addr);
185}
186
187void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
188  if (write)
189    MutexUnlock(thr, 0, addr);
190  else
191    MutexReadUnlock(thr, 0, addr);
192}
193
194void __tsan_go_ignore_sync_begin(ThreadState *thr) {
195  ThreadIgnoreSyncBegin(thr, 0);
196}
197
198void __tsan_go_ignore_sync_end(ThreadState *thr) {
199  ThreadIgnoreSyncEnd(thr, 0);
200}
201
202}  // extern "C"
203}  // namespace __tsan
204
205namespace __sanitizer {
206
207void SymbolizerPrepareForSandboxing() {
208  // Nothing to do here for Go.
209}
210
211}  // namespace __sanitizer
212