diff options
Diffstat (limited to 'lib/tsan/go')
-rwxr-xr-x | lib/tsan/go/buildgo.sh | 78 | ||||
-rw-r--r-- | lib/tsan/go/test.c | 51 | ||||
-rw-r--r-- | lib/tsan/go/tsan_go.cc | 185 |
3 files changed, 314 insertions, 0 deletions
diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh new file mode 100755 index 0000000..a0d2f67 --- /dev/null +++ b/lib/tsan/go/buildgo.sh @@ -0,0 +1,78 @@ +#!/bin/bash +set -e + +if [ "`uname -a | grep Linux`" != "" ]; then + LINUX=1 + SUFFIX="linux_amd64" +elif [ "`uname -a | grep Darwin`" != "" ]; then + MAC=1 + SUFFIX="darwin_amd64" +else + echo Unknown platform + exit 1 +fi + +SRCS=" + tsan_go.cc + ../rtl/tsan_clock.cc + ../rtl/tsan_flags.cc + ../rtl/tsan_md5.cc + ../rtl/tsan_mutex.cc + ../rtl/tsan_printf.cc + ../rtl/tsan_report.cc + ../rtl/tsan_rtl.cc + ../rtl/tsan_rtl_mutex.cc + ../rtl/tsan_rtl_report.cc + ../rtl/tsan_rtl_thread.cc + ../rtl/tsan_stat.cc + ../rtl/tsan_suppressions.cc + ../rtl/tsan_sync.cc + ../../sanitizer_common/sanitizer_allocator.cc + ../../sanitizer_common/sanitizer_common.cc + ../../sanitizer_common/sanitizer_flags.cc + ../../sanitizer_common/sanitizer_libc.cc + ../../sanitizer_common/sanitizer_posix.cc + ../../sanitizer_common/sanitizer_printf.cc + ../../sanitizer_common/sanitizer_symbolizer.cc +" + +if [ "$LINUX" != "" ]; then + SRCS+=" + ../rtl/tsan_platform_linux.cc + ../../sanitizer_common/sanitizer_linux.cc + " +elif [ "$MAC" != "" ]; then + SRCS+=" + ../rtl/tsan_platform_mac.cc + ../../sanitizer_common/sanitizer_mac.cc + " +fi + +SRCS+=$ADD_SRCS +#ASMS="../rtl/tsan_rtl_amd64.S" + +rm -f gotsan.cc +for F in $SRCS; do + cat $F >> gotsan.cc +done + +FLAGS=" -I../rtl -I../.. -I../../sanitizer_common -fPIC -g -Wall -Werror -fno-exceptions -DTSAN_GO -DSANITIZER_GO -DTSAN_SHADOW_COUNT=4" +if [ "$DEBUG" == "" ]; then + FLAGS+=" -DTSAN_DEBUG=0 -O3 -fomit-frame-pointer" +else + FLAGS+=" -DTSAN_DEBUG=1 -g" +fi + +if [ "$LINUX" != "" ]; then + FLAGS+=" -ffreestanding" +fi + +echo gcc gotsan.cc -S -o tmp.s $FLAGS $CFLAGS +gcc gotsan.cc -S -o tmp.s $FLAGS $CFLAGS +cat tmp.s $ASMS > gotsan.s +echo as gotsan.s -o race_$SUFFIX.syso +as gotsan.s -o race_$SUFFIX.syso + +gcc test.c race_$SUFFIX.syso -lpthread -o test +TSAN_OPTIONS="exitcode=0" ./test + diff --git a/lib/tsan/go/test.c b/lib/tsan/go/test.c new file mode 100644 index 0000000..a9a5b3d --- /dev/null +++ b/lib/tsan/go/test.c @@ -0,0 +1,51 @@ +//===-- test.c ------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Sanity test for Go runtime. +// +//===----------------------------------------------------------------------===// + +#include <stdio.h> + +void __tsan_init(); +void __tsan_fini(); +void __tsan_go_start(int pgoid, int chgoid, void *pc); +void __tsan_go_end(int goid); +void __tsan_read(int goid, void *addr, void *pc); +void __tsan_write(int goid, void *addr, void *pc); +void __tsan_func_enter(int goid, void *pc); +void __tsan_func_exit(int goid); +void __tsan_malloc(int goid, void *p, unsigned long sz, void *pc); +void __tsan_free(void *p); +void __tsan_acquire(int goid, void *addr); +void __tsan_release(int goid, void *addr); +void __tsan_release_merge(int goid, void *addr); + +int __tsan_symbolize(void *pc, char **img, char **rtn, char **file, int *l) { + return 0; +} + +char buf[10]; + +int main(void) { + __tsan_init(); + __tsan_func_enter(0, &main); + __tsan_malloc(0, buf, 10, 0); + __tsan_release(0, buf); + __tsan_release_merge(0, buf); + __tsan_go_start(0, 1, 0); + __tsan_write(1, buf, 0); + __tsan_acquire(1, buf); + __tsan_go_end(1); + __tsan_read(0, buf, 0); + __tsan_free(buf); + __tsan_func_exit(0); + __tsan_fini(); + return 0; +} diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc new file mode 100644 index 0000000..4b3076c --- /dev/null +++ b/lib/tsan/go/tsan_go.cc @@ -0,0 +1,185 @@ +//===-- tsan_go.cc --------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ThreadSanitizer runtime for Go language. +// +//===----------------------------------------------------------------------===// + +#include "tsan_rtl.h" +#include "tsan_symbolize.h" +#include "sanitizer_common/sanitizer_common.h" +#include <stdlib.h> + +namespace __tsan { + +static ThreadState *goroutines[kMaxTid]; + +void InitializeInterceptors() { +} + +void InitializeDynamicAnnotations() { +} + +bool IsExpectedReport(uptr addr, uptr size) { + return false; +} + +void internal_start_thread(void(*func)(void*), void *arg) { +} + +ReportStack *SymbolizeData(uptr addr) { + return 0; +} + +ReportStack *NewReportStackEntry(uptr addr) { + ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack, + sizeof(ReportStack)); + internal_memset(ent, 0, sizeof(*ent)); + ent->pc = addr; + return ent; +} + +void *internal_alloc(MBlockType typ, uptr sz) { + return InternalAlloc(sz); +} + +void internal_free(void *p) { + InternalFree(p); +} + +// Callback into Go. +extern "C" int __tsan_symbolize(uptr pc, char **func, char **file, + int *line, int *off); + +ReportStack *SymbolizeCode(uptr addr) { + ReportStack *s = (ReportStack*)internal_alloc(MBlockReportStack, + sizeof(ReportStack)); + internal_memset(s, 0, sizeof(*s)); + s->pc = addr; + char *func = 0, *file = 0; + int line = 0, off = 0; + if (__tsan_symbolize(addr, &func, &file, &line, &off)) { + s->offset = off; + s->func = internal_strdup(func ? func : "??"); + s->file = internal_strdup(file ? file : "-"); + s->line = line; + s->col = 0; + free(func); + free(file); + } + return s; +} + +extern "C" { + +static void AllocGoroutine(int tid) { + goroutines[tid] = (ThreadState*)internal_alloc(MBlockThreadContex, + sizeof(ThreadState)); + internal_memset(goroutines[tid], 0, sizeof(ThreadState)); +} + +void __tsan_init() { + AllocGoroutine(0); + ThreadState *thr = goroutines[0]; + thr->in_rtl++; + Initialize(thr); + thr->in_rtl--; +} + +void __tsan_fini() { + // FIXME: Not necessary thread 0. + ThreadState *thr = goroutines[0]; + thr->in_rtl++; + int res = Finalize(thr); + thr->in_rtl--; + exit(res); +} + +void __tsan_read(int goid, void *addr, void *pc) { + ThreadState *thr = goroutines[goid]; + MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, false); +} + +void __tsan_write(int goid, void *addr, void *pc) { + ThreadState *thr = goroutines[goid]; + MemoryAccess(thr, (uptr)pc, (uptr)addr, 0, true); +} + +void __tsan_func_enter(int goid, void *pc) { + ThreadState *thr = goroutines[goid]; + FuncEntry(thr, (uptr)pc); +} + +void __tsan_func_exit(int goid) { + ThreadState *thr = goroutines[goid]; + FuncExit(thr); +} + +void __tsan_malloc(int goid, void *p, uptr sz, void *pc) { + ThreadState *thr = goroutines[goid]; + thr->in_rtl++; + MemoryResetRange(thr, (uptr)pc, (uptr)p, sz); + MemoryAccessRange(thr, (uptr)pc, (uptr)p, sz, true); + thr->in_rtl--; +} + +void __tsan_free(void *p) { + (void)p; +} + +void __tsan_go_start(int pgoid, int chgoid, void *pc) { + if (chgoid == 0) + return; + AllocGoroutine(chgoid); + ThreadState *thr = goroutines[chgoid]; + ThreadState *parent = goroutines[pgoid]; + thr->in_rtl++; + parent->in_rtl++; + int goid2 = ThreadCreate(parent, (uptr)pc, 0, true); + ThreadStart(thr, goid2); + parent->in_rtl--; + thr->in_rtl--; +} + +void __tsan_go_end(int goid) { + ThreadState *thr = goroutines[goid]; + thr->in_rtl++; + ThreadFinish(thr); + thr->in_rtl--; +} + +void __tsan_acquire(int goid, void *addr) { + ThreadState *thr = goroutines[goid]; + thr->in_rtl++; + Acquire(thr, 0, (uptr)addr); + thr->in_rtl--; + //internal_free(thr); +} + +void __tsan_release(int goid, void *addr) { + ThreadState *thr = goroutines[goid]; + thr->in_rtl++; + ReleaseStore(thr, 0, (uptr)addr); + thr->in_rtl--; +} + +void __tsan_release_merge(int goid, void *addr) { + ThreadState *thr = goroutines[goid]; + thr->in_rtl++; + Release(thr, 0, (uptr)addr); + thr->in_rtl--; +} + +void __tsan_finalizer_goroutine(int goid) { + ThreadState *thr = goroutines[goid]; + ThreadFinalizerGoroutine(thr); +} + +} // extern "C" +} // namespace __tsan |