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