12d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines//===-- dd_rtl.cc ---------------------------------------------------------===//
22d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines//
32d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines//                     The LLVM Compiler Infrastructure
42d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines//
52d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// This file is distributed under the University of Illinois Open Source
62d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// License. See LICENSE.TXT for details.
72d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines//
82d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines//===----------------------------------------------------------------------===//
92d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "dd_rtl.h"
112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_common.h"
122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_placement_new.h"
132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_flags.h"
142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_stacktrace.h"
152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_stackdepot.h"
162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesnamespace __dsan {
182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic Context *ctx;
202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic u32 CurrentStackTrace(Thread *thr, uptr skip) {
222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  StackTrace trace;
232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->ignore_interceptors = true;
242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  trace.Unwind(1000, 0, 0, 0, 0, 0, false);
252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->ignore_interceptors = false;
262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (trace.size <= skip)
272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return 0;
282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return StackDepotPut(trace.trace + skip, trace.size - skip);
292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintStackTrace(Thread *thr, u32 stk) {
322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr size = 0;
332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  const uptr *trace = StackDepotGet(stk, &size);
342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->ignore_interceptors = true;
352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  StackTrace::PrintStack(trace, size);
362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->ignore_interceptors = false;
372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void ReportDeadlock(Thread *thr, DDReport *rep) {
402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (rep == 0)
412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  BlockingMutexLock lock(&ctx->report_mutex);
432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Printf("==============================\n");
442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Printf("WARNING: lock-order-inversion (potential deadlock)\n");
452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  for (int i = 0; i < rep->n; i++) {
462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PrintStackTrace(thr, rep->loop[i].stk[1]);
492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    if (rep->loop[i].stk[0]) {
502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("Mutex %llu was acquired here:\n",
512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        rep->loop[i].mtx_ctx0);
522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintStackTrace(thr, rep->loop[i].stk[0]);
532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Printf("==============================\n");
562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesCallback::Callback(Thread *thr)
592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    : thr(thr) {
602d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  lt = thr->dd_lt;
612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  pt = thr->dd_pt;
622d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
632d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
642d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesu32 Callback::Unwind() {
652d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return CurrentStackTrace(thr, 3);
662d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
672d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
682d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid InitializeFlags(Flags *f, const char *env) {
692d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  internal_memset(f, 0, sizeof(*f));
702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Default values.
722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  f->second_deadlock_stack = false;
732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
742d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  SetCommonFlagsDefaults(f);
752d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Override some common flags defaults.
762d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  f->allow_addr2line = true;
772d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
782d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Override from command line.
792d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
802d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ParseCommonFlagsFromString(f, env);
812d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Copy back to common flags.
832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  *common_flags() = *f;
842d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
852d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
862d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid Initialize() {
872d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
882d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx = new(ctx_mem) Context();
892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  InitializeInterceptors();
912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  InitializeFlags(flags(), GetEnv("DSAN_OPTIONS"));
922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  common_flags()->symbolize = true;
932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd = DDetector::Create(flags());
942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
962d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ThreadInit(Thread *thr) {
972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static atomic_uintptr_t id_gen;
982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->dd_pt = ctx->dd->CreatePhysicalThread();
1002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->dd_lt = ctx->dd->CreateLogicalThread(id);
1012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ThreadDestroy(Thread *thr) {
1042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd->DestroyPhysicalThread(thr->dd_pt);
1052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd->DestroyLogicalThread(thr->dd_lt);
1062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
1092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  {
1132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    MutexHashMap::Handle h(&ctx->mutex_map, m);
1142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    if (h.created())
1152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      ctx->dd->MutexInit(&cb, &h->dd);
1162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
1172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
1222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  {
1262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    MutexHashMap::Handle h(&ctx->mutex_map, m);
1272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    if (h.created())
1282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      ctx->dd->MutexInit(&cb, &h->dd);
1292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
1302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
1352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  {
1392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    MutexHashMap::Handle h(&ctx->mutex_map, m);
1402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
1412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexDestroy(Thread *thr, uptr m) {
1462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  MutexHashMap::Handle h(&ctx->mutex_map, m, true);
1502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (!h.exists())
1512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd->MutexDestroy(&cb, &h->dd);
1532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}  // namespace __dsan
156