1 //===-- tsan_go.cpp -------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // ThreadSanitizer runtime for Go language.
11 //===----------------------------------------------------------------------===//
14 #include "tsan_symbolize.h"
15 #include "sanitizer_common/sanitizer_common.h"
20 void InitializeInterceptors() {
23 void InitializeDynamicAnnotations() {
26 bool IsExpectedReport(uptr addr
, uptr size
) {
30 void *Alloc(uptr sz
) { return InternalAlloc(sz
); }
32 void FreeImpl(void *p
) { InternalFree(p
); }
35 static void (*go_runtime_cb
)(uptr cmd
, void *ctx
);
39 CallbackSymbolizeCode
= 1,
40 CallbackSymbolizeData
= 2,
43 struct SymbolizeCodeContext
{
52 SymbolizedStack
*SymbolizeCode(uptr addr
) {
53 SymbolizedStack
*first
= SymbolizedStack::New(addr
);
54 SymbolizedStack
*s
= first
;
56 SymbolizeCodeContext cbctx
;
57 internal_memset(&cbctx
, 0, sizeof(cbctx
));
59 go_runtime_cb(CallbackSymbolizeCode
, &cbctx
);
62 AddressInfo
&info
= s
->info
;
63 info
.module_offset
= cbctx
.off
;
64 info
.function
= internal_strdup(cbctx
.func
? cbctx
.func
: "??");
65 info
.file
= internal_strdup(cbctx
.file
? cbctx
.file
: "-");
66 info
.line
= cbctx
.line
;
69 if (cbctx
.pc
== addr
) // outermost (non-inlined) function
72 // Allocate a stack entry for the parent of the inlined function.
73 SymbolizedStack
*s2
= SymbolizedStack::New(addr
);
80 struct SymbolizeDataContext
{
91 ReportLocation
*SymbolizeData(uptr addr
) {
92 SymbolizeDataContext cbctx
;
93 internal_memset(&cbctx
, 0, sizeof(cbctx
));
95 go_runtime_cb(CallbackSymbolizeData
, &cbctx
);
99 MBlock
*b
= ctx
->metamap
.GetBlock(cbctx
.start
);
102 auto *loc
= New
<ReportLocation
>();
103 loc
->type
= ReportLocationHeap
;
104 loc
->heap_chunk_start
= cbctx
.start
;
105 loc
->heap_chunk_size
= b
->siz
;
107 loc
->stack
= SymbolizeStackId(b
->stk
);
110 auto *loc
= New
<ReportLocation
>();
111 loc
->type
= ReportLocationGlobal
;
112 loc
->global
.name
= internal_strdup(cbctx
.name
? cbctx
.name
: "??");
113 loc
->global
.file
= internal_strdup(cbctx
.file
? cbctx
.file
: "??");
114 loc
->global
.line
= cbctx
.line
;
115 loc
->global
.start
= cbctx
.start
;
116 loc
->global
.size
= cbctx
.size
;
121 static ThreadState
*main_thr
;
124 static Processor
* get_cur_proc() {
125 if (UNLIKELY(!inited
)) {
126 // Running Initialize().
127 // We have not yet returned the Processor to Go, so we cannot ask it back.
128 // Currently, Initialize() does not use the Processor, so return nullptr.
132 go_runtime_cb(CallbackGetProc
, &proc
);
136 Processor
*ThreadState::proc() {
137 return get_cur_proc();
142 static ThreadState
*AllocGoroutine() {
143 auto *thr
= (ThreadState
*)Alloc(sizeof(ThreadState
));
144 internal_memset(thr
, 0, sizeof(*thr
));
148 void __tsan_init(ThreadState
**thrp
, Processor
**procp
,
149 void (*cb
)(uptr cmd
, void *cb
)) {
151 ThreadState
*thr
= AllocGoroutine();
152 main_thr
= *thrp
= thr
;
159 // FIXME: Not necessary thread 0.
160 ThreadState
*thr
= main_thr
;
161 int res
= Finalize(thr
);
165 void __tsan_map_shadow(uptr addr
, uptr size
) {
166 MapShadow(addr
, size
);
169 void __tsan_read(ThreadState
*thr
, void *addr
, void *pc
) {
170 MemoryAccess(thr
, (uptr
)pc
, (uptr
)addr
, 1, kAccessRead
);
173 void __tsan_read_pc(ThreadState
*thr
, void *addr
, uptr callpc
, uptr pc
) {
175 FuncEntry(thr
, callpc
);
176 MemoryAccess(thr
, (uptr
)pc
, (uptr
)addr
, 1, kAccessRead
);
181 void __tsan_write(ThreadState
*thr
, void *addr
, void *pc
) {
182 MemoryAccess(thr
, (uptr
)pc
, (uptr
)addr
, 1, kAccessWrite
);
185 void __tsan_write_pc(ThreadState
*thr
, void *addr
, uptr callpc
, uptr pc
) {
187 FuncEntry(thr
, callpc
);
188 MemoryAccess(thr
, (uptr
)pc
, (uptr
)addr
, 1, kAccessWrite
);
193 void __tsan_read_range(ThreadState
*thr
, void *addr
, uptr size
, uptr pc
) {
194 MemoryAccessRange(thr
, (uptr
)pc
, (uptr
)addr
, size
, false);
197 void __tsan_write_range(ThreadState
*thr
, void *addr
, uptr size
, uptr pc
) {
198 MemoryAccessRange(thr
, (uptr
)pc
, (uptr
)addr
, size
, true);
201 void __tsan_func_enter(ThreadState
*thr
, void *pc
) {
202 FuncEntry(thr
, (uptr
)pc
);
205 void __tsan_func_exit(ThreadState
*thr
) {
209 void __tsan_malloc(ThreadState
*thr
, uptr pc
, uptr p
, uptr sz
) {
212 ctx
->metamap
.AllocBlock(thr
, pc
, p
, sz
);
213 MemoryResetRange(thr
, pc
, (uptr
)p
, sz
);
216 void __tsan_free(uptr p
, uptr sz
) {
217 ctx
->metamap
.FreeRange(get_cur_proc(), p
, sz
, false);
220 void __tsan_go_start(ThreadState
*parent
, ThreadState
**pthr
, void *pc
) {
221 ThreadState
*thr
= AllocGoroutine();
223 Tid goid
= ThreadCreate(parent
, (uptr
)pc
, 0, true);
224 ThreadStart(thr
, goid
, 0, ThreadType::Regular
);
227 void __tsan_go_end(ThreadState
*thr
) {
232 void __tsan_proc_create(Processor
**pproc
) {
233 *pproc
= ProcCreate();
236 void __tsan_proc_destroy(Processor
*proc
) {
240 void __tsan_acquire(ThreadState
*thr
, void *addr
) {
241 Acquire(thr
, 0, (uptr
)addr
);
244 void __tsan_release_acquire(ThreadState
*thr
, void *addr
) {
245 ReleaseStoreAcquire(thr
, 0, (uptr
)addr
);
248 void __tsan_release(ThreadState
*thr
, void *addr
) {
249 ReleaseStore(thr
, 0, (uptr
)addr
);
252 void __tsan_release_merge(ThreadState
*thr
, void *addr
) {
253 Release(thr
, 0, (uptr
)addr
);
256 void __tsan_finalizer_goroutine(ThreadState
*thr
) { AcquireGlobal(thr
); }
258 void __tsan_mutex_before_lock(ThreadState
*thr
, uptr addr
, uptr write
) {
260 MutexPreLock(thr
, 0, addr
);
262 MutexPreReadLock(thr
, 0, addr
);
265 void __tsan_mutex_after_lock(ThreadState
*thr
, uptr addr
, uptr write
) {
267 MutexPostLock(thr
, 0, addr
);
269 MutexPostReadLock(thr
, 0, addr
);
272 void __tsan_mutex_before_unlock(ThreadState
*thr
, uptr addr
, uptr write
) {
274 MutexUnlock(thr
, 0, addr
);
276 MutexReadUnlock(thr
, 0, addr
);
279 void __tsan_go_ignore_sync_begin(ThreadState
*thr
) {
280 ThreadIgnoreSyncBegin(thr
, 0);
283 void __tsan_go_ignore_sync_end(ThreadState
*thr
) { ThreadIgnoreSyncEnd(thr
); }
285 void __tsan_report_count(u64
*pn
) {
286 Lock
lock(&ctx
->report_mtx
);
287 *pn
= ctx
->nreported
;
291 } // namespace __tsan