LCOV - code coverage report
Current view: top level - include/llvm/ProfileData - GCOV.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 107 119 89.9 %
Date: 2018-02-20 03:34:22 Functions: 19 19 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13