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   ~GCOVFile();
00236   bool readGCNO(GCOVBuffer &Buffer);
00237   bool readGCDA(GCOVBuffer &Buffer);
00238   uint32_t getChecksum() const { return Checksum; }
00239   void dump() const;
00240   void collectLineCounts(FileInfo &FI);
00241 private:
00242   bool GCNOInitialized;
00243   GCOV::GCOVVersion Version;
00244   uint32_t Checksum;
00245   SmallVector<GCOVFunction *, 16> Functions;
00246   uint32_t RunCount;
00247   uint32_t ProgramCount;
00248 };
00249 
00250 /// GCOVEdge - Collects edge information.
00251 struct GCOVEdge {
00252   GCOVEdge(GCOVBlock *S, GCOVBlock *D): Src(S), Dst(D), Count(0) {}
00253 
00254   GCOVBlock *Src;
00255   GCOVBlock *Dst;
00256   uint64_t Count;
00257 };
00258 
00259 /// GCOVFunction - Collects function information.
00260 class GCOVFunction {
00261 public:
00262   typedef SmallVectorImpl<GCOVBlock *>::const_iterator BlockIterator;
00263 
00264   GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {}
00265   ~GCOVFunction();
00266   bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
00267   bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
00268   StringRef getName() const { return Name; }
00269   StringRef getFilename() const { return Filename; }
00270   size_t getNumBlocks() const { return Blocks.size(); }
00271   uint64_t getEntryCount() const;
00272   uint64_t getExitCount() const;
00273 
00274   BlockIterator block_begin() const { return Blocks.begin(); }
00275   BlockIterator block_end() const { return Blocks.end(); }
00276 
00277   void dump() const;
00278   void collectLineCounts(FileInfo &FI);
00279 private:
00280   GCOVFile &Parent;
00281   uint32_t Ident;
00282   uint32_t Checksum;
00283   uint32_t LineNumber;
00284   StringRef Name;
00285   StringRef Filename;
00286   SmallVector<GCOVBlock *, 16> Blocks;
00287   SmallVector<GCOVEdge *, 16> Edges;
00288 };
00289 
00290 /// GCOVBlock - Collects block information.
00291 class GCOVBlock {
00292   struct EdgeWeight {
00293     EdgeWeight(GCOVBlock *D): Dst(D), Count(0) {}
00294 
00295     GCOVBlock *Dst;
00296     uint64_t Count;
00297   };
00298 
00299   struct SortDstEdgesFunctor {
00300     bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
00301       return E1->Dst->Number < E2->Dst->Number;
00302     }
00303   };
00304 public:
00305   typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator;
00306 
00307   GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N), Counter(0),
00308     DstEdgesAreSorted(true), SrcEdges(), DstEdges(), Lines() {}
00309   ~GCOVBlock();
00310   const GCOVFunction &getParent() const { return Parent; }
00311   void addLine(uint32_t N) { Lines.push_back(N); }
00312   uint32_t getLastLine() const { return Lines.back(); }
00313   void addCount(size_t DstEdgeNo, uint64_t N);
00314   uint64_t getCount() const { return Counter; }
00315 
00316   void addSrcEdge(GCOVEdge *Edge) {
00317     assert(Edge->Dst == this); // up to caller to ensure edge is valid
00318     SrcEdges.push_back(Edge);
00319   }
00320   void addDstEdge(GCOVEdge *Edge) {
00321     assert(Edge->Src == this); // up to caller to ensure edge is valid
00322     // Check if adding this edge causes list to become unsorted.
00323     if (DstEdges.size() && DstEdges.back()->Dst->Number > Edge->Dst->Number)
00324       DstEdgesAreSorted = false;
00325     DstEdges.push_back(Edge);
00326   }
00327   size_t getNumSrcEdges() const { return SrcEdges.size(); }
00328   size_t getNumDstEdges() const { return DstEdges.size(); }
00329   void sortDstEdges();
00330 
00331   EdgeIterator src_begin() const { return SrcEdges.begin(); }
00332   EdgeIterator src_end() const { return SrcEdges.end(); }
00333   EdgeIterator dst_begin() const { return DstEdges.begin(); }
00334   EdgeIterator dst_end() const { return DstEdges.end(); }
00335 
00336   void dump() const;
00337   void collectLineCounts(FileInfo &FI);
00338 private:
00339   GCOVFunction &Parent;
00340   uint32_t Number;
00341   uint64_t Counter;
00342   bool DstEdgesAreSorted;
00343   SmallVector<GCOVEdge *, 16> SrcEdges;
00344   SmallVector<GCOVEdge *, 16> DstEdges;
00345   SmallVector<uint32_t, 16> Lines;
00346 };
00347 
00348 class FileInfo {
00349   // It is unlikely--but possible--for multiple functions to be on the same line.
00350   // Therefore this typedef allows LineData.Functions to store multiple functions
00351   // per instance. This is rare, however, so optimize for the common case.
00352   typedef SmallVector<const GCOVFunction *, 1> FunctionVector;
00353   typedef DenseMap<uint32_t, FunctionVector> FunctionLines;
00354   typedef SmallVector<const GCOVBlock *, 4> BlockVector;
00355   typedef DenseMap<uint32_t, BlockVector> BlockLines;
00356 
00357   struct LineData {
00358     BlockLines Blocks;
00359     FunctionLines Functions;
00360   };
00361 
00362   struct GCOVCoverage {
00363     GCOVCoverage(StringRef Name) :
00364       Name(Name), LogicalLines(0), LinesExec(0), Branches(0), BranchesExec(0),
00365       BranchesTaken(0) {}
00366 
00367     StringRef Name;
00368 
00369     uint32_t LogicalLines;
00370     uint32_t LinesExec;
00371 
00372     uint32_t Branches;
00373     uint32_t BranchesExec;
00374     uint32_t BranchesTaken;
00375   };
00376 public:
00377   FileInfo(const GCOVOptions &Options) :
00378     Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {}
00379 
00380   void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
00381     LineInfo[Filename].Blocks[Line-1].push_back(Block);
00382   }
00383   void addFunctionLine(StringRef Filename, uint32_t Line,
00384                        const GCOVFunction *Function) {
00385     LineInfo[Filename].Functions[Line-1].push_back(Function);
00386   }
00387   void setRunCount(uint32_t Runs) { RunCount = Runs; }
00388   void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
00389   void print(StringRef GCNOFile, StringRef GCDAFile);
00390 private:
00391   void printFunctionSummary(raw_fd_ostream &OS,
00392                             const FunctionVector &Funcs) const;
00393   void printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
00394                       uint32_t LineIndex, uint32_t &BlockNo) const;
00395   void printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block,
00396                        GCOVCoverage &Coverage, uint32_t &EdgeNo);
00397   void printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo,
00398                              uint64_t Count) const;
00399 
00400   void printCoverage(const GCOVCoverage &Coverage) const;
00401   void printFuncCoverage() const;
00402   void printFileCoverage() const;
00403 
00404   const GCOVOptions &Options;
00405   StringMap<LineData> LineInfo;
00406   uint32_t RunCount;
00407   uint32_t ProgramCount;
00408 
00409   typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4>
00410       FileCoverageList;
00411   typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap;
00412 
00413   FileCoverageList FileCoverages;
00414   FuncCoverageMap FuncCoverages;
00415 };
00416 
00417 }
00418 
00419 #endif