tsan_report.cc revision a27512c4e115df4f260501a94b8d343f9ed955af
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"
16a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany#include "sanitizer_common/sanitizer_report_decorator.h"
177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
197ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
20a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryanyclass Decorator: private __sanitizer::AnsiColorDecorator {
21a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany public:
22a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
23a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Warning()    { return Red(); }
24a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndWarning() { return Default(); }
25a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Access()     { return Blue(); }
26a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndAccess()  { return Default(); }
27a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *ThreadDescription()    { return Cyan(); }
28a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndThreadDescription() { return Default(); }
29a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Location()   { return Green(); }
30a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndLocation() { return Default(); }
31a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Sleep()   { return Yellow(); }
32a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndSleep() { return Default(); }
33a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *Mutex()   { return Magenta(); }
34a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  const char *EndMutex() { return Default(); }
35a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany};
36a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany
377ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::ReportDesc()
387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    : stacks(MBlockReportStack)
397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mops(MBlockReportMop)
407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , locs(MBlockReportLoc)
417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mutexes(MBlockReportMutex)
42848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    , threads(MBlockReportThread)
434536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    , sleep()
444536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    , count() {
457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
47ad9da372f962495b3487685232d09390be841b1cDmitry VyukovReportMop::ReportMop()
48ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    : mset(MBlockReportMutex) {
49ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
50ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
517ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::~ReportDesc() {
52aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  // FIXME(dvyukov): it must be leaking a lot of memory.
537ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
55c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#ifndef TSAN_GO
56c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
57da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst int kThreadBufSize = 32;
58da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst char *thread_name(char *buf, int tid) {
59da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  if (tid == 0)
60da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    return "main thread";
61da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
62da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  return buf;
63da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov}
64da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov
652f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic const char *ReportTypeString(ReportType typ) {
667ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (typ == ReportTypeRace)
672f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "data race";
680dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov  if (typ == ReportTypeVptrRace)
690dc47b652dfbe0d61d153eded02bae9487a7b539Dmitry Vyukov    return "data race on vptr (ctor/dtor vs virtual call)";
702f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeUseAfterFree)
712f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "heap-use-after-free";
722f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeThreadLeak)
732f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "thread leak";
742f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeMutexDestroyLocked)
752f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "destroy of a locked mutex";
762f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeSignalUnsafe)
772f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal-unsafe call inside of a signal";
782f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeErrnoInSignal)
792f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal handler spoils errno";
802f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return "";
817ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
827ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
831da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintStack(const ReportStack *ent) {
84dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov  if (ent == 0) {
8595f50b126cebecc0165fbf6e4c8209c640836271Dmitry Vyukov    Printf("    [failed to restore the stack]\n\n");
86dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov    return;
87dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov  }
887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (int i = 0; ent; ent = ent->next, i++) {
89b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("    #%d %s %s:%d", i, ent->func, ent->file, ent->line);
907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->col)
91b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(":%d", ent->col);
927ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->module && ent->offset)
93b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    else
95b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(" (%p)\n", (void*)ent->pc);
967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
97b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
100ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovstatic void PrintMutexSet(Vector<ReportMopMutex> const& mset) {
101ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < mset.Size(); i++) {
102ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (i == 0)
103ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      Printf(" (mutexes:");
104ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    const ReportMopMutex m = mset[i];
105ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(" %s M%llu", m.write ? "write" : "read", m.id);
106ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(i == mset.Size() - 1 ? ")" : ",");
107ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
108ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
109ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
1100a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukovstatic const char *MopDesc(bool first, bool write, bool atomic) {
1110a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov  return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
1120a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous atomic write" : "Previous atomic read"))
1130a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (first ? (write ? "Write" : "Read")
1140a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous write" : "Previous read"));
1150a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov}
1160a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov
1177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMop(const ReportMop *mop, bool first) {
118a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
119da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
120a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Access());
121da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf("  %s of size %d at %p by %s",
1220a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov      MopDesc(first, mop->write, mop->atomic),
123da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      mop->size, (void*)mop->addr,
124da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      thread_name(thrbuf, mop->tid));
125ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  PrintMutexSet(mop->mset);
126ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf(":\n");
127a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndAccess());
1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(mop->stack);
1297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1307ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintLocation(const ReportLocation *loc) {
132a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
133c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  char thrbuf[kThreadBufSize];
134a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  bool print_stack = false;
135a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Location());
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (loc->type == ReportLocationGlobal) {
1375a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov    Printf("  Location is global '%s' of size %zu at %zx (%s+%p)\n\n",
1385a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov               loc->name, loc->size, loc->addr, loc->module, loc->offset);
1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationHeap) {
140da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    char thrbuf[kThreadBufSize];
141da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
142da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov        loc->size, loc->addr, thread_name(thrbuf, loc->tid));
143a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    print_stack = true;
1447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationStack) {
145fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
146fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  } else if (loc->type == ReportLocationTLS) {
147fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid));
148c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  } else if (loc->type == ReportLocationFD) {
149c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    Printf("  Location is file descriptor %d created by %s at:\n",
150c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov        loc->fd, thread_name(thrbuf, loc->tid));
151a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    print_stack = true;
1527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
153a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndLocation());
154a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  if (print_stack)
155a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    PrintStack(loc->stack);
1567ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1577ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1587ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMutex(const ReportMutex *rm) {
159a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
160ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (rm->destroyed) {
161a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.Mutex());
162ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf("  Mutex M%llu is already destroyed.\n\n", rm->id);
163a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.EndMutex());
164ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  } else {
165a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.Mutex());
166ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf("  Mutex M%llu created at:\n", rm->id);
167a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany    Printf("%s", d.EndMutex());
168ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    PrintStack(rm->stack);
169ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
1707ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1727ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintThread(const ReportThread *rt) {
173a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
1747ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->id == 0)  // Little sense in describing the main thread.
1757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
176a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.ThreadDescription());
177ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf("  Thread T%d", rt->id);
1782bbd8bec77c2fdb41c5f5b6cb0d83d22bc576650Alexey Samsonov  if (rt->name && rt->name[0] != '\0')
179b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf(" '%s'", rt->name);
180da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
181da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf(" (tid=%zu, %s) created by %s",
182da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    rt->pid, rt->running ? "running" : "finished",
183da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    thread_name(thrbuf, rt->parent_tid));
1847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->stack)
185da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf(" at:");
186b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
187a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndThreadDescription());
1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rt->stack);
1897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1907ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
191848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovstatic void PrintSleep(const ReportStack *s) {
192a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
193a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Sleep());
194b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("  As if synchronized via sleep:\n");
195a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndSleep());
196848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  PrintStack(s);
197848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
198848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
1992f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
2002f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mops.Size())
2012f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mops[0]->stack;
2022f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->stacks.Size())
2032f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->stacks[0];
2042f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mutexes.Size())
2052f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mutexes[0]->stack;
2062f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->threads.Size())
2072f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->threads[0]->stack;
2082f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return 0;
2092f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
2102f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
2115ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey SamsonovReportStack *SkipTsanInternalFrames(ReportStack *ent) {
2125ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey Samsonov  while (FrameIsInternal(ent) && ent->next)
2135ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey Samsonov    ent = ent->next;
2142f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return ent;
2152f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
2162f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
2177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid PrintReport(const ReportDesc *rep) {
218a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Decorator d;
219b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
2202f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  const char *rep_typ_str = ReportTypeString(rep->typ);
221a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.Warning());
2220b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
2230b694fcab9b2f33bdd6691cbea4e80a5c27191b1Peter Collingbourne         (int)internal_getpid());
224a27512c4e115df4f260501a94b8d343f9ed955afKostya Serebryany  Printf("%s", d.EndWarning());
2257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
226332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  for (uptr i = 0; i < rep->stacks.Size(); i++) {
227332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov    if (i)
228b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf("  and:\n");
2297ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintStack(rep->stacks[i]);
230332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  }
2317ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2327ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mops.Size(); i++)
2337ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMop(rep->mops[i], i == 0);
2347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
235848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (rep->sleep)
236848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    PrintSleep(rep->sleep);
237848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
2387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->locs.Size(); i++)
2397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintLocation(rep->locs[i]);
2407ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mutexes.Size(); i++)
2427ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMutex(rep->mutexes[i]);
2437ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2447ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->threads.Size(); i++)
2457ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintThread(rep->threads[i]);
2467ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2474536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov  if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
2484536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov    Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
2494536cb1fa7734133f404acb413589d7a6d314f4aDmitry Vyukov
2505ba301dfe9a39c02b3faeb0fa252473f1d6e742cAlexey Samsonov  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
2512f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
2522f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
253b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
2547ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2557ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2569d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov#else  // #ifndef TSAN_GO
2579d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov
2589d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukovconst int kMainThreadId = 1;
259c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
2600ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukovvoid PrintStack(const ReportStack *ent) {
2616c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov  if (ent == 0) {
2629d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("  [failed to restore the stack]\n");
2636c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov    return;
2646c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov  }
265c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (int i = 0; ent; ent = ent->next, i++) {
266b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("  %s()\n      %s:%d +0x%zx\n",
267853733e772b2885d93fdf994dedc4a1b5dc1369eDmitry Vyukov        ent->func, ent->file, ent->line, (void*)ent->offset);
268c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  }
269c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
270c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
271c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintMop(const ReportMop *mop, bool first) {
2729d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("\n");
2739d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("%s by ",
274c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      (first ? (mop->write ? "Write" : "Read")
2759d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov             : (mop->write ? "Previous write" : "Previous read")));
2769d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  if (mop->tid == kMainThreadId)
2779d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("main goroutine:\n");
2789d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  else
2799d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov    Printf("goroutine %d:\n", mop->tid);
280c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  PrintStack(mop->stack);
281c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
282c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
28343046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukovstatic void PrintThread(const ReportThread *rt) {
2849d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  if (rt->id == kMainThreadId)
28543046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    return;
2869d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("\n");
287b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("Goroutine %d (%s) created at:\n",
28843046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    rt->id, rt->running ? "running" : "finished");
28943046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  PrintStack(rt->stack);
29043046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov}
29143046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov
292c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovvoid PrintReport(const ReportDesc *rep) {
293b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
2949d95475f8adb1e08e45484feb03570ae2be2d0f3Dmitry Vyukov  Printf("WARNING: DATA RACE");
295c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (uptr i = 0; i < rep->mops.Size(); i++)
296c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov    PrintMop(rep->mops[i], i == 0);
29743046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  for (uptr i = 0; i < rep->threads.Size(); i++)
29843046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    PrintThread(rep->threads[i]);
299b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
300c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
301c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
302c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
303c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
3047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
305