1603c4be006d8c53905d736bf1f19a49f5ce98276Alexey Samsonov//===-- tsan_report.cc ----------------------------------------------------===//
27ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
37ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//                     The LLVM Compiler Infrastructure
47ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
57ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is distributed under the University of Illinois Open Source
67ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// License. See LICENSE.TXT for details.
77ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
87ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
97ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
107ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany// This file is a part of ThreadSanitizer (TSan), a race detector.
117ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//
127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany//===----------------------------------------------------------------------===//
137ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_report.h"
147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_platform.h"
157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany#include "tsan_rtl.h"
166d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_common/sanitizer_placement_new.h"
17a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany#include "sanitizer_common/sanitizer_report_decorator.h"
186d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_common/sanitizer_stacktrace_printer.h"
197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2286277eb844c4983c81de62d7c050e92fe7155788Stephen HinesReportStack::ReportStack() : frames(nullptr), suppressable(false) {}
236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
2486277eb844c4983c81de62d7c050e92fe7155788Stephen HinesReportStack *ReportStack::New() {
256d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack));
2686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  return new(mem) ReportStack();
276d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
286d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
296d1862363c88c183b0ed7740fca876342cf0474bStephen HinesReportLocation::ReportLocation(ReportLocationType type)
306d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0),
316d1862363c88c183b0ed7740fca876342cf0474bStephen Hines      fd(0), suppressable(false), stack(nullptr) {}
326d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
336d1862363c88c183b0ed7740fca876342cf0474bStephen HinesReportLocation *ReportLocation::New(ReportLocationType type) {
346d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation));
356d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  return new(mem) ReportLocation(type);
366d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
376d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
386a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hinesclass Decorator: public __sanitizer::SanitizerCommonDecorator {
39a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany public:
406a211c5814e25d6745a5058cc0e499e5235d3821Stephen Hines  Decorator() : SanitizerCommonDecorator() { }
41a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Warning()    { return Red(); }
42a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndWarning() { return Default(); }
43a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Access()     { return Blue(); }
44a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndAccess()  { return Default(); }
45a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *ThreadDescription()    { return Cyan(); }
46a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndThreadDescription() { return Default(); }
47a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Location()   { return Green(); }
48a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndLocation() { return Default(); }
49a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Sleep()   { return Yellow(); }
50a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndSleep() { return Default(); }
51a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Mutex()   { return Magenta(); }
52a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndMutex() { return Default(); }
53a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany};
54a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany
557ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::ReportDesc()
567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    : stacks(MBlockReportStack)
577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mops(MBlockReportMop)
587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , locs(MBlockReportLoc)
597ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mutexes(MBlockReportMutex)
60848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    , threads(MBlockReportThread)
612d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    , unique_tids(MBlockReportThread)
624536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    , sleep()
634536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    , count() {
647ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
657ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
66ad9da372f962495b3487685232d09390be841b1cDmitry VyukovReportMop::ReportMop()
67ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    : mset(MBlockReportMutex) {
68ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
69ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
707ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::~ReportDesc() {
71aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  // FIXME(dvyukov): it must be leaking a lot of memory.
727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
7486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#ifndef SANITIZER_GO
75c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
76da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst int kThreadBufSize = 32;
77da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst char *thread_name(char *buf, int tid) {
78da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  if (tid == 0)
79da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    return "main thread";
80da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
81da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  return buf;
82da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov}
83da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov
842f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic const char *ReportTypeString(ReportType typ) {
857ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (typ == ReportTypeRace)
862f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "data race";
870dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  if (typ == ReportTypeVptrRace)
880dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov    return "data race on vptr (ctor/dtor vs virtual call)";
892f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeUseAfterFree)
902f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "heap-use-after-free";
916d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (typ == ReportTypeVptrUseAfterFree)
926d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return "heap-use-after-free (virtual call vs free)";
932f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeThreadLeak)
942f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "thread leak";
952f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeMutexDestroyLocked)
962f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "destroy of a locked mutex";
972d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexDoubleLock)
982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "double lock of a mutex";
99c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  if (typ == ReportTypeMutexInvalidAccess)
100c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    return "use of an invalid mutex (e.g. uninitialized or destroyed)";
1012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexBadUnlock)
1022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "unlock of an unlocked mutex (or by a wrong thread)";
1032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexBadReadLock)
1042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "read lock of a write locked mutex";
1052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeMutexBadReadUnlock)
1062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "read unlock of a write locked mutex";
1072f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeSignalUnsafe)
1082f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal-unsafe call inside of a signal";
1092f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeErrnoInSignal)
1102f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal handler spoils errno";
1112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (typ == ReportTypeDeadlock)
1122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    return "lock-order-inversion (potential deadlock)";
1132f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return "";
1147ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
116799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar#if SANITIZER_MAC
117799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainarstatic const char *const kInterposedFunctionPrefix = "wrap_";
118799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar#else
119799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainarstatic const char *const kInterposedFunctionPrefix = "__interceptor_";
120799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar#endif
121799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
1221da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintStack(const ReportStack *ent) {
12386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (ent == 0 || ent->frames == 0) {
12495f50b126cebecc0165fbf6e4c8209c640836271Dmitry Vyukov    Printf("    [failed to restore the stack]\n\n");
125dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov    return;
126dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov  }
12786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SymbolizedStack *frame = ent->frames;
12886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
1296d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    InternalScopedString res(2 * GetPageSizeCached());
13086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    RenderFrame(&res, common_flags()->stack_trace_format, i, frame->info,
131cdce50bda3603770cc4ef80cbb613c78b8e47a17Pirama Arumuga Nainar                common_flags()->symbolize_vs_style,
132799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar                common_flags()->strip_path_prefix, kInterposedFunctionPrefix);
1336d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    Printf("%s\n", res.data());
1347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
135b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
138ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovstatic void PrintMutexSet(Vector<ReportMopMutex> const& mset) {
139ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < mset.Size(); i++) {
140ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (i == 0)
141ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      Printf(" (mutexes:");
142ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    const ReportMopMutex m = mset[i];
143ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(" %s M%llu", m.write ? "write" : "read", m.id);
144ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(i == mset.Size() - 1 ? ")" : ",");
145ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
146ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
147ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
1480a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukovstatic const char *MopDesc(bool first, bool write, bool atomic) {
1490a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov  return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
1500a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous atomic write" : "Previous atomic read"))
1510a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (first ? (write ? "Write" : "Read")
1520a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous write" : "Previous read"));
1530a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov}
1540a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov
1557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMop(const ReportMop *mop, bool first) {
156a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
157da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
158a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Access());
159da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf("  %s of size %d at %p by %s",
1600a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov      MopDesc(first, mop->write, mop->atomic),
161da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      mop->size, (void*)mop->addr,
162da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      thread_name(thrbuf, mop->tid));
163ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  PrintMutexSet(mop->mset);
164ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf(":\n");
165a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndAccess());
1667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(mop->stack);
1677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1687ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintLocation(const ReportLocation *loc) {
170a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
171c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  char thrbuf[kThreadBufSize];
172a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  bool print_stack = false;
173a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Location());
1747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (loc->type == ReportLocationGlobal) {
1756d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    const DataInfo &global = loc->global;
176799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    if (global.size != 0)
177799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar      Printf("  Location is global '%s' of size %zu at %p (%s+%p)\n\n",
178799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar             global.name, global.size, global.start,
179799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar             StripModuleName(global.module), global.module_offset);
180799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    else
181799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar      Printf("  Location is global '%s' at %p (%s+%p)\n\n", global.name,
182799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar             global.start, StripModuleName(global.module),
183799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar             global.module_offset);
1847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationHeap) {
185da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    char thrbuf[kThreadBufSize];
186da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
1876d1862363c88c183b0ed7740fca876342cf0474bStephen Hines           loc->heap_chunk_size, loc->heap_chunk_start,
1886d1862363c88c183b0ed7740fca876342cf0474bStephen Hines           thread_name(thrbuf, loc->tid));
189a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    print_stack = true;
1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationStack) {
191fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
192fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  } else if (loc->type == ReportLocationTLS) {
193fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid));
194c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  } else if (loc->type == ReportLocationFD) {
195c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    Printf("  Location is file descriptor %d created by %s at:\n",
196c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov        loc->fd, thread_name(thrbuf, loc->tid));
197a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    print_stack = true;
1987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
199a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndLocation());
200a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  if (print_stack)
201a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    PrintStack(loc->stack);
2027ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2037ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintMutexShort(const ReportMutex *rm, const char *after) {
2052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Decorator d;
2062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after);
2072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
2082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
2092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void PrintMutexShortWithAddress(const ReportMutex *rm,
2102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                                       const char *after) {
2112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Decorator d;
2122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after);
2132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
2142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
2157ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMutex(const ReportMutex *rm) {
216a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
217ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (rm->destroyed) {
218a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.Mutex());
219ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf("  Mutex M%llu is already destroyed.\n\n", rm->id);
220a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.EndMutex());
221ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  } else {
222a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.Mutex());
2232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("  Mutex M%llu (%p) created at:\n", rm->id, rm->addr);
224a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.EndMutex());
225ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    PrintStack(rm->stack);
226ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
2277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintThread(const ReportThread *rt) {
230a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
2317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->id == 0)  // Little sense in describing the main thread.
2327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
233a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.ThreadDescription());
234ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf("  Thread T%d", rt->id);
2352bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  if (rt->name && rt->name[0] != '\0')
236b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf(" '%s'", rt->name);
237da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
238da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf(" (tid=%zu, %s) created by %s",
239c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    rt->os_id, rt->running ? "running" : "finished",
240da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    thread_name(thrbuf, rt->parent_tid));
2417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->stack)
242da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf(" at:");
243b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
244a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndThreadDescription());
2457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rt->stack);
2467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
248848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovstatic void PrintSleep(const ReportStack *s) {
249a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
250a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Sleep());
251b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("  As if synchronized via sleep:\n");
252a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndSleep());
253848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  PrintStack(s);
254848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
255848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
2562f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
2572f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mops.Size())
2582f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mops[0]->stack;
2592f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->stacks.Size())
2602f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->stacks[0];
2612f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mutexes.Size())
2622f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mutexes[0]->stack;
2632f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->threads.Size())
2642f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->threads[0]->stack;
2652f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return 0;
2662f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
2672f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
26886277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesstatic bool FrameIsInternal(const SymbolizedStack *frame) {
26986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (frame == 0)
27086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    return false;
27186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  const char *file = frame->info.file;
272799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  const char *module = frame->info.module;
273799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  if (file != 0 &&
274799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar      (internal_strstr(file, "tsan_interceptors.cc") ||
275799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar       internal_strstr(file, "sanitizer_common_interceptors.inc") ||
276799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar       internal_strstr(file, "tsan_interface_")))
277799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    return true;
278799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  if (module != 0 && (internal_strstr(module, "libclang_rt.tsan_")))
279799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    return true;
280799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  return false;
28186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}
28286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
28386277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesstatic SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
28486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  while (FrameIsInternal(frames) && frames->next)
28586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    frames = frames->next;
28686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  return frames;
2872f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
2882f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
2897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid PrintReport(const ReportDesc *rep) {
290a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
291b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
2922f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  const char *rep_typ_str = ReportTypeString(rep->typ);
293a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Warning());
2940b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
2950b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne         (int)internal_getpid());
296a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndWarning());
2977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2982d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (rep->typ == ReportTypeDeadlock) {
2992d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    char thrbuf[kThreadBufSize];
3002d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("  Cycle in lock order graph: ");
3012d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++)
3022d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutexShortWithAddress(rep->mutexes[i], " => ");
3032d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    PrintMutexShort(rep->mutexes[0], "\n\n");
3042d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    CHECK_GT(rep->mutexes.Size(), 0U);
3052d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    CHECK_EQ(rep->mutexes.Size() * (flags()->second_deadlock_stack ? 2 : 1),
3062d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines             rep->stacks.Size());
3072d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++) {
3082d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("  Mutex ");
3092d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutexShort(rep->mutexes[(i + 1) % rep->mutexes.Size()],
3102d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                      " acquired here while holding mutex ");
3112d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutexShort(rep->mutexes[i], " in ");
3122d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("%s", d.ThreadDescription());
3132d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i]));
3142d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("%s", d.EndThreadDescription());
3152d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      if (flags()->second_deadlock_stack) {
3162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintStack(rep->stacks[2*i]);
3172d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        Printf("  Mutex ");
3182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintMutexShort(rep->mutexes[i],
3192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                        " previously acquired by the same thread here:\n");
3202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintStack(rep->stacks[2*i+1]);
3212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      } else {
3222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        PrintStack(rep->stacks[i]);
3232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        if (i == 0)
3242d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          Printf("    Hint: use TSAN_OPTIONS=second_deadlock_stack=1 "
3252d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines                 "to get more informative warning message\n\n");
3262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      }
3272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
3282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  } else {
3292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->stacks.Size(); i++) {
3302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      if (i)
3312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines        Printf("  and:\n");
3322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintStack(rep->stacks[i]);
3332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
334332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  }
3357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mops.Size(); i++)
3377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMop(rep->mops[i], i == 0);
3387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
339848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (rep->sleep)
340848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    PrintSleep(rep->sleep);
341848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
3427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->locs.Size(); i++)
3437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintLocation(rep->locs[i]);
3447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (rep->typ != ReportTypeDeadlock) {
3462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++)
3472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMutex(rep->mutexes[i]);
3482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
3497ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->threads.Size(); i++)
3517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintThread(rep->threads[i]);
3527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
3534536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov  if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
3544536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
3554536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov
35686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (ReportStack *stack = ChooseSummaryStack(rep)) {
3577c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames))
3587c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar      ReportErrorSummary(rep_typ_str, frame->info);
3596d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  }
3602f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
361b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
3627ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
3637ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
36486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#else  // #ifndef SANITIZER_GO
3659d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov
3669d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukovconst int kMainThreadId = 1;
367c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
3680ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukovvoid PrintStack(const ReportStack *ent) {
36986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (ent == 0 || ent->frames == 0) {
3709d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("  [failed to restore the stack]\n");
3716c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov    return;
3726c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov  }
37386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SymbolizedStack *frame = ent->frames;
37486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  for (int i = 0; frame; frame = frame->next, i++) {
37586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    const AddressInfo &info = frame->info;
37686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    Printf("  %s()\n      %s:%d +0x%zx\n", info.function,
37786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        StripPathPrefix(info.file, common_flags()->strip_path_prefix),
37886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        info.line, (void *)info.module_offset);
379c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  }
380c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
381c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
382c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintMop(const ReportMop *mop, bool first) {
3839d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("\n");
384c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  Printf("%s at %p by ",
385c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      (first ? (mop->write ? "Write" : "Read")
386c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar             : (mop->write ? "Previous write" : "Previous read")), mop->addr);
3879d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  if (mop->tid == kMainThreadId)
3889d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("main goroutine:\n");
3899d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  else
3909d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("goroutine %d:\n", mop->tid);
391c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  PrintStack(mop->stack);
392c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
393c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
394c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainarstatic void PrintLocation(const ReportLocation *loc) {
395c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  switch (loc->type) {
396c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  case ReportLocationHeap: {
397c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    Printf("\n");
398c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    Printf("Heap block of size %zu at %p allocated by ",
399c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar        loc->heap_chunk_size, loc->heap_chunk_start);
400c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    if (loc->tid == kMainThreadId)
401c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      Printf("main goroutine:\n");
402c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    else
403c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      Printf("goroutine %d:\n", loc->tid);
404c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    PrintStack(loc->stack);
405c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    break;
406c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  }
407c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  case ReportLocationGlobal: {
408c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    Printf("\n");
409c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    Printf("Global var %s of size %zu at %p declared at %s:%zu\n",
410c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar        loc->global.name, loc->global.size, loc->global.start,
411c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar        loc->global.file, loc->global.line);
412c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    break;
413c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  }
414c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  default:
415c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    break;
416c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  }
417c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar}
418c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar
41943046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukovstatic void PrintThread(const ReportThread *rt) {
4209d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  if (rt->id == kMainThreadId)
42143046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    return;
4229d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("\n");
423b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("Goroutine %d (%s) created at:\n",
42443046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    rt->id, rt->running ? "running" : "finished");
42543046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  PrintStack(rt->stack);
42643046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov}
42743046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov
428c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovvoid PrintReport(const ReportDesc *rep) {
429b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
4302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (rep->typ == ReportTypeRace) {
4312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("WARNING: DATA RACE");
4322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mops.Size(); i++)
4332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintMop(rep->mops[i], i == 0);
434c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    for (uptr i = 0; i < rep->locs.Size(); i++)
435c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      PrintLocation(rep->locs[i]);
4362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->threads.Size(); i++)
4372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintThread(rep->threads[i]);
4382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  } else if (rep->typ == ReportTypeDeadlock) {
4392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    Printf("WARNING: DEADLOCK\n");
4402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    for (uptr i = 0; i < rep->mutexes.Size(); i++) {
4412d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("Goroutine %d lock mutex %d while holding mutex %d:\n",
4422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          999, rep->mutexes[i]->id,
4432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
4442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintStack(rep->stacks[2*i]);
4452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("\n");
4462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("Mutex %d was previously locked here:\n",
4472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines          rep->mutexes[(i+1) % rep->mutexes.Size()]->id);
4482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      PrintStack(rep->stacks[2*i + 1]);
4492d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines      Printf("\n");
4502d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    }
4512d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  }
452b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
453c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
454c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
455c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
456c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
4577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
458