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// 10249259Sdim// GCOV implements the interface to read and write coverage files that use 11249259Sdim// 'gcov' format. 12249259Sdim// 13249259Sdim//===----------------------------------------------------------------------===// 14249259Sdim 15249259Sdim#include "llvm/Support/GCOV.h" 16249259Sdim#include "llvm/ADT/OwningPtr.h" 17249259Sdim#include "llvm/ADT/STLExtras.h" 18249259Sdim#include "llvm/Support/MemoryObject.h" 19249259Sdim#include "llvm/Support/system_error.h" 20249259Sdimusing namespace llvm; 21249259Sdim 22249259Sdim//===----------------------------------------------------------------------===// 23249259Sdim// GCOVFile implementation. 24249259Sdim 25249259Sdim/// ~GCOVFile - Delete GCOVFile and its content. 26249259SdimGCOVFile::~GCOVFile() { 27249259Sdim DeleteContainerPointers(Functions); 28249259Sdim} 29249259Sdim 30249259Sdim/// isGCDAFile - Return true if Format identifies a .gcda file. 31249259Sdimstatic bool isGCDAFile(GCOV::GCOVFormat Format) { 32249259Sdim return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404; 33249259Sdim} 34249259Sdim 35249259Sdim/// isGCNOFile - Return true if Format identifies a .gcno file. 36249259Sdimstatic bool isGCNOFile(GCOV::GCOVFormat Format) { 37249259Sdim return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404; 38249259Sdim} 39249259Sdim 40249259Sdim/// read - Read GCOV buffer. 41249259Sdimbool GCOVFile::read(GCOVBuffer &Buffer) { 42249259Sdim GCOV::GCOVFormat Format = Buffer.readGCOVFormat(); 43249259Sdim if (Format == GCOV::InvalidGCOV) 44249259Sdim return false; 45249259Sdim 46249259Sdim unsigned i = 0; 47249259Sdim while (1) { 48249259Sdim GCOVFunction *GFun = NULL; 49249259Sdim if (isGCDAFile(Format)) { 50249259Sdim // Use existing function while reading .gcda file. 51249259Sdim assert(i < Functions.size() && ".gcda data does not match .gcno data"); 52249259Sdim GFun = Functions[i]; 53249259Sdim } else if (isGCNOFile(Format)){ 54249259Sdim GFun = new GCOVFunction(); 55249259Sdim Functions.push_back(GFun); 56249259Sdim } 57249259Sdim if (!GFun || !GFun->read(Buffer, Format)) 58249259Sdim break; 59249259Sdim ++i; 60249259Sdim } 61249259Sdim return true; 62249259Sdim} 63249259Sdim 64249259Sdim/// dump - Dump GCOVFile content on standard out for debugging purposes. 65249259Sdimvoid GCOVFile::dump() { 66249259Sdim for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(), 67249259Sdim E = Functions.end(); I != E; ++I) 68249259Sdim (*I)->dump(); 69249259Sdim} 70249259Sdim 71249259Sdim/// collectLineCounts - Collect line counts. This must be used after 72249259Sdim/// reading .gcno and .gcda files. 73249259Sdimvoid GCOVFile::collectLineCounts(FileInfo &FI) { 74249259Sdim for (SmallVector<GCOVFunction *, 16>::iterator I = Functions.begin(), 75249259Sdim E = Functions.end(); I != E; ++I) 76249259Sdim (*I)->collectLineCounts(FI); 77249259Sdim FI.print(); 78249259Sdim} 79249259Sdim 80249259Sdim//===----------------------------------------------------------------------===// 81249259Sdim// GCOVFunction implementation. 82249259Sdim 83249259Sdim/// ~GCOVFunction - Delete GCOVFunction and its content. 84249259SdimGCOVFunction::~GCOVFunction() { 85249259Sdim DeleteContainerPointers(Blocks); 86249259Sdim} 87249259Sdim 88249259Sdim/// read - Read a aunction from the buffer. Return false if buffer cursor 89249259Sdim/// does not point to a function tag. 90249259Sdimbool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) { 91249259Sdim if (!Buff.readFunctionTag()) 92249259Sdim return false; 93249259Sdim 94249259Sdim Buff.readInt(); // Function header length 95249259Sdim Ident = Buff.readInt(); 96249259Sdim Buff.readInt(); // Checksum #1 97249259Sdim if (Format != GCOV::GCNO_402) 98249259Sdim Buff.readInt(); // Checksum #2 99249259Sdim 100249259Sdim Name = Buff.readString(); 101249259Sdim if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404) 102249259Sdim Filename = Buff.readString(); 103249259Sdim 104249259Sdim if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) { 105249259Sdim Buff.readArcTag(); 106249259Sdim uint32_t Count = Buff.readInt() / 2; 107249259Sdim for (unsigned i = 0, e = Count; i != e; ++i) { 108249259Sdim Blocks[i]->addCount(Buff.readInt64()); 109249259Sdim } 110249259Sdim return true; 111249259Sdim } 112249259Sdim 113249259Sdim LineNumber = Buff.readInt(); 114249259Sdim 115249259Sdim // read blocks. 116249259Sdim bool BlockTagFound = Buff.readBlockTag(); 117249259Sdim (void)BlockTagFound; 118249259Sdim assert(BlockTagFound && "Block Tag not found!"); 119249259Sdim uint32_t BlockCount = Buff.readInt(); 120249259Sdim for (int i = 0, e = BlockCount; i != e; ++i) { 121249259Sdim Buff.readInt(); // Block flags; 122249259Sdim Blocks.push_back(new GCOVBlock(i)); 123249259Sdim } 124249259Sdim 125249259Sdim // read edges. 126249259Sdim while (Buff.readEdgeTag()) { 127249259Sdim uint32_t EdgeCount = (Buff.readInt() - 1) / 2; 128249259Sdim uint32_t BlockNo = Buff.readInt(); 129249259Sdim assert(BlockNo < BlockCount && "Unexpected Block number!"); 130249259Sdim for (int i = 0, e = EdgeCount; i != e; ++i) { 131249259Sdim Blocks[BlockNo]->addEdge(Buff.readInt()); 132249259Sdim Buff.readInt(); // Edge flag 133249259Sdim } 134249259Sdim } 135249259Sdim 136249259Sdim // read line table. 137249259Sdim while (Buff.readLineTag()) { 138249259Sdim uint32_t LineTableLength = Buff.readInt(); 139249259Sdim uint32_t Size = Buff.getCursor() + LineTableLength*4; 140249259Sdim uint32_t BlockNo = Buff.readInt(); 141249259Sdim assert(BlockNo < BlockCount && "Unexpected Block number!"); 142249259Sdim GCOVBlock *Block = Blocks[BlockNo]; 143249259Sdim Buff.readInt(); // flag 144249259Sdim while (Buff.getCursor() != (Size - 4)) { 145249259Sdim StringRef Filename = Buff.readString(); 146249259Sdim if (Buff.getCursor() == (Size - 4)) break; 147249259Sdim while (uint32_t L = Buff.readInt()) 148249259Sdim Block->addLine(Filename, L); 149249259Sdim } 150249259Sdim Buff.readInt(); // flag 151249259Sdim } 152249259Sdim return true; 153249259Sdim} 154249259Sdim 155249259Sdim/// dump - Dump GCOVFunction content on standard out for debugging purposes. 156249259Sdimvoid GCOVFunction::dump() { 157249259Sdim outs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n"; 158249259Sdim for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(), 159249259Sdim E = Blocks.end(); I != E; ++I) 160249259Sdim (*I)->dump(); 161249259Sdim} 162249259Sdim 163249259Sdim/// collectLineCounts - Collect line counts. This must be used after 164249259Sdim/// reading .gcno and .gcda files. 165249259Sdimvoid GCOVFunction::collectLineCounts(FileInfo &FI) { 166249259Sdim for (SmallVector<GCOVBlock *, 16>::iterator I = Blocks.begin(), 167249259Sdim E = Blocks.end(); I != E; ++I) 168249259Sdim (*I)->collectLineCounts(FI); 169249259Sdim} 170249259Sdim 171249259Sdim//===----------------------------------------------------------------------===// 172249259Sdim// GCOVBlock implementation. 173249259Sdim 174249259Sdim/// ~GCOVBlock - Delete GCOVBlock and its content. 175249259SdimGCOVBlock::~GCOVBlock() { 176249259Sdim Edges.clear(); 177249259Sdim DeleteContainerSeconds(Lines); 178249259Sdim} 179249259Sdim 180249259Sdimvoid GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) { 181249259Sdim GCOVLines *&LinesForFile = Lines[Filename]; 182249259Sdim if (!LinesForFile) 183249259Sdim LinesForFile = new GCOVLines(); 184249259Sdim LinesForFile->add(LineNo); 185249259Sdim} 186249259Sdim 187249259Sdim/// collectLineCounts - Collect line counts. This must be used after 188249259Sdim/// reading .gcno and .gcda files. 189249259Sdimvoid GCOVBlock::collectLineCounts(FileInfo &FI) { 190249259Sdim for (StringMap<GCOVLines *>::iterator I = Lines.begin(), 191249259Sdim E = Lines.end(); I != E; ++I) 192249259Sdim I->second->collectLineCounts(FI, I->first(), Counter); 193249259Sdim} 194249259Sdim 195249259Sdim/// dump - Dump GCOVBlock content on standard out for debugging purposes. 196249259Sdimvoid GCOVBlock::dump() { 197249259Sdim outs() << "Block : " << Number << " Counter : " << Counter << "\n"; 198249259Sdim if (!Edges.empty()) { 199249259Sdim outs() << "\tEdges : "; 200249259Sdim for (SmallVector<uint32_t, 16>::iterator I = Edges.begin(), E = Edges.end(); 201249259Sdim I != E; ++I) 202249259Sdim outs() << (*I) << ","; 203249259Sdim outs() << "\n"; 204249259Sdim } 205249259Sdim if (!Lines.empty()) { 206249259Sdim outs() << "\tLines : "; 207249259Sdim for (StringMap<GCOVLines *>::iterator LI = Lines.begin(), 208249259Sdim LE = Lines.end(); LI != LE; ++LI) { 209249259Sdim outs() << LI->first() << " -> "; 210249259Sdim LI->second->dump(); 211249259Sdim outs() << "\n"; 212249259Sdim } 213249259Sdim } 214249259Sdim} 215249259Sdim 216249259Sdim//===----------------------------------------------------------------------===// 217249259Sdim// GCOVLines implementation. 218249259Sdim 219249259Sdim/// collectLineCounts - Collect line counts. This must be used after 220249259Sdim/// reading .gcno and .gcda files. 221249259Sdimvoid GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename, 222249259Sdim uint32_t Count) { 223249259Sdim for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(), 224249259Sdim E = Lines.end(); I != E; ++I) 225249259Sdim FI.addLineCount(Filename, *I, Count); 226249259Sdim} 227249259Sdim 228249259Sdim/// dump - Dump GCOVLines content on standard out for debugging purposes. 229249259Sdimvoid GCOVLines::dump() { 230249259Sdim for (SmallVector<uint32_t, 16>::iterator I = Lines.begin(), 231249259Sdim E = Lines.end(); I != E; ++I) 232249259Sdim outs() << (*I) << ","; 233249259Sdim} 234249259Sdim 235249259Sdim//===----------------------------------------------------------------------===// 236249259Sdim// FileInfo implementation. 237249259Sdim 238249259Sdim/// addLineCount - Add line count for the given line number in a file. 239249259Sdimvoid FileInfo::addLineCount(StringRef Filename, uint32_t Line, uint32_t Count) { 240249259Sdim if (LineInfo.find(Filename) == LineInfo.end()) { 241249259Sdim OwningPtr<MemoryBuffer> Buff; 242249259Sdim if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { 243249259Sdim errs() << Filename << ": " << ec.message() << "\n"; 244249259Sdim return; 245249259Sdim } 246249259Sdim StringRef AllLines = Buff.take()->getBuffer(); 247249259Sdim LineCounts L(AllLines.count('\n')+2); 248249259Sdim L[Line-1] = Count; 249249259Sdim LineInfo[Filename] = L; 250249259Sdim return; 251249259Sdim } 252249259Sdim LineCounts &L = LineInfo[Filename]; 253249259Sdim L[Line-1] = Count; 254249259Sdim} 255249259Sdim 256249259Sdim/// print - Print source files with collected line count information. 257249259Sdimvoid FileInfo::print() { 258249259Sdim for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end(); 259249259Sdim I != E; ++I) { 260249259Sdim StringRef Filename = I->first(); 261249259Sdim outs() << Filename << "\n"; 262249259Sdim LineCounts &L = LineInfo[Filename]; 263249259Sdim OwningPtr<MemoryBuffer> Buff; 264249259Sdim if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { 265249259Sdim errs() << Filename << ": " << ec.message() << "\n"; 266249259Sdim return; 267249259Sdim } 268249259Sdim StringRef AllLines = Buff.take()->getBuffer(); 269249259Sdim for (unsigned i = 0, e = L.size(); i != e; ++i) { 270249259Sdim if (L[i]) 271249259Sdim outs() << L[i] << ":\t"; 272249259Sdim else 273249259Sdim outs() << " :\t"; 274249259Sdim std::pair<StringRef, StringRef> P = AllLines.split('\n'); 275249259Sdim if (AllLines != P.first) 276249259Sdim outs() << P.first; 277249259Sdim outs() << "\n"; 278249259Sdim AllLines = P.second; 279249259Sdim } 280249259Sdim } 281249259Sdim} 282249259Sdim 283249259Sdim 284