llvm/compiler-rt/lib/tsan/rtl/tsan_report.cpp

//===-- tsan_report.cpp ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "tsan_report.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stacktrace_printer.h"

namespace __tsan {

class Decorator: public __sanitizer::SanitizerCommonDecorator {};

ReportDesc::ReportDesc()
    :{}

ReportMop::ReportMop()
    :{}

ReportDesc::~ReportDesc() {}

#if !SANITIZER_GO

const int kThreadBufSize =;
const char *thread_name(char *buf, Tid tid) {}

static const char *ReportTypeString(ReportType typ, uptr tag) {}

void PrintStack(const ReportStack *ent) {}

static void PrintMutexSet(Vector<ReportMopMutex> const& mset) {}

static const char *MopDesc(bool first, bool write, bool atomic) {}

static const char *ExternalMopDesc(bool first, bool write) {}

static void PrintMop(const ReportMop *mop, bool first) {}

static void PrintLocation(const ReportLocation *loc) {}

static void PrintMutexShort(const ReportMutex *rm, const char *after) {}

static void PrintMutexShortWithAddress(const ReportMutex *rm,
                                       const char *after) {}

static void PrintMutex(const ReportMutex *rm) {}

static void PrintThread(const ReportThread *rt) {}

static void PrintSleep(const ReportStack *s) {}

static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {}

static const SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {}

void PrintReport(const ReportDesc *rep) {}

#else  // #if !SANITIZER_GO

const Tid kMainGoroutineId = 1;

void PrintStack(const ReportStack *ent) {
  if (ent == 0 || ent->frames == 0) {
    Printf("  [failed to restore the stack]\n");
    return;
  }
  SymbolizedStack *frame = ent->frames;
  for (int i = 0; frame; frame = frame->next, i++) {
    const AddressInfo &info = frame->info;
    Printf("  %s()\n      %s:%d +0x%zx\n", info.function,
           StripPathPrefix(info.file, common_flags()->strip_path_prefix),
           info.line, info.module_offset);
  }
}

static void PrintMop(const ReportMop *mop, bool first) {
  Printf("\n");
  Printf("%s at %p by ",
         (first ? (mop->write ? "Write" : "Read")
                : (mop->write ? "Previous write" : "Previous read")),
         reinterpret_cast<void *>(mop->addr));
  if (mop->tid == kMainGoroutineId)
    Printf("main goroutine:\n");
  else
    Printf("goroutine %d:\n", mop->tid);
  PrintStack(mop->stack);
}

static void PrintLocation(const ReportLocation *loc) {
  switch (loc->type) {
  case ReportLocationHeap: {
    Printf("\n");
    Printf("Heap block of size %zu at %p allocated by ", loc->heap_chunk_size,
           reinterpret_cast<void *>(loc->heap_chunk_start));
    if (loc->tid == kMainGoroutineId)
      Printf("main goroutine:\n");
    else
      Printf("goroutine %d:\n", loc->tid);
    PrintStack(loc->stack);
    break;
  }
  case ReportLocationGlobal: {
    Printf("\n");
    Printf("Global var %s of size %zu at %p declared at %s:%zu\n",
           loc->global.name, loc->global.size,
           reinterpret_cast<void *>(loc->global.start), loc->global.file,
           loc->global.line);
    break;
  }
  default:
    break;
  }
}

static void PrintThread(const ReportThread *rt) {
  if (rt->id == kMainGoroutineId)
    return;
  Printf("\n");
  Printf("Goroutine %d (%s) created at:\n",
    rt->id, rt->running ? "running" : "finished");
  PrintStack(rt->stack);
}

void PrintReport(const ReportDesc *rep) {
  Printf("==================\n");
  if (rep->typ == ReportTypeRace) {
    Printf("WARNING: DATA RACE");
    for (uptr i = 0; i < rep->mops.Size(); i++)
      PrintMop(rep->mops[i], i == 0);
    for (uptr i = 0; i < rep->locs.Size(); i++)
      PrintLocation(rep->locs[i]);
    for (uptr i = 0; i < rep->threads.Size(); i++)
      PrintThread(rep->threads[i]);
  } else if (rep->typ == ReportTypeDeadlock) {
    Printf("WARNING: DEADLOCK\n");
    for (uptr i = 0; i < rep->mutexes.Size(); i++) {
      Printf("Goroutine %d lock mutex %u while holding mutex %u:\n", 999,
             rep->mutexes[i]->id,
             rep->mutexes[(i + 1) % rep->mutexes.Size()]->id);
      PrintStack(rep->stacks[2*i]);
      Printf("\n");
      Printf("Mutex %u was previously locked here:\n",
             rep->mutexes[(i + 1) % rep->mutexes.Size()]->id);
      PrintStack(rep->stacks[2*i + 1]);
      Printf("\n");
    }
  }
  Printf("==================\n");
}

#endif

}  // namespace __tsan