tsan_report.cc revision 2f588f9d3417aa107ebbbd8830f97501023d3f40
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"
167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanynamespace __tsan {
187ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
197ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::ReportDesc()
207ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    : stacks(MBlockReportStack)
217ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mops(MBlockReportMop)
227ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , locs(MBlockReportLoc)
237ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    , mutexes(MBlockReportMutex)
24848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    , threads(MBlockReportThread)
25848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    , sleep() {
267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
28ad9da372f962495b3487685232d09390be841b1cDmitry VyukovReportMop::ReportMop()
29ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    : mset(MBlockReportMutex) {
30ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
31ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
327ac41484ea322e0ea5774df681660269f5dc321eKostya SerebryanyReportDesc::~ReportDesc() {
33aecf2e5756c6a0de7c146bef67a6e338c7017d55Dmitry Vyukov  // FIXME(dvyukov): it must be leaking a lot of memory.
347ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
36c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#ifndef TSAN_GO
37c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
38da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst int kThreadBufSize = 32;
39da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukovconst char *thread_name(char *buf, int tid) {
40da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  if (tid == 0)
41da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    return "main thread";
42da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
43da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  return buf;
44da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov}
45da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov
462f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic const char *ReportTypeString(ReportType typ) {
477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (typ == ReportTypeRace)
482f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "data race";
492f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeUseAfterFree)
502f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "heap-use-after-free";
512f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeThreadLeak)
522f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "thread leak";
532f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeMutexDestroyLocked)
542f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "destroy of a locked mutex";
552f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeSignalUnsafe)
562f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal-unsafe call inside of a signal";
572f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (typ == ReportTypeErrnoInSignal)
582f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return "signal handler spoils errno";
592f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return "";
607ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
617ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
621da1056127d1dbcacdd035eb4149257848f7c4dfDmitry Vyukovvoid PrintStack(const ReportStack *ent) {
63dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov  if (ent == 0) {
6495f50b126cebecc0165fbf6e4c8209c640836271Dmitry Vyukov    Printf("    [failed to restore the stack]\n\n");
65dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov    return;
66dc2a27ecd65079f1916f5ab53ec646f9a9e61349Dmitry Vyukov  }
677ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (int i = 0; ent; ent = ent->next, i++) {
68b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("    #%d %s %s:%d", i, ent->func, ent->file, ent->line);
697ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->col)
70b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(":%d", ent->col);
717ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    if (ent->module && ent->offset)
72b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
737ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    else
74b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf(" (%p)\n", (void*)ent->pc);
757ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
76b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
777ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
787ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
79ad9da372f962495b3487685232d09390be841b1cDmitry Vyukovstatic void PrintMutexSet(Vector<ReportMopMutex> const& mset) {
80ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  for (uptr i = 0; i < mset.Size(); i++) {
81ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    if (i == 0)
82ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov      Printf(" (mutexes:");
83ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    const ReportMopMutex m = mset[i];
84ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(" %s M%llu", m.write ? "write" : "read", m.id);
85ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf(i == mset.Size() - 1 ? ")" : ",");
86ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
87ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov}
88ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov
890a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukovstatic const char *MopDesc(bool first, bool write, bool atomic) {
900a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov  return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
910a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous atomic write" : "Previous atomic read"))
920a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (first ? (write ? "Write" : "Read")
930a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov                : (write ? "Previous write" : "Previous read"));
940a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov}
950a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov
967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMop(const ReportMop *mop, bool first) {
97da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
98da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf("  %s of size %d at %p by %s",
990a07b354fe95d50911c620b42fc031868ef15cc1Dmitry Vyukov      MopDesc(first, mop->write, mop->atomic),
100da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      mop->size, (void*)mop->addr,
101da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov      thread_name(thrbuf, mop->tid));
102ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  PrintMutexSet(mop->mset);
103ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf(":\n");
1047ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(mop->stack);
1057ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintLocation(const ReportLocation *loc) {
108c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  char thrbuf[kThreadBufSize];
1097ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (loc->type == ReportLocationGlobal) {
1105a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov    Printf("  Location is global '%s' of size %zu at %zx (%s+%p)\n\n",
1115a1f23310cc4a1debae8741653defe620518e612Dmitry Vyukov               loc->name, loc->size, loc->addr, loc->module, loc->offset);
1127ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationHeap) {
113da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    char thrbuf[kThreadBufSize];
114da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
115da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov        loc->size, loc->addr, thread_name(thrbuf, loc->tid));
1167ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintStack(loc->stack);
1177ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  } else if (loc->type == ReportLocationStack) {
118fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
119fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov  } else if (loc->type == ReportLocationTLS) {
120fb917e9069ea44f7103f50c658be84a8f66de56cDmitry Vyukov    Printf("  Location is TLS of %s.\n\n", thread_name(thrbuf, loc->tid));
121c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov  } else if (loc->type == ReportLocationFD) {
122c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    Printf("  Location is file descriptor %d created by %s at:\n",
123c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov        loc->fd, thread_name(thrbuf, loc->tid));
124c2234cd922bbd94e276e0bebb08004d63cbc5cf2Dmitry Vyukov    PrintStack(loc->stack);
1257ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  }
1267ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1277ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1287ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintMutex(const ReportMutex *rm) {
129ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  if (rm->destroyed) {
130ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf("  Mutex M%llu is already destroyed.\n\n", rm->id);
131ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  } else {
132ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    Printf("  Mutex M%llu created at:\n", rm->id);
133ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov    PrintStack(rm->stack);
134ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  }
1357ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1367ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1377ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanystatic void PrintThread(const ReportThread *rt) {
1387ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->id == 0)  // Little sense in describing the main thread.
1397ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    return;
140ad9da372f962495b3487685232d09390be841b1cDmitry Vyukov  Printf("  Thread T%d", rt->id);
1417ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->name)
142b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf(" '%s'", rt->name);
143da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  char thrbuf[kThreadBufSize];
144da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov  Printf(" (tid=%zu, %s) created by %s",
145da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    rt->pid, rt->running ? "running" : "finished",
146da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    thread_name(thrbuf, rt->parent_tid));
1477ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  if (rt->stack)
148da3503782901d30bd6e48885055b51b38cf5126cDmitry Vyukov    Printf(" at:");
149b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
1507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  PrintStack(rt->stack);
1517ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
1527ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
153848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukovstatic void PrintSleep(const ReportStack *s) {
154b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("  As if synchronized via sleep:\n");
155848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  PrintStack(s);
156848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov}
157848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
1582f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
1592f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mops.Size())
1602f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mops[0]->stack;
1612f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->stacks.Size())
1622f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->stacks[0];
1632f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->mutexes.Size())
1642f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->mutexes[0]->stack;
1652f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (rep->threads.Size())
1662f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return rep->threads[0]->stack;
1672f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return 0;
1682f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
1692f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
1702f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryanystatic ReportStack *SkipTsanInternalFrame(ReportStack *ent) {
1712f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (FrameIsInternal(ent) && ent->next)
1722f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    return ent->next;
1732f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  return ent;
1742f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany}
1752f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
1767ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryanyvoid PrintReport(const ReportDesc *rep) {
177b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
1782f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  const char *rep_typ_str = ReportTypeString(rep->typ);
1792f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, GetPid());
1807ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
181332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  for (uptr i = 0; i < rep->stacks.Size(); i++) {
182332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov    if (i)
183b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov      Printf("  and:\n");
1847ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintStack(rep->stacks[i]);
185332c62b52b3603be872b28bd3ea5e739aa28cd05Dmitry Vyukov  }
1867ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1877ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mops.Size(); i++)
1887ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMop(rep->mops[i], i == 0);
1897ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
190848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov  if (rep->sleep)
191848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov    PrintSleep(rep->sleep);
192848531192777acecf79747dc7c1ffeedf5c1da9fDmitry Vyukov
1937ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->locs.Size(); i++)
1947ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintLocation(rep->locs[i]);
1957ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1967ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->mutexes.Size(); i++)
1977ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintMutex(rep->mutexes[i]);
1987ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
1997ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany  for (uptr i = 0; i < rep->threads.Size(); i++)
2007ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany    PrintThread(rep->threads[i]);
2017ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
2022f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany  if (ReportStack *ent = SkipTsanInternalFrame(ChooseSummaryStack(rep)))
2032f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany    ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
2042f588f9d3417aa107ebbbd8830f97501023d3f40Kostya Serebryany
205b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
2067ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}
2077ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany
208c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#else
209c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
2100ab628c61594eb80612e5389d9c33da0e0d70c66Dmitry Vyukovvoid PrintStack(const ReportStack *ent) {
2116c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov  if (ent == 0) {
2126c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov    Printf("  [failed to restore the stack]\n\n");
2136c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov    return;
2146c0fbcae2f03eb78f82969bea61ccdbd2fb58e27Dmitry Vyukov  }
215c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (int i = 0; ent; ent = ent->next, i++) {
216b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov    Printf("  %s()\n      %s:%d +0x%zx\n",
217853733e772b2885d93fdf994dedc4a1b5dc1369eDmitry Vyukov        ent->func, ent->file, ent->line, (void*)ent->offset);
218c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  }
219b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("\n");
220c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
221c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
222c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovstatic void PrintMop(const ReportMop *mop, bool first) {
223b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("%s by goroutine %d:\n",
224c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      (first ? (mop->write ? "Write" : "Read")
225c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov             : (mop->write ? "Previous write" : "Previous read")),
226c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov      mop->tid);
227c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  PrintStack(mop->stack);
228c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
229c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
23043046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukovstatic void PrintThread(const ReportThread *rt) {
23143046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  if (rt->id == 0)  // Little sense in describing the main thread.
23243046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    return;
233b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("Goroutine %d (%s) created at:\n",
23443046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    rt->id, rt->running ? "running" : "finished");
23543046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  PrintStack(rt->stack);
23643046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov}
23743046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov
238c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukovvoid PrintReport(const ReportDesc *rep) {
239b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
240b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("WARNING: DATA RACE\n");
241c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov  for (uptr i = 0; i < rep->mops.Size(); i++)
242c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov    PrintMop(rep->mops[i], i == 0);
24343046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov  for (uptr i = 0; i < rep->threads.Size(); i++)
24443046e0b628df7eaaec266a4b6c9e9a998b02120Dmitry Vyukov    PrintThread(rep->threads[i]);
245b1fe3021eca0843e37878d224ee7f32e32f40d99Alexey Samsonov  Printf("==================\n");
246c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov}
247c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
248c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov#endif
249c510a2f264a22ff60333fc48e5fa12d41cefba3cDmitry Vyukov
2507ac41484ea322e0ea5774df681660269f5dc321eKostya Serebryany}  // namespace __tsan
251