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"
1486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "sanitizer_common/sanitizer_flag_parser.h"
152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_stacktrace.h"
162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_common/sanitizer_stackdepot.h"
172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesnamespace __dsan {
192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic Context *ctx;
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic u32 CurrentStackTrace(Thread *thr, uptr skip) {
236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  BufferedStackTrace stack;
242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->ignore_interceptors = true;
256d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  stack.Unwind(1000, 0, 0, 0, 0, 0, false);
262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->ignore_interceptors = false;
276d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (stack.size <= skip)
282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return 0;
296d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintStackTrace(Thread *thr, u32 stk) {
336d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  StackTrace stack = StackDepotGet(stk);
342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->ignore_interceptors = true;
356d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  stack.Print();
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
6886277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesstatic void InitializeFlags() {
6986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  Flags *f = flags();
702d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
712d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Default values.
722d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  f->second_deadlock_stack = false;
732d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
7486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SetCommonFlagsDefaults();
7586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  {
7686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    // Override some common flags defaults.
7786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    CommonFlags cf;
7886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    cf.CopyFrom(*common_flags());
7986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    cf.allow_addr2line = true;
8086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    OverrideCommonFlags(cf);
8186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  }
822d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
832d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  // Override from command line.
8486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  FlagParser parser;
8586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
8686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  RegisterCommonFlags(&parser);
8786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  parser.ParseString(GetEnv("DSAN_OPTIONS"));
8886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SetVerbosity(common_flags()->verbosity);
892d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
902d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
912d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid Initialize() {
922d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
932d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx = new(ctx_mem) Context();
942d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
952d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  InitializeInterceptors();
9686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  InitializeFlags();
972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd = DDetector::Create(flags());
982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ThreadInit(Thread *thr) {
1012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  static atomic_uintptr_t id_gen;
1022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
1032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->dd_pt = ctx->dd->CreatePhysicalThread();
1042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  thr->dd_lt = ctx->dd->CreateLogicalThread(id);
1052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid ThreadDestroy(Thread *thr) {
1082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd->DestroyPhysicalThread(thr->dd_pt);
1092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd->DestroyLogicalThread(thr->dd_lt);
1102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
1132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  {
1172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    MutexHashMap::Handle h(&ctx->mutex_map, m);
1182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    if (h.created())
1192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      ctx->dd->MutexInit(&cb, &h->dd);
1202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
1212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
1262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  {
1302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    MutexHashMap::Handle h(&ctx->mutex_map, m);
1312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    if (h.created())
1322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      ctx->dd->MutexInit(&cb, &h->dd);
1332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
1342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
1392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  {
1432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    MutexHashMap::Handle h(&ctx->mutex_map, m);
1442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
1452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
1462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ReportDeadlock(thr, ctx->dd->GetReport(&cb));
1472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid MutexDestroy(Thread *thr, uptr m) {
1502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (thr->ignore_interceptors)
1512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Callback cb(thr);
1532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  MutexHashMap::Handle h(&ctx->mutex_map, m, true);
1542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (!h.exists())
1552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return;
1562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  ctx->dd->MutexDestroy(&cb, &h->dd);
1572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
1582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1592d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}  // namespace __dsan
160