LLVM API Documentation

GCOV.h
Go to the documentation of this file.
00001 //===- GCOV.h - LLVM coverage tool ----------------------------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This header provides the interface to read and write coverage files that
00011 // use 'gcov' format.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #ifndef LLVM_SUPPORT_GCOV_H
00016 #define LLVM_SUPPORT_GCOV_H
00017 
00018 #include "llvm/ADT/DenseMap.h"
00019 #include "llvm/ADT/MapVector.h"
00020 #include "llvm/ADT/SmallVector.h"
00021 #include "llvm/ADT/StringMap.h"
00022 #include "llvm/Support/MemoryBuffer.h"
00023 #include "llvm/Support/raw_ostream.h"
00024 
00025 namespace llvm {
00026 
00027 class GCOVFunction;
00028 class GCOVBlock;
00029 class FileInfo;
00030 
00031 namespace GCOV {
00032   enum GCOVVersion {
00033     V402,
00034     V404
00035   };
00036 } // end GCOV namespace
00037 
00038 /// GCOVOptions - A struct for passing gcov options between functions.
00039 struct GCOVOptions {
00040   GCOVOptions(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
00041       : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
00042         PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
00043 
00044   bool AllBlocks;
00045   bool BranchInfo;
00046   bool BranchCount;
00047   bool FuncCoverage;
00048   bool PreservePaths;
00049   bool UncondBranch;
00050   bool LongFileNames;
00051   bool NoOutput;
00052 };
00053 
00054 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
00055 /// read operations.
00056 class GCOVBuffer {
00057 public:
00058   GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
00059   
00060   /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
00061   bool readGCNOFormat() {
00062     StringRef File = Buffer->getBuffer().slice(0, 4);
00063     if (File != "oncg") {
00064       errs() << "Unexpected file type: " << File << ".\n";
00065       return false;
00066     }
00067     Cursor = 4;
00068     return true;
00069   }
00070 
00071   /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
00072   bool readGCDAFormat() {
00073     StringRef File = Buffer->getBuffer().slice(0, 4);
00074     if (File != "adcg") {
00075       errs() << "Unexpected file type: " << File << ".\n";
00076       return false;
00077     }
00078     Cursor = 4;
00079     return true;
00080   }
00081 
00082   /// readGCOVVersion - Read GCOV version.
00083   bool readGCOVVersion(GCOV::GCOVVersion &Version) {
00084     StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor+4);
00085     if (VersionStr == "*204") {
00086       Cursor += 4;
00087       Version = GCOV::V402;
00088       return true;
00089     }
00090     if (VersionStr == "*404") {
00091       Cursor += 4;
00092       Version = GCOV::V404;
00093       return true;
00094     }
00095     errs() << "Unexpected version: " << VersionStr << ".\n";
00096     return false;
00097   }
00098 
00099   /// readFunctionTag - If cursor points to a function tag then increment the
00100   /// cursor and return true otherwise return false.
00101   bool readFunctionTag() {
00102     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
00103     if (Tag.empty() ||
00104         Tag[0] != '\0' || Tag[1] != '\0' ||
00105         Tag[2] != '\0' || Tag[3] != '\1') {
00106       return false;
00107     }
00108     Cursor += 4;
00109     return true;
00110   }
00111 
00112   /// readBlockTag - If cursor points to a block tag then increment the
00113   /// cursor and return true otherwise return false.
00114   bool readBlockTag() {
00115     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
00116     if (Tag.empty() ||
00117         Tag[0] != '\0' || Tag[1] != '\0' ||
00118         Tag[2] != '\x41' || Tag[3] != '\x01') {
00119       return false;
00120     }
00121     Cursor += 4;
00122     return true;
00123   }
00124 
00125   /// readEdgeTag - If cursor points to an edge tag then increment the
00126   /// cursor and return true otherwise return false.
00127   bool readEdgeTag() {
00128     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
00129     if (Tag.empty() ||
00130         Tag[0] != '\0' || Tag[1] != '\0' ||
00131         Tag[2] != '\x43' || Tag[3] != '\x01') {
00132       return false;
00133     }
00134     Cursor += 4;
00135     return true;
00136   }
00137 
00138   /// readLineTag - If cursor points to a line tag then increment the
00139   /// cursor and return true otherwise return false.
00140   bool readLineTag() {
00141     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
00142     if (Tag.empty() ||
00143         Tag[0] != '\0' || Tag[1] != '\0' ||
00144         Tag[2] != '\x45' || Tag[3] != '\x01') {
00145       return false;
00146     }
00147     Cursor += 4;
00148     return true;
00149   }
00150 
00151   /// readArcTag - If cursor points to an gcda arc tag then increment the
00152   /// cursor and return true otherwise return false.
00153   bool readArcTag() {
00154     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
00155     if (Tag.empty() ||
00156         Tag[0] != '\0' || Tag[1] != '\0' ||
00157         Tag[2] != '\xa1' || Tag[3] != '\1') {
00158       return false;
00159     }
00160     Cursor += 4;
00161     return true;
00162   }
00163 
00164   /// readObjectTag - If cursor points to an object summary tag then increment
00165   /// the cursor and return true otherwise return false.
00166   bool readObjectTag() {
00167     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
00168     if (Tag.empty() ||
00169         Tag[0] != '\0' || Tag[1] != '\0' ||
00170         Tag[2] != '\0' || Tag[3] != '\xa1') {
00171       return false;
00172     }
00173     Cursor += 4;
00174     return true;
00175   }
00176 
00177   /// readProgramTag - If cursor points to a program summary tag then increment
00178   /// the cursor and return true otherwise return false.
00179   bool readProgramTag() {
00180     StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
00181     if (Tag.empty() ||
00182         Tag[0] != '\0' || Tag[1] != '\0' ||
00183         Tag[2] != '\0' || Tag[3] != '\xa3') {
00184       return false;
00185     }
00186     Cursor += 4;
00187     return true;
00188   }
00189 
00190   bool readInt(uint32_t &Val) {
00191     if (Buffer->getBuffer().size() < Cursor+4) {
00192       errs() << "Unexpected end of memory buffer: " << Cursor+4 << ".\n";
00193       return false;
00194     }
00195     StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4);
00196     Cursor += 4;
00197     Val = *(const uint32_t *)(Str.data());
00198     return true;
00199   }
00200 
00201   bool readInt64(uint64_t &Val) {
00202     uint32_t Lo, Hi;
00203     if (!readInt(Lo) || !readInt(Hi)) return false;
00204     Val = ((uint64_t)Hi << 32) | Lo;
00205     return true;
00206   }
00207 
00208   bool readString(StringRef &Str) {
00209     uint32_t Len = 0;
00210     // Keep reading until we find a non-zero length. This emulates gcov's
00211     // behaviour, which appears to do the same.
00212     while (Len == 0)
00213       if (!readInt(Len)) return false;
00214     Len *= 4;
00215     if (Buffer->getBuffer().size() < Cursor+Len) {
00216       errs() << "Unexpected end of memory buffer: " << Cursor+Len << ".\n";
00217       return false;
00218     }
00219     Str = Buffer->getBuffer().slice(Cursor, Cursor+Len).split('\0').first;
00220     Cursor += Len;
00221     return true;
00222   }
00223 
00224   uint64_t getCursor() const { return Cursor; }
00225   void advanceCursor(uint32_t n) { Cursor += n*4; }
00226 private:
00227   MemoryBuffer *Buffer;
00228   uint64_t Cursor;
00229 };
00230 
00231 /// GCOVFile - Collects coverage information for one pair of coverage file
00232 /// (.gcno and .gcda).
00233 class GCOVFile {
00234 public:
00235   GCOVFile() : GCNOInitialized(false), Checksum(0), Functions(), RunCount(0),
00236                ProgramCount(0) {}
00237   bool readGCNO(GCOVBuffer &Buffer);
00238   bool readGCDA(GCOVBuffer &Buffer);
00239   uint32_t getChecksum() const { return Checksum; }
00240   void dump() const;
00241   void collectLineCounts(FileInfo &FI);
00242 private:
00243   bool GCNOInitialized;
00244   GCOV::GCOVVersion Version;
00245   uint32_t Checksum;
00246   SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
00247   uint32_t RunCount;
00248   uint32_t ProgramCount;
00249 };
00250 
00251 /// GCOVEdge - Collects edge information.
00252 struct GCOVEdge {
00253   GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D), Count(0) {}
00254 
00255   GCOVBlock &Src;
00256   GCOVBlock &Dst;
00257   uint64_t Count;
00258 };
00259 
00260 /// GCOVFunction - Collects function information.
00261 class GCOVFunction {
00262 public:
00263   typedef SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator
00264   BlockIterator;
00265 
00266   GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {}
00267   bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
00268   bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
00269   StringRef getName() const { return Name; }
00270   StringRef getFilename() const { return Filename; }
00271   size_t getNumBlocks() const { return Blocks.size(); }
00272   uint64_t getEntryCount() const;
00273   uint64_t getExitCount() const;
00274 
00275   BlockIterator block_begin() const { return Blocks.begin(); }
00276   BlockIterator block_end() const { return Blocks.end(); }
00277 
00278   void dump() const;
00279   void collectLineCounts(FileInfo &FI);
00280 private:
00281   GCOVFile &Parent;
00282   uint32_t Ident;
00283   uint32_t Checksum;
00284   uint32_t LineNumber;
00285   StringRef Name;
00286   StringRef Filename;
00287   SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
00288   SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
00289 };
00290 
00291 /// GCOVBlock - Collects block information.
00292 class GCOVBlock {
00293   struct EdgeWeight {
00294     EdgeWeight(GCOVBlock *D): Dst(D), Count(0) {}
00295 
00296     GCOVBlock *Dst;
00297     uint64_t Count;
00298   };
00299 
00300   struct SortDstEdgesFunctor {
00301     bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
00302       return E1->Dst.Number < E2->Dst.Number;
00303     }
00304   };
00305 public:
00306   typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator;
00307 
00308   GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N), Counter(0),
00309     DstEdgesAreSorted(true), SrcEdges(), DstEdges(), Lines() {}
00310   ~GCOVBlock();
00311   const GCOVFunction &getParent() const { return Parent; }
00312   void addLine(uint32_t N) { Lines.push_back(N); }
00313   uint32_t getLastLine() const { return Lines.back(); }
00314   void addCount(size_t DstEdgeNo, uint64_t N);
00315   uint64_t getCount() const { return Counter; }
00316 
00317   void addSrcEdge(GCOVEdge *Edge) {
00318     assert(&Edge->Dst == this); // up to caller to ensure edge is valid
00319     SrcEdges.push_back(Edge);
00320   }
00321   void addDstEdge(GCOVEdge *Edge) {
00322     assert(&Edge->Src == this); // up to caller to ensure edge is valid
00323     // Check if adding this edge causes list to become unsorted.
00324     if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
00325       DstEdgesAreSorted = false;
00326     DstEdges.push_back(Edge);
00327   }
00328   size_t getNumSrcEdges() const { return SrcEdges.size(); }
00329   size_t getNumDstEdges() const { return DstEdges.size(); }
00330   void sortDstEdges();
00331 
00332   EdgeIterator src_begin() const { return SrcEdges.begin(); }
00333   EdgeIterator src_end() const { return SrcEdges.end(); }
00334   EdgeIterator dst_begin() const { return DstEdges.begin(); }
00335   EdgeIterator dst_end() const { return DstEdges.end(); }
00336 
00337   void dump() const;
00338   void collectLineCounts(FileInfo &FI);
00339 private:
00340   GCOVFunction &Parent;
00341   uint32_t Number;
00342   uint64_t Counter;
00343   bool DstEdgesAreSorted;
00344   SmallVector<GCOVEdge *, 16> SrcEdges;
00345   SmallVector<GCOVEdge *, 16> DstEdges;
00346   SmallVector<uint32_t, 16> Lines;
00347 };
00348 
00349 class FileInfo {
00350   // It is unlikely--but possible--for multiple functions to be on the same line.
00351   // Therefore this typedef allows LineData.Functions to store multiple functions
00352   // per instance. This is rare, however, so optimize for the common case.
00353   typedef SmallVector<const GCOVFunction *, 1> FunctionVector;
00354   typedef DenseMap<uint32_t, FunctionVector> FunctionLines;
00355   typedef SmallVector<const GCOVBlock *, 4> BlockVector;
00356   typedef DenseMap<uint32_t, BlockVector> BlockLines;
00357 
00358   struct LineData {
00359     LineData() : LastLine(0) {}
00360     BlockLines Blocks;
00361     FunctionLines Functions;
00362     uint32_t LastLine;
00363   };
00364 
00365   struct GCOVCoverage {
00366     GCOVCoverage(StringRef Name) :
00367       Name(Name), LogicalLines(0), LinesExec(0), Branches(0), BranchesExec(0),
00368       BranchesTaken(0) {}
00369 
00370     StringRef Name;
00371 
00372     uint32_t LogicalLines;
00373     uint32_t LinesExec;
00374 
00375     uint32_t Branches;
00376     uint32_t BranchesExec;
00377     uint32_t BranchesTaken;
00378   };
00379 public:
00380   FileInfo(const GCOVOptions &Options) :
00381     Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {}
00382 
00383   void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
00384     if (Line > LineInfo[Filename].LastLine)
00385       LineInfo[Filename].LastLine = Line;
00386     LineInfo[Filename].Blocks[Line-1].push_back(Block);
00387   }
00388   void addFunctionLine(StringRef Filename, uint32_t Line,
00389                        const GCOVFunction *Function) {
00390     if (Line > LineInfo[Filename].LastLine)
00391       LineInfo[Filename].LastLine = Line;
00392     LineInfo[Filename].Functions[Line-1].push_back(Function);
00393   }
00394   void setRunCount(uint32_t Runs) { RunCount = Runs; }
00395   void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
00396   void print(StringRef MainFilename, StringRef GCNOFile, StringRef GCDAFile);
00397 
00398 private:
00399   std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
00400   std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath);
00401   void printFunctionSummary(raw_ostream &OS,
00402                             const FunctionVector &Funcs) const;
00403   void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
00404                       uint32_t LineIndex, uint32_t &BlockNo) const;
00405   void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
00406                        GCOVCoverage &Coverage, uint32_t &EdgeNo);
00407   void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
00408                              uint64_t Count) const;
00409 
00410   void printCoverage(const GCOVCoverage &Coverage) const;
00411   void printFuncCoverage() const;
00412   void printFileCoverage() const;
00413 
00414   const GCOVOptions &Options;
00415   StringMap<LineData> LineInfo;
00416   uint32_t RunCount;
00417   uint32_t ProgramCount;
00418 
00419   typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4>
00420       FileCoverageList;
00421   typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap;
00422 
00423   FileCoverageList FileCoverages;
00424   FuncCoverageMap FuncCoverages;
00425 };
00426 
00427 }
00428 
00429 #endif