tsan: add standalone deadlock detector

llvm-svn: 202505
This commit is contained in:
Dmitry Vyukov 2014-02-28 14:52:20 +00:00
parent 9cffc9550b
commit 512a18e518
5 changed files with 6168 additions and 0 deletions

View File

@ -0,0 +1,45 @@
#!/bin/bash
set -e
SRCS="
dd_rtl.cc
dd_interceptors.cc
../../sanitizer_common/sanitizer_allocator.cc
../../sanitizer_common/sanitizer_common.cc
../../sanitizer_common/sanitizer_deadlock_detector1.cc
../../sanitizer_common/sanitizer_flags.cc
../../sanitizer_common/sanitizer_libc.cc
../../sanitizer_common/sanitizer_printf.cc
../../sanitizer_common/sanitizer_suppressions.cc
../../sanitizer_common/sanitizer_thread_registry.cc
../../sanitizer_common/sanitizer_posix.cc
../../sanitizer_common/sanitizer_posix_libcdep.cc
../../sanitizer_common/sanitizer_procmaps_linux.cc
../../sanitizer_common/sanitizer_linux.cc
../../sanitizer_common/sanitizer_linux_libcdep.cc
../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
../../sanitizer_common/sanitizer_stackdepot.cc
../../sanitizer_common/sanitizer_stacktrace.cc
../../sanitizer_common/sanitizer_stacktrace_libcdep.cc
../../sanitizer_common/sanitizer_symbolizer.cc
../../sanitizer_common/sanitizer_symbolizer_libcdep.cc
../../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
../../sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
../../interception/interception_linux.cc
"
FLAGS=" -I../.. -I../../sanitizer_common -I../../interception -Wall -fno-exceptions -fno-rtti -DSANITIZER_USE_MALLOC"
if [ "$DEBUG" == "" ]; then
FLAGS+=" -DDEBUG=0 -O3 -fomit-frame-pointer"
else
FLAGS+=" -DDEBUG=1 -g"
fi
rm -f dd.cc
for F in $SRCS; do
g++ $F -c -o dd.o $FLAGS
cat $F >> dd.cc
done
g++ dd.cc -c -o dd.o $FLAGS

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
//===-- dd_interceptors.cc ------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "dd_rtl.h"
#include "interception/interception.h"
#include <pthread.h>
using namespace __dsan;
extern "C" void *__libc_malloc(uptr size);
extern "C" void __libc_free(void *ptr);
static __thread Thread *thr;
static void InitThread() {
if (thr != 0)
return;
thr = (Thread*)InternalAlloc(sizeof(*thr));
internal_memset(thr, 0, sizeof(*thr));
ThreadInit(thr);
}
INTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) {
InitThread();
int res = REAL(pthread_mutex_destroy)(m);
MutexDestroy(thr, (uptr)m);
return res;
}
INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) {
InitThread();
int res = REAL(pthread_mutex_lock)(m);
if (res == 0)
MutexLock(thr, (uptr)m, true, false);
return res;
}
INTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) {
InitThread();
int res = REAL(pthread_mutex_trylock)(m);
if (res == 0)
MutexLock(thr, (uptr)m, true, true);
return res;
}
INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) {
InitThread();
MutexUnlock(thr, (uptr)m, true);
int res = REAL(pthread_mutex_unlock)(m);
return res;
}
namespace __dsan {
void InitializeInterceptors() {
INTERCEPT_FUNCTION(pthread_mutex_destroy);
INTERCEPT_FUNCTION(pthread_mutex_lock);
INTERCEPT_FUNCTION(pthread_mutex_trylock);
INTERCEPT_FUNCTION(pthread_mutex_unlock);
}
} // namespace __dsan

View File

