GCOV.cpp revision 12e90cb69a0a39d0db208de98162e39a2e3d6d1e
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 if (Line >= Blocks.size()) { 139 errs() << "Unexpected number of edges.\n"; 140 return false; 141 } 142 GCOVBlock &Block = *Blocks[Line]; 143 for (size_t Edge = 0, End = Block.getNumEdges(); Edge < End; ++Edge) { 144 if (Count == 0) { 145 errs() << "Unexpected number of edges.\n"; 146 return false; 147 } 148 uint64_t ArcCount; 149 if (!Buff.readInt64(ArcCount)) return false; 150 Block.addCount(ArcCount); 151 --Count; 152 } 153 } 154 return true; 155 } 156 157 if (!Buff.readInt(LineNumber)) return false; 158 159 // read blocks. 160 if (!Buff.readBlockTag()) { 161 errs() << "Block tag not found.\n"; 162 return false; 163 } 164 uint32_t BlockCount; 165 if (!Buff.readInt(BlockCount)) return false; 166 for (uint32_t i = 0, e = BlockCount; i != e; ++i) { 167 if (!Buff.readInt(Dummy)) return false; // Block flags; 168 Blocks.push_back(new GCOVBlock(*this, i)); 169 } 170 171 // read edges. 172 while (Buff.readEdgeTag()) { 173 uint32_t EdgeCount; 174 if (!Buff.readInt(EdgeCount)) return false; 175 EdgeCount = (EdgeCount - 1) / 2; 176 uint32_t BlockNo; 177 if (!Buff.readInt(BlockNo)) return false; 178 if (BlockNo >= BlockCount) { 179 errs() << "Unexpected block number.\n"; 180 return false; 181 } 182 for (uint32_t i = 0, e = EdgeCount; i != e; ++i) { 183 uint32_t Dst; 184 if (!Buff.readInt(Dst)) return false; 185 Blocks[BlockNo]->addEdge(Dst); 186 if (!Buff.readInt(Dummy)) return false; // Edge flag 187 } 188 } 189 190 // read line table. 191 while (Buff.readLineTag()) { 192 uint32_t LineTableLength; 193 if (!Buff.readInt(LineTableLength)) return false; 194 uint32_t EndPos = Buff.getCursor() + LineTableLength*4; 195 uint32_t BlockNo; 196 if (!Buff.readInt(BlockNo)) return false; 197 if (BlockNo >= BlockCount) { 198 errs() << "Unexpected block number.\n"; 199 return false; 200 } 201 GCOVBlock *Block = Blocks[BlockNo]; 202 if (!Buff.readInt(Dummy)) return false; // flag 203 while (Buff.getCursor() != (EndPos - 4)) { 204 StringRef F; 205 if (!Buff.readString(F)) return false; 206 if (F != Filename) { 207 errs() << "Multiple sources for a single basic block.\n"; 208 return false; 209 } 210 if (Buff.getCursor() == (EndPos - 4)) break; 211 while (true) { 212 uint32_t Line; 213 if (!Buff.readInt(Line)) return false; 214 if (!Line) break; 215 Block->addLine(Line); 216 } 217 } 218 if (!Buff.readInt(Dummy)) return false; // flag 219 } 220 return true; 221} 222 223/// dump - Dump GCOVFunction content to dbgs() for debugging purposes. 224void GCOVFunction::dump() { 225 dbgs() << "===== " << Name << " @ " << Filename << ":" << LineNumber << "\n"; 226 for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 227 E = Blocks.end(); I != E; ++I) 228 (*I)->dump(); 229} 230 231/// collectLineCounts - Collect line counts. This must be used after 232/// reading .gcno and .gcda files. 233void GCOVFunction::collectLineCounts(FileInfo &FI) { 234 for (SmallVectorImpl<GCOVBlock *>::iterator I = Blocks.begin(), 235 E = Blocks.end(); I != E; ++I) 236 (*I)->collectLineCounts(FI); 237} 238 239//===----------------------------------------------------------------------===// 240// GCOVBlock implementation. 241 242/// ~GCOVBlock - Delete GCOVBlock and its content. 243GCOVBlock::~GCOVBlock() { 244 Edges.clear(); 245 Lines.clear(); 246} 247 248/// collectLineCounts - Collect line counts. This must be used after 249/// reading .gcno and .gcda files. 250void GCOVBlock::collectLineCounts(FileInfo &FI) { 251 for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 252 E = Lines.end(); I != E; ++I) 253 FI.addLineCount(Parent.getFilename(), *I, Counter); 254} 255 256/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. 257void GCOVBlock::dump() { 258 dbgs() << "Block : " << Number << " Counter : " << Counter << "\n"; 259 if (!Edges.empty()) { 260 dbgs() << "\tEdges : "; 261 for (SmallVectorImpl<uint32_t>::iterator I = Edges.begin(), E = Edges.end(); 262 I != E; ++I) 263 dbgs() << (*I) << ","; 264 dbgs() << "\n"; 265 } 266 if (!Lines.empty()) { 267 dbgs() << "\tLines : "; 268 for (SmallVectorImpl<uint32_t>::iterator I = Lines.begin(), 269 E = Lines.end(); I != E; ++I) 270 dbgs() << (*I) << ","; 271 dbgs() << "\n"; 272 } 273} 274 275//===----------------------------------------------------------------------===// 276// FileInfo implementation. 277 278/// print - Print source files with collected line count information. 279void FileInfo::print(raw_fd_ostream &OS, StringRef gcnoFile, 280 StringRef gcdaFile) { 281 for (StringMap<LineCounts>::iterator I = LineInfo.begin(), E = LineInfo.end(); 282 I != E; ++I) { 283 StringRef Filename = I->first(); 284 OS << " -: 0:Source:" << Filename << "\n"; 285 OS << " -: 0:Graph:" << gcnoFile << "\n"; 286 OS << " -: 0:Data:" << gcdaFile << "\n"; 287 OS << " -: 0:Runs:" << RunCount << "\n"; 288 OS << " -: 0:Programs:" << ProgramCount << "\n"; 289 LineCounts &L = LineInfo[Filename]; 290 OwningPtr<MemoryBuffer> Buff; 291 if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { 292 errs() << Filename << ": " << ec.message() << "\n"; 293 return; 294 } 295 StringRef AllLines = Buff.take()->getBuffer(); 296 uint32_t i = 0; 297 while (!AllLines.empty()) { 298 if (L.find(i) != L.end()) { 299 if (L[i] == 0) 300 OS << " #####:"; 301 else 302 OS << format("%9lu:", L[i]); 303 } else { 304 OS << " -:"; 305 } 306 std::pair<StringRef, StringRef> P = AllLines.split('\n'); 307 if (AllLines != P.first) 308 OS << format("%5u:", i+1) << P.first; 309 OS << "\n"; 310 AllLines = P.second; 311 ++i; 312 } 313 } 314} 315