Home | History | Annotate | Line # | Download | only in ProfileData
      1 //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This header provides the interface to read and write coverage files that
     10 // use 'gcov' format.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_PROFILEDATA_GCOV_H
     15 #define LLVM_PROFILEDATA_GCOV_H
     16 
     17 #include "llvm/ADT/DenseMap.h"
     18 #include "llvm/ADT/DenseSet.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/DataExtractor.h"
     26 #include "llvm/Support/MemoryBuffer.h"
     27 #include "llvm/Support/raw_ostream.h"
     28 #include <algorithm>
     29 #include <cassert>
     30 #include <cstddef>
     31 #include <cstdint>
     32 #include <limits>
     33 #include <map>
     34 #include <memory>
     35 #include <string>
     36 #include <utility>
     37 
     38 namespace llvm {
     39 
     40 class GCOVFunction;
     41 class GCOVBlock;
     42 
     43 namespace GCOV {
     44 
     45 enum GCOVVersion { V304, V407, V408, V800, V900 };
     46 
     47 /// A struct for passing gcov options between functions.
     48 struct Options {
     49   Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L,
     50           bool M, bool N, bool R, bool T, bool X, std::string SourcePrefix)
     51       : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
     52         PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L),
     53         Demangle(M), NoOutput(N), RelativeOnly(R), UseStdout(T),
     54         HashFilenames(X), SourcePrefix(std::move(SourcePrefix)) {}
     55 
     56   bool AllBlocks;
     57   bool BranchInfo;
     58   bool BranchCount;
     59   bool FuncCoverage;
     60   bool PreservePaths;
     61   bool UncondBranch;
     62   bool Intermediate;
     63   bool LongFileNames;
     64   bool Demangle;
     65   bool NoOutput;
     66   bool RelativeOnly;
     67   bool UseStdout;
     68   bool HashFilenames;
     69   std::string SourcePrefix;
     70 };
     71 
     72 } // end namespace GCOV
     73 
     74 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
     75 /// read operations.
     76 class GCOVBuffer {
     77 public:
     78   GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
     79   ~GCOVBuffer() { consumeError(cursor.takeError()); }
     80 
     81   /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
     82   bool readGCNOFormat() {
     83     StringRef buf = Buffer->getBuffer();
     84     StringRef magic = buf.substr(0, 4);
     85     if (magic == "gcno") {
     86       de = DataExtractor(buf.substr(4), false, 0);
     87     } else if (magic == "oncg") {
     88       de = DataExtractor(buf.substr(4), true, 0);
     89     } else {
     90       errs() << "unexpected magic: " << magic << "\n";
     91       return false;
     92     }
     93     return true;
     94   }
     95 
     96   /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
     97   bool readGCDAFormat() {
     98     StringRef buf = Buffer->getBuffer();
     99     StringRef magic = buf.substr(0, 4);
    100     if (magic == "gcda") {
    101       de = DataExtractor(buf.substr(4), false, 0);
    102     } else if (magic == "adcg") {
    103       de = DataExtractor(buf.substr(4), true, 0);
    104     } else {
    105       return false;
    106     }
    107     return true;
    108   }
    109 
    110   /// readGCOVVersion - Read GCOV version.
    111   bool readGCOVVersion(GCOV::GCOVVersion &Version) {
    112     std::string str(de.getBytes(cursor, 4));
    113     if (str.size() != 4)
    114       return false;
    115     if (de.isLittleEndian())
    116       std::reverse(str.begin(), str.end());
    117     int ver = str[0] >= 'A'
    118                   ? (str[0] - 'A') * 100 + (str[1] - '0') * 10 + str[2] - '0'
    119                   : (str[0] - '0') * 10 + str[2] - '0';
    120     if (ver >= 90) {
    121       // PR gcov-profile/84846, r269678
    122       Version = GCOV::V900;
    123       return true;
    124     } else if (ver >= 80) {
    125       // PR gcov-profile/48463
    126       Version = GCOV::V800;
    127       return true;
    128     } else if (ver >= 48) {
    129       // r189778: the exit block moved from the last to the second.
    130       Version = GCOV::V408;
    131       return true;
    132     } else if (ver >= 47) {
    133       // r173147: split checksum into cfg checksum and line checksum.
    134       Version = GCOV::V407;
    135       return true;
    136     } else if (ver >= 34) {
    137       Version = GCOV::V304;
    138       return true;
    139     }
    140     errs() << "unexpected version: " << str << "\n";
    141     return false;
    142   }
    143 
    144   uint32_t getWord() { return de.getU32(cursor); }
    145   StringRef getString() {
    146     uint32_t len;
    147     if (!readInt(len) || len == 0)
    148       return {};
    149     return de.getBytes(cursor, len * 4).split('\0').first;
    150   }
    151 
    152   bool readInt(uint32_t &Val) {
    153     if (cursor.tell() + 4 > de.size()) {
    154       Val = 0;
    155       errs() << "unexpected end of memory buffer: " << cursor.tell() << "\n";
    156       return false;
    157     }
    158     Val = de.getU32(cursor);
    159     return true;
    160   }
    161 
    162   bool readInt64(uint64_t &Val) {
    163     uint32_t Lo, Hi;
    164     if (!readInt(Lo) || !readInt(Hi))
    165       return false;
    166     Val = ((uint64_t)Hi << 32) | Lo;
    167     return true;
    168   }
    169 
    170   bool readString(StringRef &Str) {
    171     uint32_t len;
    172     if (!readInt(len) || len == 0)
    173       return false;
    174     Str = de.getBytes(cursor, len * 4).split('\0').first;
    175     return bool(cursor);
    176   }
    177 
    178   DataExtractor de{ArrayRef<uint8_t>{}, false, 0};
    179   DataExtractor::Cursor cursor{0};
    180 
    181 private:
    182   MemoryBuffer *Buffer;
    183 };
    184 
    185 /// GCOVFile - Collects coverage information for one pair of coverage file
    186 /// (.gcno and .gcda).
    187 class GCOVFile {
    188 public:
    189   GCOVFile() = default;
    190 
    191   bool readGCNO(GCOVBuffer &Buffer);
    192   bool readGCDA(GCOVBuffer &Buffer);
    193   GCOV::GCOVVersion getVersion() const { return Version; }
    194   void print(raw_ostream &OS) const;
    195   void dump() const;
    196 
    197   std::vector<std::string> filenames;
    198   StringMap<unsigned> filenameToIdx;
    199 
    200 public:
    201   bool GCNOInitialized = false;
    202   GCOV::GCOVVersion Version;
    203   uint32_t Checksum = 0;
    204   StringRef cwd;
    205   SmallVector<std::unique_ptr<GCOVFunction>, 16> functions;
    206   std::map<uint32_t, GCOVFunction *> IdentToFunction;
    207   uint32_t RunCount = 0;
    208   uint32_t ProgramCount = 0;
    209 
    210   using iterator = pointee_iterator<
    211       SmallVectorImpl<std::unique_ptr<GCOVFunction>>::const_iterator>;
    212   iterator begin() const { return iterator(functions.begin()); }
    213   iterator end() const { return iterator(functions.end()); }
    214 };
    215 
    216 struct GCOVArc {
    217   GCOVArc(GCOVBlock &src, GCOVBlock &dst, uint32_t flags)
    218       : src(src), dst(dst), flags(flags) {}
    219   bool onTree() const;
    220 
    221   GCOVBlock &src;
    222   GCOVBlock &dst;
    223   uint32_t flags;
    224   uint64_t count = 0;
    225   uint64_t cycleCount = 0;
    226 };
    227 
    228 /// GCOVFunction - Collects function information.
    229 class GCOVFunction {
    230 public:
    231   using BlockIterator = pointee_iterator<
    232       SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
    233 
    234   GCOVFunction(GCOVFile &file) : file(file) {}
    235 
    236   StringRef getName(bool demangle) const;
    237   StringRef getFilename() const;
    238   uint64_t getEntryCount() const;
    239   GCOVBlock &getExitBlock() const;
    240 
    241   iterator_range<BlockIterator> blocksRange() const {
    242     return make_range(blocks.begin(), blocks.end());
    243   }
    244 
    245   uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred);
    246   void print(raw_ostream &OS) const;
    247   void dump() const;
    248 
    249   GCOVFile &file;
    250   uint32_t ident = 0;
    251   uint32_t linenoChecksum;
    252   uint32_t cfgChecksum = 0;
    253   uint32_t startLine = 0;
    254   uint32_t startColumn = 0;
    255   uint32_t endLine = 0;
    256   uint32_t endColumn = 0;
    257   uint8_t artificial = 0;
    258   StringRef Name;
    259   mutable SmallString<0> demangled;
    260   unsigned srcIdx;
    261   SmallVector<std::unique_ptr<GCOVBlock>, 0> blocks;
    262   SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs;
    263   DenseSet<const GCOVBlock *> visited;
    264 };
    265 
    266 /// GCOVBlock - Collects block information.
    267 class GCOVBlock {
    268 public:
    269   using EdgeIterator = SmallVectorImpl<GCOVArc *>::const_iterator;
    270   using BlockVector = SmallVector<const GCOVBlock *, 1>;
    271   using BlockVectorLists = SmallVector<BlockVector, 4>;
    272   using Edges = SmallVector<GCOVArc *, 4>;
    273 
    274   GCOVBlock(uint32_t N) : number(N) {}
    275 
    276   void addLine(uint32_t N) { lines.push_back(N); }
    277   uint32_t getLastLine() const { return lines.back(); }
    278   uint64_t getCount() const { return count; }
    279 
    280   void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
    281 
    282   void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); }
    283 
    284   iterator_range<EdgeIterator> srcs() const {
    285     return make_range(pred.begin(), pred.end());
    286   }
    287 
    288   iterator_range<EdgeIterator> dsts() const {
    289     return make_range(succ.begin(), succ.end());
    290   }
    291 
    292   void print(raw_ostream &OS) const;
    293   void dump() const;
    294 
    295   static uint64_t
    296   augmentOneCycle(GCOVBlock *src,
    297                   std::vector<std::pair<GCOVBlock *, size_t>> &stack);
    298   static uint64_t getCyclesCount(const BlockVector &blocks);
    299   static uint64_t getLineCount(const BlockVector &Blocks);
    300 
    301 public:
    302   uint32_t number;
    303   uint64_t count = 0;
    304   SmallVector<GCOVArc *, 2> pred;
    305   SmallVector<GCOVArc *, 2> succ;
    306   SmallVector<uint32_t, 4> lines;
    307   bool traversable = false;
    308   GCOVArc *incoming = nullptr;
    309 };
    310 
    311 void gcovOneInput(const GCOV::Options &options, StringRef filename,
    312                   StringRef gcno, StringRef gcda, GCOVFile &file);
    313 
    314 } // end namespace llvm
    315 
    316 #endif // LLVM_PROFILEDATA_GCOV_H
    317