GCOV.cpp revision dbb51ff01fd08df39e5040c1cd9edacdc3e4308a
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(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 Filename; 201 if (!Buff.readString(Filename)) return false; 202 if (Buff.getCursor() == (EndPos - 4)) break; 203 while (true) { 204 uint32_t Line; 205 if (!Buff.readInt(Line)) return false; 206 if (!Line) break; 207 Block->addLine(Filename, Line); 208 } 209 } 210 if (!Buff.readInt(Dummy)) return false; // flag 211 } 212 return true; 213} 214 215/// dump - Dump GCOVFunction content to dbgs() for debugging purposes. 216void GCOVFunction::dump() { 217 dbgs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n"; 218 for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 219 E = Blocks.end(); I != E; ++I) 220 (*I)->dump(); 221} 222 223/// collectLineCounts - Collect line counts. This must be used after 224/// reading .gcno and .gcda files. 225void GCOVFunction::collectLineCounts(FileInfo &FI) { 226 for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 227 E = Blocks.end(); I != E; ++I) 228 (*I)->collectLineCounts(FI); 229} 230 231//===----------------------------------------------------------------------===// 232// GCOVBlock implementation. 233 234/// ~GCOVBlock - Delete GCOVBlock and its content. 235GCOVBlock::~GCOVBlock() { 236 Edges.clear(); 237 DeleteContainerSeconds(Lines); 238} 239 240void GCOVBlock::addLine(StringRef Filename, uint32_t LineNo) { 241 GCOVLines *&LinesForFile = Lines[Filename]; 242 if (!LinesForFile) 243 LinesForFile = new GCOVLines(); 244 LinesForFile->add(LineNo); 245} 246 247/// collectLineCounts - Collect line counts. This must be used after 248/// reading .gcno and .gcda files. 249void GCOVBlock::collectLineCounts(FileInfo &FI) { 250 for (StringMap<GCOVLines *>::iterator I = Lines.begin(), 251 E = Lines.end(); I != E; ++I) 252 I->second->collectLineCounts(FI, I->first(), Counter); 253} 254 255/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. 256void GCOVBlock::dump() { 257 dbgs() << "Block : " << Number << " Counter : " << Counter << "\n"; 258 if (!Edges.empty()) { 259 dbgs() << "\tEdges : "; 260 for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end(); 261 I != E; ++I) 262 dbgs() << (*I) << ","; 263 dbgs() << "\n"; 264 } 265 if (!Lines.empty()) { 266 dbgs() << "\tLines : "; 267 for (StringMap<GCOVLines *>::iterator LI = Lines.begin(), 268 LE = Lines.end(); LI != LE; ++LI) { 269 dbgs() << LI->first() << " -> "; 270 LI->second->dump(); 271 dbgs() << "\n"; 272 } 273 } 274} 275 276//===----------------------------------------------------------------------===// 277// GCOVLines implementation. 278 279/// collectLineCounts - Collect line counts. This must be used after 280/// reading .gcno and .gcda files. 281void GCOVLines::collectLineCounts(FileInfo &FI, StringRef Filename, 282 uint64_t Count) { 283 for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 284 E = Lines.end(); I != E; ++I) 285 FI.addLineCount(Filename, *I, Count); 286} 287 288/// dump - Dump GCOVLines content to dbgs() for debugging purposes. 289void GCOVLines::dump() { 290 for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 291 E = Lines.end(); I != E; ++I) 292 dbgs() << (*I) << ","; 293} 294 295//===----------------------------------------------------------------------===// 296// FileInfo implementation. 297 298/// print - Print source files with collected line count information. 299void FileInfo::print(raw_fd_ostream &OS, StringRef gcnoFile, 300 StringRef gcdaFile) { 301 for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end(); 302 I != E; ++I) { 303 StringRef Filename = I->first(); 304 OS << " -: 0:Source:" << Filename << "\n"; 305 OS << " -: 0:Graph:" << gcnoFile << "\n"; 306 OS << " -: 0:Data:" << gcdaFile << "\n"; 307 OS << " -: 0:Runs:" << RunCount << "\n"; 308 OS << " -: 0:Programs:" << ProgramCount << "\n"; 309 LineCounts &L = LineInfo[Filename]; 310 OwningPtr<MemoryBuffer> Buff; 311 if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { 312 errs() << Filename << ": " << ec.message() << "\n"; 313 return; 314 } 315 StringRef AllLines = Buff.take()->getBuffer(); 316 uint32_t i = 0; 317 while (!AllLines.empty()) { 318 if (L.find(i) != L.end()) { 319 if (L[i] == 0) 320 OS << " #####:"; 321 else 322 OS << format("%9lu:", L[i]); 323 } else { 324 OS << " -:"; 325 } 326 std::pair<StringRef, StringRef> P = AllLines.split('\n'); 327 if (AllLines != P.first) 328 OS << format("%5u:", i+1) << P.first; 329 OS << "\n"; 330 AllLines = P.second; 331 ++i; 332 } 333 } 334} 335 336