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