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