GCOV.cpp revision 131a764e0e7abc90b322fd568e042d3c5a0633af
1//===- GCOVr.cpp - LLVM coverage tool -------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// GCOV implements the interface to read and write coverage files that use 11// 'gcov' format. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/Support/Debug.h" 16#include "llvm/Support/GCOV.h" 17#include "llvm/ADT/OwningPtr.h" 18#include "llvm/ADT/STLExtras.h" 19#include "llvm/Support/Format.h" 20#include "llvm/Support/MemoryObject.h" 21#include "llvm/Support/system_error.h" 22using namespace llvm; 23 24//===----------------------------------------------------------------------===// 25// GCOVFile implementation. 26 27/// ~GCOVFile - Delete GCOVFile and its content. 28GCOVFile::~GCOVFile() { 29 DeleteContainerPointers(Functions); 30} 31 32/// isGCDAFile - Return true if Format identifies a .gcda file. 33static bool isGCDAFile(GCOV::GCOVFormat Format) { 34 return Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404; 35} 36 37/// isGCNOFile - Return true if Format identifies a .gcno file. 38static bool isGCNOFile(GCOV::GCOVFormat Format) { 39 return Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404; 40} 41 42/// read - Read GCOV buffer. 43bool GCOVFile::read(GCOVBuffer &Buffer) { 44 GCOV::GCOVFormat Format = Buffer.readGCOVFormat(); 45 if (Format == GCOV::InvalidGCOV) 46 return false; 47 48 if (isGCNOFile(Format)) { 49 while (true) { 50 if (!Buffer.readFunctionTag()) break; 51 GCOVFunction *GFun = new GCOVFunction(); 52 if (!GFun->read(Buffer, Format)) 53 return false; 54 Functions.push_back(GFun); 55 } 56 } 57 else if (isGCDAFile(Format)) { 58 for (size_t i = 0, e = Functions.size(); i < e; ++i) { 59 if (!Buffer.readFunctionTag()) { 60 errs() << "Unexpected number of functions.\n"; 61 return false; 62 } 63 if (!Functions[i]->read(Buffer, Format)) 64 return false; 65 } 66 if (Buffer.readObjectTag()) { 67 uint32_t Length; 68 uint32_t Dummy; 69 if (!Buffer.readInt(Length)) return false; 70 if (!Buffer.readInt(Dummy)) return false; // checksum 71 if (!Buffer.readInt(Dummy)) return false; // num 72 if (!Buffer.readInt(RunCount)) return false;; 73 Buffer.advanceCursor(Length-3); 74 } 75 while (Buffer.readProgramTag()) { 76 uint32_t Length; 77 if (!Buffer.readInt(Length)) return false; 78 Buffer.advanceCursor(Length); 79 ++ProgramCount; 80 } 81 } 82 83 return true; 84} 85 86/// dump - Dump GCOVFile content to dbgs() for debugging purposes. 87void GCOVFile::dump() { 88 for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(), 89 E = Functions.end(); I != E; ++I) 90 (*I)->dump(); 91} 92 93/// collectLineCounts - Collect line counts. This must be used after 94/// reading .gcno and .gcda files. 95void GCOVFile::collectLineCounts(FileInfo &FI) { 96 for (SmallVectorImpl<GCOVFunction *>::iterator I = Functions.begin(), 97 E = Functions.end(); I != E; ++I) 98 (*I)->collectLineCounts(FI); 99 FI.setRunCount(RunCount); 100 FI.setProgramCount(ProgramCount); 101} 102 103//===----------------------------------------------------------------------===// 104// GCOVFunction implementation. 105 106/// ~GCOVFunction - Delete GCOVFunction and its content. 107GCOVFunction::~GCOVFunction() { 108 DeleteContainerPointers(Blocks); 109} 110 111/// read - Read a function from the buffer. Return false if buffer cursor 112/// does not point to a function tag. 113bool GCOVFunction::read(GCOVBuffer &Buff, GCOV::GCOVFormat Format) { 114 uint32_t Dummy; 115 if (!Buff.readInt(Dummy)) return false; // Function header length 116 if (!Buff.readInt(Ident)) return false; 117 if (!Buff.readInt(Dummy)) return false; // Checksum #1 118 if (Format != GCOV::GCNO_402 && Format != GCOV::GCDA_402) 119 if (!Buff.readInt(Dummy)) return false; // Checksum #2 120 121 if (!Buff.readString(Name)) return false; 122 123 if (Format == GCOV::GCNO_402 || Format == GCOV::GCNO_404) 124 if (!Buff.readString(Filename)) return false; 125 126 if (Format == GCOV::GCDA_402 || Format == GCOV::GCDA_404) { 127 if (!Buff.readArcTag()) { 128 errs() << "Arc tag not found.\n"; 129 return false; 130 } 131 uint32_t Count; 132 if (!Buff.readInt(Count)) return false; 133 Count /= 2; 134 135 // This for loop adds the counts for each block. A second nested loop is 136 // required to combine the edge counts that are contained in the GCDA file. 137 for (uint32_t Line = 0; Count > 0; ++Line) { 138 GCOVBlock &Block = *Blocks[Line]; 139 for (size_t Edge = 0, End = Block.getNumEdges(); Edge < End; ++Edge) { 140 if (Count == 0) { 141 errs() << "Unexpected number of edges.\n"; 142 return false; 143 } 144 uint64_t ArcCount; 145 if (!Buff.readInt64(ArcCount)) return false; 146 Block.addCount(ArcCount); 147 --Count; 148 } 149 } 150 return true; 151 } 152 153 if (!Buff.readInt(LineNumber)) return false; 154 155 // read blocks. 156 if (!Buff.readBlockTag()) { 157 errs() << "Block tag not found.\n"; 158 return false; 159 } 160 uint32_t BlockCount; 161 if (!Buff.readInt(BlockCount)) return false; 162 for (uint32_t i = 0, e = BlockCount; i != e; ++i) { 163 if (!Buff.readInt(Dummy)) return false; // Block flags; 164 Blocks.push_back(new GCOVBlock(*this, i)); 165 } 166 167 // read edges. 168 while (Buff.readEdgeTag()) { 169 uint32_t EdgeCount; 170 if (!Buff.readInt(EdgeCount)) return false; 171 EdgeCount = (EdgeCount - 1) / 2; 172 uint32_t BlockNo; 173 if (!Buff.readInt(BlockNo)) return false; 174 if (BlockNo >= BlockCount) { 175 errs() << "Unexpected block number.\n"; 176 return false; 177 } 178 for (uint32_t i = 0, e = EdgeCount; i != e; ++i) { 179 uint32_t Dst; 180 if (!Buff.readInt(Dst)) return false; 181 Blocks[BlockNo]->addEdge(Dst); 182 if (!Buff.readInt(Dummy)) return false; // Edge flag 183 } 184 } 185 186 // read line table. 187 while (Buff.readLineTag()) { 188 uint32_t LineTableLength; 189 if (!Buff.readInt(LineTableLength)) return false; 190 uint32_t EndPos = Buff.getCursor() + LineTableLength*4; 191 uint32_t BlockNo; 192 if (!Buff.readInt(BlockNo)) return false; 193 if (BlockNo >= BlockCount) { 194 errs() << "Unexpected block number.\n"; 195 return false; 196 } 197 GCOVBlock *Block = Blocks[BlockNo]; 198 if (!Buff.readInt(Dummy)) return false; // flag 199 while (Buff.getCursor() != (EndPos - 4)) { 200 StringRef F; 201 if (!Buff.readString(F)) return false; 202 if (F != Filename) { 203 errs() << "Multiple sources for a single basic block.\n"; 204 return false; 205 } 206 if (Buff.getCursor() == (EndPos - 4)) break; 207 while (true) { 208 uint32_t Line; 209 if (!Buff.readInt(Line)) return false; 210 if (!Line) break; 211 Block->addLine(Line); 212 } 213 } 214 if (!Buff.readInt(Dummy)) return false; // flag 215 } 216 return true; 217} 218 219/// dump - Dump GCOVFunction content to dbgs() for debugging purposes. 220void GCOVFunction::dump() { 221 dbgs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n"; 222 for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 223 E = Blocks.end(); I != E; ++I) 224 (*I)->dump(); 225} 226 227/// collectLineCounts - Collect line counts. This must be used after 228/// reading .gcno and .gcda files. 229void GCOVFunction::collectLineCounts(FileInfo &FI) { 230 for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 231 E = Blocks.end(); I != E; ++I) 232 (*I)->collectLineCounts(FI); 233} 234 235//===----------------------------------------------------------------------===// 236// GCOVBlock implementation. 237 238/// ~GCOVBlock - Delete GCOVBlock and its content. 239GCOVBlock::~GCOVBlock() { 240 Edges.clear(); 241 Lines.clear(); 242} 243 244/// collectLineCounts - Collect line counts. This must be used after 245/// reading .gcno and .gcda files. 246void GCOVBlock::collectLineCounts(FileInfo &FI) { 247 for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 248 E = Lines.end(); I != E; ++I) 249 FI.addLineCount(Parent.getFilename(), *I, Counter); 250} 251 252/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. 253void GCOVBlock::dump() { 254 dbgs() << "Block : " << Number << " Counter : " << Counter << "\n"; 255 if (!Edges.empty()) { 256 dbgs() << "\tEdges : "; 257 for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end(); 258 I != E; ++I) 259 dbgs() << (*I) << ","; 260 dbgs() << "\n"; 261 } 262 if (!Lines.empty()) { 263 dbgs() << "\tLines : "; 264 for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 265 E = Lines.end(); I != E; ++I) 266 dbgs() << (*I) << ","; 267 dbgs() << "\n"; 268 } 269} 270 271//===----------------------------------------------------------------------===// 272// FileInfo implementation. 273 274/// print - Print source files with collected line count information. 275void FileInfo::print(raw_fd_ostream &OS, StringRef gcnoFile, 276 StringRef gcdaFile) { 277 for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end(); 278 I != E; ++I) { 279 StringRef Filename = I->first(); 280 OS << " -: 0:Source:" << Filename << "\n"; 281 OS << " -: 0:Graph:" << gcnoFile << "\n"; 282 OS << " -: 0:Data:" << gcdaFile << "\n"; 283 OS << " -: 0:Runs:" << RunCount << "\n"; 284 OS << " -: 0:Programs:" << ProgramCount << "\n"; 285 LineCounts &L = LineInfo[Filename]; 286 OwningPtr<MemoryBuffer> Buff; 287 if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { 288 errs() << Filename << ": " << ec.message() << "\n"; 289 return; 290 } 291 StringRef AllLines = Buff.take()->getBuffer(); 292 uint32_t i = 0; 293 while (!AllLines.empty()) { 294 if (L.find(i) != L.end()) { 295 if (L[i] == 0) 296 OS << " #####:"; 297 else 298 OS << format("%9lu:", L[i]); 299 } else { 300 OS << " -:"; 301 } 302 std::pair<StringRef, StringRef> P = AllLines.split('\n'); 303 if (AllLines != P.first) 304 OS << format("%5u:", i+1) << P.first; 305 OS << "\n"; 306 AllLines = P.second; 307 ++i; 308 } 309 } 310} 311 312