@ -0,0 +1,128 @@
//===-- dd_rtl.cc ---------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "dd_rtl.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
namespace __dsan {
static Context ctx0;
static Context * const ctx = &ctx0;
void Initialize() {
InitializeInterceptors();
//common_flags()->allow_addr2line = true;
common_flags()->symbolize = true;
ctx->dd = DDetector::Create();
}
void ThreadInit(Thread *thr) {
thr->dd_pt = ctx->dd->CreatePhysicalThread();
thr->dd_lt = ctx->dd->CreateLogicalThread(0);
}
void ThreadDestroy(Thread *thr) {
ctx->dd->DestroyPhysicalThread(thr->dd_pt);
ctx->dd->DestroyLogicalThread(thr->dd_lt);
}
static u32 CurrentStackTrace(Thread *thr) {
StackTrace trace;
thr->in_symbolizer = true;
trace.Unwind(1000, 0, 0, 0, 0, 0, false);
thr->in_symbolizer = false;
const uptr skip = 4;
if (trace.size <= skip)
return 0;
return StackDepotPut(trace.trace + skip, trace.size - skip);
}
static void PrintStackTrace(Thread *thr, u32 stk) {
uptr size = 0;
const uptr *trace = StackDepotGet(stk, &size);
thr->in_symbolizer = true;
StackTrace::PrintStack(trace, size);
thr->in_symbolizer = false;
}
static Mutex *FindMutex(Thread *thr, uptr m) {
SpinMutexLock l(&ctx->mutex_mtx);
for (Mutex *mtx = ctx->mutex_list; mtx; mtx = mtx->link) {
if (mtx->addr == m)
return mtx;
}
Mutex *mtx = (Mutex*)InternalAlloc(sizeof(*mtx));
internal_memset(mtx, 0, sizeof(*mtx));
mtx->addr = m;
ctx->dd->MutexInit(&mtx->dd, CurrentStackTrace(thr), ctx->mutex_seq++);
mtx->link = ctx->mutex_list;
ctx->mutex_list = mtx;
return mtx;
}
static Mutex *FindMutexAndRemove(uptr m) {
SpinMutexLock l(&ctx->mutex_mtx);
Mutex **prev = &ctx->mutex_list;
for (;;) {
Mutex *mtx = *prev;
if (mtx == 0)
return 0;
if (mtx->addr == m) {
*prev = mtx->link;
return mtx;
}
prev = &mtx->link;
}
}
static void ReportDeadlock(Thread *thr, DDReport *rep) {
Printf("==============================\n");
Printf("DEADLOCK\n");
PrintStackTrace(thr, CurrentStackTrace(thr));
for (int i = 0; i < rep->n; i++) {
Printf("Mutex %llu created at:\n", rep->loop[i].mtx_ctx0);
PrintStackTrace(thr, rep->loop[i].stk);
}
Printf("==============================\n");
}
void MutexLock(Thread *thr, uptr m, bool writelock, bool trylock) {
if (thr->in_symbolizer)
return;
Mutex *mtx = FindMutex(thr, m);
DDReport *rep = ctx->dd->MutexLock(thr->dd_pt, thr->dd_lt, &mtx->dd,
writelock, trylock);
if (rep)
ReportDeadlock(thr, rep);
}
void MutexUnlock(Thread *thr, uptr m, bool writelock) {
if (thr->in_symbolizer)
return;
Mutex *mtx = FindMutex(thr, m);
ctx->dd->MutexUnlock(thr->dd_pt, thr->dd_lt, &mtx->dd, writelock);
}
void MutexDestroy(Thread *thr, uptr m) {
if (thr->in_symbolizer)
return;
Mutex *mtx = FindMutexAndRemove(m);
if (mtx == 0)
return;
ctx->dd->MutexDestroy(thr->dd_pt, thr->dd_lt, &mtx->dd);
InternalFree(mtx);
}
} // namespace __dsan
__attribute__((section(".preinit_array"), used))
void (*__local_dsan_preinit)(void) = __dsan::Initialize;

View File

@ -0,0 +1,50 @@
//===-- dd_rtl.h ----------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef DD_RTL_H
#define DD_RTL_H
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_mutex.h"
namespace __dsan {
struct Mutex {
Mutex *link;
uptr addr;
DDMutex dd;
};
struct Thread {
DDPhysicalThread *dd_pt;
DDLogicalThread *dd_lt;
bool in_symbolizer;
};
struct Context {
DDetector *dd;
SpinMutex mutex_mtx;
Mutex *mutex_list;
u64 mutex_seq;
};
void InitializeInterceptors();
void ThreadInit(Thread *thr);
void ThreadDestroy(Thread *thr);
void MutexLock(Thread *thr, uptr m, bool writelock, bool trylock);
void MutexUnlock(Thread *thr, uptr m, bool writelock);
void MutexDestroy(Thread *thr, uptr m);
} // namespace __dsan
#endif // DD_RTL_H