1249259Sdim//===- GCOVr.cpp - LLVM coverage tool -------------------------------------===// 2249259Sdim// 3249259Sdim// The LLVM Compiler Infrastructure 4249259Sdim// 5249259Sdim// This file is distributed under the University of Illinois Open Source 6249259Sdim// License. See LICENSE.TXT for details. 7249259Sdim// 8249259Sdim//===----------------------------------------------------------------------===// 9249259Sdim// 10263508Sdim// GCOV implements the interface to read and write coverage files that use 11249259Sdim// 'gcov' format. 12249259Sdim// 13249259Sdim//===----------------------------------------------------------------------===// 14249259Sdim 15263508Sdim#include "llvm/Support/Debug.h" 16249259Sdim#include "llvm/Support/GCOV.h" 17249259Sdim#include "llvm/ADT/OwningPtr.h" 18249259Sdim#include "llvm/ADT/STLExtras.h" 19263508Sdim#include "llvm/Support/Format.h" 20249259Sdim#include "llvm/Support/MemoryObject.h" 21249259Sdim#include "llvm/Support/system_error.h" 22249259Sdimusing namespace llvm; 23249259Sdim 24249259Sdim//===----------------------------------------------------------------------===// 25249259Sdim// GCOVFile implementation. 26249259Sdim 27249259Sdim/// ~GCOVFile - Delete GCOVFile and its content. 28249259SdimGCOVFile::~GCOVFile() { 29249259Sdim DeleteContainerPointers(Functions); 30249259Sdim} 31249259Sdim 32249259Sdim/// isGCDAFile - Return true if Format identifies a .gcda file. 33249259Sdimstatic bool isGCDAFile(GCOV::GCOVFormat Format) { 34249259Sdim return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404; 35249259Sdim} 36249259Sdim 37249259Sdim/// isGCNOFile - Return true if Format identifies a .gcno file. 38249259Sdimstatic bool isGCNOFile(GCOV::GCOVFormat Format) { 39249259Sdim return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404; 40249259Sdim} 41249259Sdim 42249259Sdim/// read - Read GCOV buffer. 43249259Sdimbool GCOVFile::read(GCOVBuffer &Buffer) { 44249259Sdim GCOV::GCOVFormat Format = Buffer.readGCOVFormat(); 45249259Sdim if (Format == GCOV::InvalidGCOV) 46249259Sdim return false; 47249259Sdim 48263508Sdim if (isGCNOFile(Format)) { 49263508Sdim while (true) { 50263508Sdim if (!Buffer.readFunctionTag()) break; 51263508Sdim GCOVFunction *GFun = new GCOVFunction(); 52263508Sdim if (!GFun->read(Buffer, Format)) 53263508Sdim return false; 54249259Sdim Functions.push_back(GFun); 55249259Sdim } 56249259Sdim } 57263508Sdim else if (isGCDAFile(Format)) { 58263508Sdim for (size_t i = 0, e = Functions.size(); i < e; ++i) { 59263508Sdim if (!Buffer.readFunctionTag()) { 60263508Sdim errs() << "Unexpected number of functions.\n"; 61263508Sdim return false; 62263508Sdim } 63263508Sdim if (!Functions[i]->read(Buffer, Format)) 64263508Sdim return false; 65263508Sdim } 66263508Sdim if (Buffer.readObjectTag()) { 67263508Sdim uint32_t Length; 68263508Sdim uint32_t Dummy; 69263508Sdim if (!Buffer.readInt(Length)) return false; 70263508Sdim if (!Buffer.readInt(Dummy)) return false; // checksum 71263508Sdim if (!Buffer.readInt(Dummy)) return false; // num 72263508Sdim if (!Buffer.readInt(RunCount)) return false;; 73263508Sdim Buffer.advanceCursor(Length-3); 74263508Sdim } 75263508Sdim while (Buffer.readProgramTag()) { 76263508Sdim uint32_t Length; 77263508Sdim if (!Buffer.readInt(Length)) return false; 78263508Sdim Buffer.advanceCursor(Length); 79263508Sdim ++ProgramCount; 80263508Sdim } 81263508Sdim } 82263508Sdim 83249259Sdim return true; 84249259Sdim} 85249259Sdim 86263508Sdim/// dump - Dump GCOVFile content to dbgs() for debugging purposes. 87249259Sdimvoid GCOVFile::dump() { 88263508Sdim for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(), 89249259Sdim E = Functions.end(); I != E; ++I) 90249259Sdim (*I)->dump(); 91249259Sdim} 92249259Sdim 93249259Sdim/// collectLineCounts - Collect line counts. This must be used after 94249259Sdim/// reading .gcno and .gcda files. 95249259Sdimvoid GCOVFile::collectLineCounts(FileInfo &FI) { 96263508Sdim for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(), 97263508Sdim E = Functions.end(); I != E; ++I) 98249259Sdim (*I)->collectLineCounts(FI); 99263508Sdim FI.setRunCount(RunCount); 100263508Sdim FI.setProgramCount(ProgramCount); 101249259Sdim} 102249259Sdim 103249259Sdim//===----------------------------------------------------------------------===// 104249259Sdim// GCOVFunction implementation. 105249259Sdim 106249259Sdim/// ~GCOVFunction - Delete GCOVFunction and its content. 107249259SdimGCOVFunction::~GCOVFunction() { 108249259Sdim DeleteContainerPointers(Blocks); 109249259Sdim} 110249259Sdim 111263508Sdim/// read - Read a function from the buffer. Return false if buffer cursor 112249259Sdim/// does not point to a function tag. 113249259Sdimbool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) { 114263508Sdim uint32_t Dummy; 115263508Sdim if (!Buff.readInt(Dummy)) return false; // Function header length 116263508Sdim if (!Buff.readInt(Ident)) return false; 117263508Sdim if (!Buff.readInt(Dummy)) return false; // Checksum #1 118263508Sdim if (Format != GCOV::GCNO_402 && Format != GCOV::GCDA_402) 119263508Sdim if (!Buff.readInt(Dummy)) return false; // Checksum #2 120249259Sdim 121263508Sdim if (!Buff.readString(Name)) return false; 122249259Sdim 123249259Sdim if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404) 124263508Sdim if (!Buff.readString(Filename)) return false; 125249259Sdim 126249259Sdim if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) { 127263508Sdim if (!Buff.readArcTag()) { 128263508Sdim errs() << "Arc tag not found.\n"; 129263508Sdim return false; 130249259Sdim } 131263508Sdim uint32_t Count; 132263508Sdim if (!Buff.readInt(Count)) return false; 133263508Sdim Count /= 2; 134263508Sdim 135263508Sdim // This for loop adds the counts for each block. A second nested loop is 136263508Sdim // required to combine the edge counts that are contained in the GCDA file. 137263508Sdim for (uint32_t Line = 0; Count > 0; ++Line) { 138263508Sdim if (Line >= Blocks.size()) { 139263508Sdim errs() << "Unexpected number of edges.\n"; 140263508Sdim return false; 141263508Sdim } 142263508Sdim GCOVBlock &Block = *Blocks[Line]; 143263508Sdim for (size_t Edge = 0, End = Block.getNumEdges(); Edge < End; ++Edge) { 144263508Sdim if (Count == 0) { 145263508Sdim errs() << "Unexpected number of edges.\n"; 146263508Sdim return false; 147263508Sdim } 148263508Sdim uint64_t ArcCount; 149263508Sdim if (!Buff.readInt64(ArcCount)) return false; 150263508Sdim Block.addCount(ArcCount); 151263508Sdim --Count; 152263508Sdim } 153263508Sdim } 154249259Sdim return true; 155249259Sdim } 156249259Sdim 157263508Sdim if (!Buff.readInt(LineNumber)) return false; 158249259Sdim 159249259Sdim // read blocks. 160263508Sdim if (!Buff.readBlockTag()) { 161263508Sdim errs() << "Block tag not found.\n"; 162263508Sdim return false; 163249259Sdim } 164263508Sdim uint32_t BlockCount; 165263508Sdim if (!Buff.readInt(BlockCount)) return false; 166263508Sdim for (uint32_t i = 0, e = BlockCount; i != e; ++i) { 167263508Sdim if (!Buff.readInt(Dummy)) return false; // Block flags; 168263508Sdim Blocks.push_back(new GCOVBlock(*this, i)); 169263508Sdim } 170249259Sdim 171249259Sdim // read edges. 172249259Sdim while (Buff.readEdgeTag()) { 173263508Sdim uint32_t EdgeCount; 174263508Sdim if (!Buff.readInt(EdgeCount)) return false; 175263508Sdim EdgeCount = (EdgeCount - 1) / 2; 176263508Sdim uint32_t BlockNo; 177263508Sdim if (!Buff.readInt(BlockNo)) return false; 178263508Sdim if (BlockNo >= BlockCount) { 179263508Sdim errs() << "Unexpected block number.\n"; 180263508Sdim return false; 181249259Sdim } 182263508Sdim for (uint32_t i = 0, e = EdgeCount; i != e; ++i) { 183263508Sdim uint32_t Dst; 184263508Sdim if (!Buff.readInt(Dst)) return false; 185263508Sdim Blocks[BlockNo]->addEdge(Dst); 186263508Sdim if (!Buff.readInt(Dummy)) return false; // Edge flag 187263508Sdim } 188249259Sdim } 189249259Sdim 190249259Sdim // read line table. 191249259Sdim while (Buff.readLineTag()) { 192263508Sdim uint32_t LineTableLength; 193263508Sdim if (!Buff.readInt(LineTableLength)) return false; 194263508Sdim uint32_t EndPos = Buff.getCursor() + LineTableLength*4; 195263508Sdim uint32_t BlockNo; 196263508Sdim if (!Buff.readInt(BlockNo)) return false; 197263508Sdim if (BlockNo >= BlockCount) { 198263508Sdim errs() << "Unexpected block number.\n"; 199263508Sdim return false; 200263508Sdim } 201249259Sdim GCOVBlock *Block = Blocks[BlockNo]; 202263508Sdim if (!Buff.readInt(Dummy)) return false; // flag 203263508Sdim while (Buff.getCursor() != (EndPos - 4)) { 204263508Sdim StringRef F; 205263508Sdim if (!Buff.readString(F)) return false; 206263508Sdim if (F != Filename) { 207263508Sdim errs() << "Multiple sources for a single basic block.\n"; 208263508Sdim return false; 209263508Sdim } 210263508Sdim if (Buff.getCursor() == (EndPos - 4)) break; 211263508Sdim while (true) { 212263508Sdim uint32_t Line; 213263508Sdim if (!Buff.readInt(Line)) return false; 214263508Sdim if (!Line) break; 215263508Sdim Block->addLine(Line); 216263508Sdim } 217249259Sdim } 218263508Sdim if (!Buff.readInt(Dummy)) return false; // flag 219249259Sdim } 220249259Sdim return true; 221249259Sdim} 222249259Sdim 223263508Sdim/// dump - Dump GCOVFunction content to dbgs() for debugging purposes. 224249259Sdimvoid GCOVFunction::dump() { 225263508Sdim dbgs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n"; 226263508Sdim for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 227249259Sdim E = Blocks.end(); I != E; ++I) 228249259Sdim (*I)->dump(); 229249259Sdim} 230249259Sdim 231249259Sdim/// collectLineCounts - Collect line counts. This must be used after 232249259Sdim/// reading .gcno and .gcda files. 233249259Sdimvoid GCOVFunction::collectLineCounts(FileInfo &FI) { 234263508Sdim for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 235249259Sdim E = Blocks.end(); I != E; ++I) 236249259Sdim (*I)->collectLineCounts(FI); 237249259Sdim} 238249259Sdim 239249259Sdim//===----------------------------------------------------------------------===// 240249259Sdim// GCOVBlock implementation. 241249259Sdim 242249259Sdim/// ~GCOVBlock - Delete GCOVBlock and its content. 243249259SdimGCOVBlock::~GCOVBlock() { 244249259Sdim Edges.clear(); 245263508Sdim Lines.clear(); 246249259Sdim} 247249259Sdim 248249259Sdim/// collectLineCounts - Collect line counts. This must be used after 249249259Sdim/// reading .gcno and .gcda files. 250249259Sdimvoid GCOVBlock::collectLineCounts(FileInfo &FI) { 251263508Sdim for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 252249259Sdim E = Lines.end(); I != E; ++I) 253263508Sdim FI.addLineCount(Parent.getFilename(), *I, Counter); 254249259Sdim} 255249259Sdim 256263508Sdim/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. 257249259Sdimvoid GCOVBlock::dump() { 258263508Sdim dbgs() << "Block : " << Number << " Counter : " << Counter << "\n"; 259249259Sdim if (!Edges.empty()) { 260263508Sdim dbgs() << "\tEdges : "; 261263508Sdim for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end(); 262249259Sdim I != E; ++I) 263263508Sdim dbgs() << (*I) << ","; 264263508Sdim dbgs() << "\n"; 265249259Sdim } 266249259Sdim if (!Lines.empty()) { 267263508Sdim dbgs() << "\tLines : "; 268263508Sdim for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 269263508Sdim E = Lines.end(); I != E; ++I) 270263508Sdim dbgs() << (*I) << ","; 271263508Sdim dbgs() << "\n"; 272249259Sdim } 273249259Sdim} 274249259Sdim 275249259Sdim//===----------------------------------------------------------------------===// 276249259Sdim// FileInfo implementation. 277249259Sdim 278249259Sdim/// print - Print source files with collected line count information. 279263508Sdimvoid FileInfo::print(raw_fd_ostream &OS, StringRef gcnoFile, 280263508Sdim StringRef gcdaFile) { 281249259Sdim for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end(); 282249259Sdim I != E; ++I) { 283249259Sdim StringRef Filename = I->first(); 284263508Sdim OS << " -: 0:Source:" << Filename << "\n"; 285263508Sdim OS << " -: 0:Graph:" << gcnoFile << "\n"; 286263508Sdim OS << " -: 0:Data:" << gcdaFile << "\n"; 287263508Sdim OS << " -: 0:Runs:" << RunCount << "\n"; 288263508Sdim OS << " -: 0:Programs:" << ProgramCount << "\n"; 289249259Sdim LineCounts &L = LineInfo[Filename]; 290249259Sdim OwningPtr<MemoryBuffer> Buff; 291249259Sdim if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { 292249259Sdim errs() << Filename << ": " << ec.message() << "\n"; 293249259Sdim return; 294249259Sdim } 295263508Sdim StringRef AllLines = Buff->getBuffer(); 296263508Sdim uint32_t i = 0; 297263508Sdim while (!AllLines.empty()) { 298263508Sdim if (L.find(i) != L.end()) { 299263508Sdim if (L[i] == 0) 300263508Sdim OS << " #####:"; 301263508Sdim else 302263508Sdim OS << format("%9" PRIu64 ":", L[i]); 303263508Sdim } else { 304263508Sdim OS << " -:"; 305263508Sdim } 306249259Sdim std::pair<StringRef, StringRef> P = AllLines.split('\n'); 307249259Sdim if (AllLines != P.first) 308263508Sdim OS << format("%5u:", i+1) << P.first; 309263508Sdim OS << "\n"; 310249259Sdim AllLines = P.second; 311263508Sdim ++i; 312249259Sdim } 313249259Sdim } 314249259Sdim} 315