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

Generated by: LCOV version 1.13