tsan: use dynamic shadow stack for Go

llvm-svn: 160288
This commit is contained in:
Dmitry Vyukov 2012-07-16 16:44:47 +00:00
parent 6c7dbf5858
commit 5bfac97ff9
7 changed files with 42 additions and 6 deletions

View File

@ -28,9 +28,7 @@ const int kTidBits = 13;
const unsigned kMaxTid = 1 << kTidBits;
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
const int kClkBits = 43;
#ifdef TSAN_GO
const int kShadowStackSize = 8 * 1024;
#else
#ifndef TSAN_GO
const int kShadowStackSize = 1024;
#endif

View File

@ -36,6 +36,7 @@ enum MBlockType {
MBlockScopedBuf,
MBlockString,
MBlockStackTrace,
MBlockShadowStack,
MBlockSync,
MBlockClock,
MBlockThreadContex,

View File

@ -451,14 +451,28 @@ void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
void FuncEntry(ThreadState *thr, uptr pc) {
DCHECK_EQ(thr->in_rtl, 0);
StatInc(thr, StatFuncEnter);
DPrintf2("#%d: tsan::FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeFuncEnter, pc);
// Shadow stack maintenance can be replaced with
// stack unwinding during trace switch (which presumably must be faster).
DCHECK_GE(thr->shadow_stack_pos, &thr->shadow_stack[0]);
#ifndef TSAN_GO
DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
#else
if (thr->shadow_stack_pos == thr->shadow_stack_end) {
const int sz = thr->shadow_stack_end - thr->shadow_stack;
const int newsz = 2 * sz;
uptr *newstack = (uptr*)internal_alloc(MBlockShadowStack,
newsz * sizeof(uptr));
internal_memcpy(newstack, thr->shadow_stack, sz * sizeof(uptr));
internal_free(thr->shadow_stack);
thr->shadow_stack = newstack;
thr->shadow_stack_pos = newstack + sz;
thr->shadow_stack_end = newstack + newsz;
}
#endif
thr->shadow_stack_pos[0] = pc;
thr->shadow_stack_pos++;
}
@ -466,12 +480,14 @@ void FuncEntry(ThreadState *thr, uptr pc) {
void FuncExit(ThreadState *thr) {
DCHECK_EQ(thr->in_rtl, 0);
StatInc(thr, StatFuncExit);
DPrintf2("#%d: tsan::FuncExit\n", (int)thr->fast_state.tid());
DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeFuncExit, 0);
DCHECK_GT(thr->shadow_stack_pos, &thr->shadow_stack[0]);
#ifndef TSAN_GO
DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
#endif
thr->shadow_stack_pos--;
}

View File

@ -228,7 +228,14 @@ struct ThreadState {
u64 *racy_shadow_addr;
u64 racy_state[2];
Trace trace;
#ifndef TSAN_GO
// C/C++ uses embed shadow stack of fixed size.
uptr shadow_stack[kShadowStackSize];
#else
// Go uses satellite shadow stack with dynamic size.
uptr *shadow_stack;
uptr *shadow_stack_end;
#endif
ThreadClock clock;
u64 stat[StatCnt];
const int tid;

View File

@ -173,6 +173,14 @@ void ThreadStart(ThreadState *thr, int tid) {
tctx->epoch1 = (u64)-1;
new(thr) ThreadState(CTX(), tid, tctx->epoch0, stk_addr, stk_size,
tls_addr, tls_size);
#ifdef TSAN_GO
// Setup dynamic shadow stack.
const int kInitStackSize = 8;
thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
kInitStackSize * sizeof(uptr));
thr->shadow_stack_pos = thr->shadow_stack;
thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
tctx->thr = thr;
thr->fast_synch_epoch = tctx->epoch0;
thr->clock.set(tid, tctx->epoch0);

View File

@ -174,7 +174,7 @@ void StackTrace::Init(const uptr *pcs, uptr cnt) {
void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
Reset();
n_ = thr->shadow_stack_pos - &thr->shadow_stack[0];
n_ = thr->shadow_stack_pos - thr->shadow_stack;
if (n_ + !!toppc == 0)
return;
if (c_) {

View File

@ -42,10 +42,16 @@ typedef u64 Event;
struct TraceHeader {
StackTrace stack0; // Start stack for the trace.
u64 epoch0; // Start epoch for the trace.
#ifndef TSAN_GO
uptr stack0buf[kShadowStackSize];
#endif
TraceHeader()
#ifndef TSAN_GO
: stack0(stack0buf, kShadowStackSize)
#else
: stack0()
#endif
, epoch0() {
}
};