Home | History | Annotate | Download | only in Support
      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 {
     38   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:
     56   GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
     57 
     58   /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
     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.
     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.
     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.
     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.
    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.
    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.
    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.
    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.
    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.
    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 
    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 
    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 
    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 
    217   uint64_t getCursor() const { return Cursor; }
    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:
    229   GCOVFile()
    230       : GCNOInitialized(false), Checksum(0), Functions(), RunCount(0),
    231         ProgramCount(0) {}
    232   bool readGCNO(GCOVBuffer &Buffer);
    233   bool readGCDA(GCOVBuffer &Buffer);
    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 {
    249   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 
    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);
    265   StringRef getName() const { return Name; }
    266   StringRef getFilename() const { return Filename; }
    267   size_t getNumBlocks() const { return Blocks.size(); }
    268   uint64_t getEntryCount() const;
    269   uint64_t getExitCount() const;
    270 
    271   BlockIterator block_begin() const { return Blocks.begin(); }
    272   BlockIterator block_end() const { return Blocks.end(); }
    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 {
    294     EdgeWeight(GCOVBlock *D) : Dst(D), Count(0) {}
    295 
    296     GCOVBlock *Dst;
    297     uint64_t Count;
    298   };
    299 
    300   struct SortDstEdgesFunctor {
    301     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 
    309   GCOVBlock(GCOVFunction &P, uint32_t N)
    310       : Parent(P), Number(N), Counter(0), DstEdgesAreSorted(true), SrcEdges(),
    311         DstEdges(), Lines() {}
    312   ~GCOVBlock();
    313   const GCOVFunction &getParent() const { return Parent; }
    314   void addLine(uint32_t N) { Lines.push_back(N); }
    315   uint32_t getLastLine() const { return Lines.back(); }
    316   void addCount(size_t DstEdgeNo, uint64_t N);
    317   uint64_t getCount() const { return Counter; }
    318 
    319   void addSrcEdge(GCOVEdge *Edge) {
    320     assert(&Edge->Dst == this); // up to caller to ensure edge is valid
    321     SrcEdges.push_back(Edge);
    322   }
    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   }
    330   size_t getNumSrcEdges() const { return SrcEdges.size(); }
    331   size_t getNumDstEdges() const { return DstEdges.size(); }
    332   void sortDstEdges();
    333 
    334   EdgeIterator src_begin() const { return SrcEdges.begin(); }
    335   EdgeIterator src_end() const { return SrcEdges.end(); }
    336   iterator_range<EdgeIterator> srcs() const {
    337     return make_range(src_begin(), src_end());
    338   }
    339 
    340   EdgeIterator dst_begin() const { return DstEdges.begin(); }
    341   EdgeIterator dst_end() const { return DstEdges.end(); }
    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 {
    371     LineData() : LastLine(0) {}
    372     BlockLines Blocks;
    373     FunctionLines Functions;
    374     uint32_t LastLine;
    375   };
    376 
    377   struct GCOVCoverage {
    378     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:
    393   FileInfo(const GCOVOptions &Options)
    394       : Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {}
    395 
    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   }
    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   }
    407   void setRunCount(uint32_t Runs) { RunCount = Runs; }
    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