1 //===- GCOV.h - 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 // This header provides the interface to read and write coverage files that 11 // use 'gcov' format. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_SUPPORT_GCOV_H 16 #define LLVM_SUPPORT_GCOV_H 17 18 #include "llvm/ADT/DenseMap.h" 19 #include "llvm/ADT/MapVector.h" 20 #include "llvm/ADT/SmallVector.h" 21 #include "llvm/ADT/StringMap.h" 22 #include "llvm/ADT/iterator.h" 23 #include "llvm/Support/MemoryBuffer.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 namespace llvm { 27 28 class GCOVFunction; 29 class GCOVBlock; 30 class FileInfo; 31 32 namespace GCOV { 33 enum GCOVVersion { V402, V404 }; 34 } // end GCOV namespace 35 36 /// GCOVOptions - A struct for passing gcov options between functions. 37 struct GCOVOptions { GCOVOptionsGCOVOptions38 GCOVOptions(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N) 39 : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F), 40 PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {} 41 42 bool AllBlocks; 43 bool BranchInfo; 44 bool BranchCount; 45 bool FuncCoverage; 46 bool PreservePaths; 47 bool UncondBranch; 48 bool LongFileNames; 49 bool NoOutput; 50 }; 51 52 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific 53 /// read operations. 54 class GCOVBuffer { 55 public: GCOVBuffer(MemoryBuffer * B)56 GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {} 57 58 /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer. readGCNOFormat()59 bool readGCNOFormat() { 60 StringRef File = Buffer->getBuffer().slice(0, 4); 61 if (File != "oncg") { 62 errs() << "Unexpected file type: " << File << ".\n"; 63 return false; 64 } 65 Cursor = 4; 66 return true; 67 } 68 69 /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer. readGCDAFormat()70 bool readGCDAFormat() { 71 StringRef File = Buffer->getBuffer().slice(0, 4); 72 if (File != "adcg") { 73 errs() << "Unexpected file type: " << File << ".\n"; 74 return false; 75 } 76 Cursor = 4; 77 return true; 78 } 79 80 /// readGCOVVersion - Read GCOV version. readGCOVVersion(GCOV::GCOVVersion & Version)81 bool readGCOVVersion(GCOV::GCOVVersion &Version) { 82 StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4); 83 if (VersionStr == "*204") { 84 Cursor += 4; 85 Version = GCOV::V402; 86 return true; 87 } 88 if (VersionStr == "*404") { 89 Cursor += 4; 90 Version = GCOV::V404; 91 return true; 92 } 93 errs() << "Unexpected version: " << VersionStr << ".\n"; 94 return false; 95 } 96 97 /// readFunctionTag - If cursor points to a function tag then increment the 98 /// cursor and return true otherwise return false. readFunctionTag()99 bool readFunctionTag() { 100 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4); 101 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' || 102 Tag[3] != '\1') { 103 return false; 104 } 105 Cursor += 4; 106 return true; 107 } 108 109 /// readBlockTag - If cursor points to a block tag then increment the 110 /// cursor and return true otherwise return false. readBlockTag()111 bool readBlockTag() { 112 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4); 113 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' || 114 Tag[3] != '\x01') { 115 return false; 116 } 117 Cursor += 4; 118 return true; 119 } 120 121 /// readEdgeTag - If cursor points to an edge tag then increment the 122 /// cursor and return true otherwise return false. readEdgeTag()123 bool readEdgeTag() { 124 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4); 125 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' || 126 Tag[3] != '\x01') { 127 return false; 128 } 129 Cursor += 4; 130 return true; 131 } 132 133 /// readLineTag - If cursor points to a line tag then increment the 134 /// cursor and return true otherwise return false. readLineTag()135 bool readLineTag() { 136 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4); 137 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' || 138 Tag[3] != '\x01') { 139 return false; 140 } 141 Cursor += 4; 142 return true; 143 } 144 145 /// readArcTag - If cursor points to an gcda arc tag then increment the 146 /// cursor and return true otherwise return false. readArcTag()147 bool readArcTag() { 148 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4); 149 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' || 150 Tag[3] != '\1') { 151 return false; 152 } 153 Cursor += 4; 154 return true; 155 } 156 157 /// readObjectTag - If cursor points to an object summary tag then increment 158 /// the cursor and return true otherwise return false. readObjectTag()159 bool readObjectTag() { 160 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4); 161 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' || 162 Tag[3] != '\xa1') { 163 return false; 164 } 165 Cursor += 4; 166 return true; 167 } 168 169 /// readProgramTag - If cursor points to a program summary tag then increment 170 /// the cursor and return true otherwise return false. readProgramTag()171 bool readProgramTag() { 172 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4); 173 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' || 174 Tag[3] != '\xa3') { 175 return false; 176 } 177 Cursor += 4; 178 return true; 179 } 180 readInt(uint32_t & Val)181 bool readInt(uint32_t &Val) { 182 if (Buffer->getBuffer().size() < Cursor + 4) { 183 errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n"; 184 return false; 185 } 186 StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4); 187 Cursor += 4; 188 Val = *(const uint32_t *)(Str.data()); 189 return true; 190 } 191 readInt64(uint64_t & Val)192 bool readInt64(uint64_t &Val) { 193 uint32_t Lo, Hi; 194 if (!readInt(Lo) || !readInt(Hi)) 195 return false; 196 Val = ((uint64_t)Hi << 32) | Lo; 197 return true; 198 } 199 readString(StringRef & Str)200 bool readString(StringRef &Str) { 201 uint32_t Len = 0; 202 // Keep reading until we find a non-zero length. This emulates gcov's 203 // behaviour, which appears to do the same. 204 while (Len == 0) 205 if (!readInt(Len)) 206 return false; 207 Len *= 4; 208 if (Buffer->getBuffer().size() < Cursor + Len) { 209 errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n"; 210 return false; 211 } 212 Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first; 213 Cursor += Len; 214 return true; 215 } 216 getCursor()217 uint64_t getCursor() const { return Cursor; } advanceCursor(uint32_t n)218 void advanceCursor(uint32_t n) { Cursor += n * 4; } 219 220 private: 221 MemoryBuffer *Buffer; 222 uint64_t Cursor; 223 }; 224 225 /// GCOVFile - Collects coverage information for one pair of coverage file 226 /// (.gcno and .gcda). 227 class GCOVFile { 228 public: GCOVFile()229 GCOVFile() 230 : GCNOInitialized(false), Checksum(0), Functions(), RunCount(0), 231 ProgramCount(0) {} 232 bool readGCNO(GCOVBuffer &Buffer); 233 bool readGCDA(GCOVBuffer &Buffer); getChecksum()234 uint32_t getChecksum() const { return Checksum; } 235 void dump() const; 236 void collectLineCounts(FileInfo &FI); 237 238 private: 239 bool GCNOInitialized; 240 GCOV::GCOVVersion Version; 241 uint32_t Checksum; 242 SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions; 243 uint32_t RunCount; 244 uint32_t ProgramCount; 245 }; 246 247 /// GCOVEdge - Collects edge information. 248 struct GCOVEdge { GCOVEdgeGCOVEdge249 GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D), Count(0) {} 250 251 GCOVBlock &Src; 252 GCOVBlock &Dst; 253 uint64_t Count; 254 }; 255 256 /// GCOVFunction - Collects function information. 257 class GCOVFunction { 258 public: 259 typedef pointee_iterator<SmallVectorImpl< 260 std::unique_ptr<GCOVBlock>>::const_iterator> BlockIterator; 261 GCOVFunction(GCOVFile & P)262 GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {} 263 bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); 264 bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); getName()265 StringRef getName() const { return Name; } getFilename()266 StringRef getFilename() const { return Filename; } getNumBlocks()267 size_t getNumBlocks() const { return Blocks.size(); } 268 uint64_t getEntryCount() const; 269 uint64_t getExitCount() const; 270 block_begin()271 BlockIterator block_begin() const { return Blocks.begin(); } block_end()272 BlockIterator block_end() const { return Blocks.end(); } blocks()273 iterator_range<BlockIterator> blocks() const { 274 return make_range(block_begin(), block_end()); 275 } 276 277 void dump() const; 278 void collectLineCounts(FileInfo &FI); 279 280 private: 281 GCOVFile &Parent; 282 uint32_t Ident; 283 uint32_t Checksum; 284 uint32_t LineNumber; 285 StringRef Name; 286 StringRef Filename; 287 SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks; 288 SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges; 289 }; 290 291 /// GCOVBlock - Collects block information. 292 class GCOVBlock { 293 struct EdgeWeight { EdgeWeightEdgeWeight294 EdgeWeight(GCOVBlock *D) : Dst(D), Count(0) {} 295 296 GCOVBlock *Dst; 297 uint64_t Count; 298 }; 299 300 struct SortDstEdgesFunctor { operatorSortDstEdgesFunctor301 bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) { 302 return E1->Dst.Number < E2->Dst.Number; 303 } 304 }; 305 306 public: 307 typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator; 308 GCOVBlock(GCOVFunction & P,uint32_t N)309 GCOVBlock(GCOVFunction &P, uint32_t N) 310 : Parent(P), Number(N), Counter(0), DstEdgesAreSorted(true), SrcEdges(), 311 DstEdges(), Lines() {} 312 ~GCOVBlock(); getParent()313 const GCOVFunction &getParent() const { return Parent; } addLine(uint32_t N)314 void addLine(uint32_t N) { Lines.push_back(N); } getLastLine()315 uint32_t getLastLine() const { return Lines.back(); } 316 void addCount(size_t DstEdgeNo, uint64_t N); getCount()317 uint64_t getCount() const { return Counter; } 318 addSrcEdge(GCOVEdge * Edge)319 void addSrcEdge(GCOVEdge *Edge) { 320 assert(&Edge->Dst == this); // up to caller to ensure edge is valid 321 SrcEdges.push_back(Edge); 322 } addDstEdge(GCOVEdge * Edge)323 void addDstEdge(GCOVEdge *Edge) { 324 assert(&Edge->Src == this); // up to caller to ensure edge is valid 325 // Check if adding this edge causes list to become unsorted. 326 if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number) 327 DstEdgesAreSorted = false; 328 DstEdges.push_back(Edge); 329 } getNumSrcEdges()330 size_t getNumSrcEdges() const { return SrcEdges.size(); } getNumDstEdges()331 size_t getNumDstEdges() const { return DstEdges.size(); } 332 void sortDstEdges(); 333 src_begin()334 EdgeIterator src_begin() const { return SrcEdges.begin(); } src_end()335 EdgeIterator src_end() const { return SrcEdges.end(); } srcs()336 iterator_range<EdgeIterator> srcs() const { 337 return make_range(src_begin(), src_end()); 338 } 339 dst_begin()340 EdgeIterator dst_begin() const { return DstEdges.begin(); } dst_end()341 EdgeIterator dst_end() const { return DstEdges.end(); } dsts()342 iterator_range<EdgeIterator> dsts() const { 343 return make_range(dst_begin(), dst_end()); 344 } 345 346 void dump() const; 347 void collectLineCounts(FileInfo &FI); 348 349 private: 350 GCOVFunction &Parent; 351 uint32_t Number; 352 uint64_t Counter; 353 bool DstEdgesAreSorted; 354 SmallVector<GCOVEdge *, 16> SrcEdges; 355 SmallVector<GCOVEdge *, 16> DstEdges; 356 SmallVector<uint32_t, 16> Lines; 357 }; 358 359 class FileInfo { 360 // It is unlikely--but possible--for multiple functions to be on the same 361 // line. 362 // Therefore this typedef allows LineData.Functions to store multiple 363 // functions 364 // per instance. This is rare, however, so optimize for the common case. 365 typedef SmallVector<const GCOVFunction *, 1> FunctionVector; 366 typedef DenseMap<uint32_t, FunctionVector> FunctionLines; 367 typedef SmallVector<const GCOVBlock *, 4> BlockVector; 368 typedef DenseMap<uint32_t, BlockVector> BlockLines; 369 370 struct LineData { LineDataLineData371 LineData() : LastLine(0) {} 372 BlockLines Blocks; 373 FunctionLines Functions; 374 uint32_t LastLine; 375 }; 376 377 struct GCOVCoverage { GCOVCoverageGCOVCoverage378 GCOVCoverage(StringRef Name) 379 : Name(Name), LogicalLines(0), LinesExec(0), Branches(0), 380 BranchesExec(0), BranchesTaken(0) {} 381 382 StringRef Name; 383 384 uint32_t LogicalLines; 385 uint32_t LinesExec; 386 387 uint32_t Branches; 388 uint32_t BranchesExec; 389 uint32_t BranchesTaken; 390 }; 391 392 public: FileInfo(const GCOVOptions & Options)393 FileInfo(const GCOVOptions &Options) 394 : Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {} 395 addBlockLine(StringRef Filename,uint32_t Line,const GCOVBlock * Block)396 void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) { 397 if (Line > LineInfo[Filename].LastLine) 398 LineInfo[Filename].LastLine = Line; 399 LineInfo[Filename].Blocks[Line - 1].push_back(Block); 400 } addFunctionLine(StringRef Filename,uint32_t Line,const GCOVFunction * Function)401 void addFunctionLine(StringRef Filename, uint32_t Line, 402 const GCOVFunction *Function) { 403 if (Line > LineInfo[Filename].LastLine) 404 LineInfo[Filename].LastLine = Line; 405 LineInfo[Filename].Functions[Line - 1].push_back(Function); 406 } setRunCount(uint32_t Runs)407 void setRunCount(uint32_t Runs) { RunCount = Runs; } setProgramCount(uint32_t Programs)408 void setProgramCount(uint32_t Programs) { ProgramCount = Programs; } 409 void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile, 410 StringRef GCDAFile); 411 412 private: 413 std::string getCoveragePath(StringRef Filename, StringRef MainFilename); 414 std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath); 415 void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const; 416 void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block, 417 uint32_t LineIndex, uint32_t &BlockNo) const; 418 void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block, 419 GCOVCoverage &Coverage, uint32_t &EdgeNo); 420 void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo, 421 uint64_t Count) const; 422 423 void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const; 424 void printFuncCoverage(raw_ostream &OS) const; 425 void printFileCoverage(raw_ostream &OS) const; 426 427 const GCOVOptions &Options; 428 StringMap<LineData> LineInfo; 429 uint32_t RunCount; 430 uint32_t ProgramCount; 431 432 typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4> FileCoverageList; 433 typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap; 434 435 FileCoverageList FileCoverages; 436 FuncCoverageMap FuncCoverages; 437 }; 438 } 439 440 #endif 441