Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

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