Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:23

0001 //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This header provides the interface to read and write coverage files that
0010 // use 'gcov' format.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_PROFILEDATA_GCOV_H
0015 #define LLVM_PROFILEDATA_GCOV_H
0016 
0017 #include "llvm/ADT/DenseSet.h"
0018 #include "llvm/ADT/SmallString.h"
0019 #include "llvm/ADT/SmallVector.h"
0020 #include "llvm/ADT/StringMap.h"
0021 #include "llvm/ADT/StringRef.h"
0022 #include "llvm/ADT/iterator.h"
0023 #include "llvm/ADT/iterator_range.h"
0024 #include "llvm/Support/DataExtractor.h"
0025 #include "llvm/Support/MemoryBuffer.h"
0026 #include "llvm/Support/raw_ostream.h"
0027 #include <algorithm>
0028 #include <cstddef>
0029 #include <cstdint>
0030 #include <map>
0031 #include <memory>
0032 #include <string>
0033 #include <utility>
0034 
0035 namespace llvm {
0036 
0037 class GCOVFunction;
0038 class GCOVBlock;
0039 
0040 namespace GCOV {
0041 
0042 enum GCOVVersion { V304, V407, V408, V800, V900, V1200 };
0043 
0044 /// A struct for passing gcov options between functions.
0045 struct Options {
0046   Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L,
0047           bool M, bool N, bool R, bool T, bool X, std::string SourcePrefix)
0048       : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
0049         PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L),
0050         Demangle(M), NoOutput(N), RelativeOnly(R), UseStdout(T),
0051         HashFilenames(X), SourcePrefix(std::move(SourcePrefix)) {}
0052 
0053   bool AllBlocks;
0054   bool BranchInfo;
0055   bool BranchCount;
0056   bool FuncCoverage;
0057   bool PreservePaths;
0058   bool UncondBranch;
0059   bool Intermediate;
0060   bool LongFileNames;
0061   bool Demangle;
0062   bool NoOutput;
0063   bool RelativeOnly;
0064   bool UseStdout;
0065   bool HashFilenames;
0066   std::string SourcePrefix;
0067 };
0068 
0069 } // end namespace GCOV
0070 
0071 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
0072 /// read operations.
0073 class GCOVBuffer {
0074 public:
0075   GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
0076   ~GCOVBuffer() { consumeError(cursor.takeError()); }
0077 
0078   /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
0079   bool readGCNOFormat() {
0080     StringRef buf = Buffer->getBuffer();
0081     StringRef magic = buf.substr(0, 4);
0082     if (magic == "gcno") {
0083       de = DataExtractor(buf.substr(4), false, 0);
0084     } else if (magic == "oncg") {
0085       de = DataExtractor(buf.substr(4), true, 0);
0086     } else {
0087       errs() << "unexpected magic: " << magic << "\n";
0088       return false;
0089     }
0090     return true;
0091   }
0092 
0093   /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
0094   bool readGCDAFormat() {
0095     StringRef buf = Buffer->getBuffer();
0096     StringRef magic = buf.substr(0, 4);
0097     if (magic == "gcda") {
0098       de = DataExtractor(buf.substr(4), false, 0);
0099     } else if (magic == "adcg") {
0100       de = DataExtractor(buf.substr(4), true, 0);
0101     } else {
0102       return false;
0103     }
0104     return true;
0105   }
0106 
0107   /// readGCOVVersion - Read GCOV version.
0108   bool readGCOVVersion(GCOV::GCOVVersion &version) {
0109     std::string str(de.getBytes(cursor, 4));
0110     if (str.size() != 4)
0111       return false;
0112     if (de.isLittleEndian())
0113       std::reverse(str.begin(), str.end());
0114     int ver = str[0] >= 'A'
0115                   ? (str[0] - 'A') * 100 + (str[1] - '0') * 10 + str[2] - '0'
0116                   : (str[0] - '0') * 10 + str[2] - '0';
0117     if (ver >= 120) {
0118       this->version = version = GCOV::V1200;
0119       return true;
0120     } else if (ver >= 90) {
0121       // PR gcov-profile/84846, r269678
0122       this->version = version = GCOV::V900;
0123       return true;
0124     } else if (ver >= 80) {
0125       // PR gcov-profile/48463
0126       this->version = version = GCOV::V800;
0127       return true;
0128     } else if (ver >= 48) {
0129       // r189778: the exit block moved from the last to the second.
0130       this->version = version = GCOV::V408;
0131       return true;
0132     } else if (ver >= 47) {
0133       // r173147: split checksum into cfg checksum and line checksum.
0134       this->version = version = GCOV::V407;
0135       return true;
0136     } else if (ver >= 34) {
0137       this->version = version = GCOV::V304;
0138       return true;
0139     }
0140     errs() << "unexpected version: " << str << "\n";
0141     return false;
0142   }
0143 
0144   uint32_t getWord() { return de.getU32(cursor); }
0145   StringRef getString() {
0146     uint32_t len;
0147     if (!readInt(len) || len == 0)
0148       return {};
0149     return de.getBytes(cursor, len * 4).split('\0').first;
0150   }
0151 
0152   bool readInt(uint32_t &Val) {
0153     if (cursor.tell() + 4 > de.size()) {
0154       Val = 0;
0155       errs() << "unexpected end of memory buffer: " << cursor.tell() << "\n";
0156       return false;
0157     }
0158     Val = de.getU32(cursor);
0159     return true;
0160   }
0161 
0162   bool readInt64(uint64_t &Val) {
0163     uint32_t Lo, Hi;
0164     if (!readInt(Lo) || !readInt(Hi))
0165       return false;
0166     Val = ((uint64_t)Hi << 32) | Lo;
0167     return true;
0168   }
0169 
0170   bool readString(StringRef &str) {
0171     uint32_t len;
0172     if (!readInt(len) || len == 0)
0173       return false;
0174     if (version >= GCOV::V1200)
0175       str = de.getBytes(cursor, len).drop_back();
0176     else
0177       str = de.getBytes(cursor, len * 4).split('\0').first;
0178     return bool(cursor);
0179   }
0180 
0181   DataExtractor de{ArrayRef<uint8_t>{}, false, 0};
0182   DataExtractor::Cursor cursor{0};
0183 
0184 private:
0185   MemoryBuffer *Buffer;
0186   GCOV::GCOVVersion version{};
0187 };
0188 
0189 /// GCOVFile - Collects coverage information for one pair of coverage file
0190 /// (.gcno and .gcda).
0191 class GCOVFile {
0192 public:
0193   GCOVFile() = default;
0194 
0195   bool readGCNO(GCOVBuffer &Buffer);
0196   bool readGCDA(GCOVBuffer &Buffer);
0197   GCOV::GCOVVersion getVersion() const { return version; }
0198   void print(raw_ostream &OS) const;
0199   void dump() const;
0200 
0201   std::vector<std::string> filenames;
0202   StringMap<unsigned> filenameToIdx;
0203 
0204 public:
0205   bool GCNOInitialized = false;
0206   GCOV::GCOVVersion version{};
0207   uint32_t checksum = 0;
0208   StringRef cwd;
0209   SmallVector<std::unique_ptr<GCOVFunction>, 16> functions;
0210   std::map<uint32_t, GCOVFunction *> identToFunction;
0211   uint32_t runCount = 0;
0212   uint32_t programCount = 0;
0213 
0214   using iterator = pointee_iterator<
0215       SmallVectorImpl<std::unique_ptr<GCOVFunction>>::const_iterator>;
0216   iterator begin() const { return iterator(functions.begin()); }
0217   iterator end() const { return iterator(functions.end()); }
0218 
0219 private:
0220   unsigned addNormalizedPathToMap(StringRef filename);
0221 };
0222 
0223 struct GCOVArc {
0224   GCOVArc(GCOVBlock &src, GCOVBlock &dst, uint32_t flags)
0225       : src(src), dst(dst), flags(flags) {}
0226   bool onTree() const;
0227 
0228   GCOVBlock &src;
0229   GCOVBlock &dst;
0230   uint32_t flags;
0231   uint64_t count = 0;
0232   uint64_t cycleCount = 0;
0233 };
0234 
0235 /// GCOVFunction - Collects function information.
0236 class GCOVFunction {
0237 public:
0238   using BlockIterator = pointee_iterator<
0239       SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
0240 
0241   GCOVFunction(GCOVFile &file) : file(file) {}
0242 
0243   StringRef getName(bool demangle) const;
0244   StringRef getFilename() const;
0245   uint64_t getEntryCount() const;
0246   GCOVBlock &getExitBlock() const;
0247 
0248   iterator_range<BlockIterator> blocksRange() const {
0249     return make_range(blocks.begin(), blocks.end());
0250   }
0251 
0252   void propagateCounts(const GCOVBlock &v, GCOVArc *pred);
0253   void print(raw_ostream &OS) const;
0254   void dump() const;
0255 
0256   GCOVFile &file;
0257   uint32_t ident = 0;
0258   uint32_t linenoChecksum;
0259   uint32_t cfgChecksum = 0;
0260   uint32_t startLine = 0;
0261   uint32_t startColumn = 0;
0262   uint32_t endLine = 0;
0263   uint32_t endColumn = 0;
0264   uint8_t artificial = 0;
0265   StringRef Name;
0266   mutable SmallString<0> demangled;
0267   unsigned srcIdx;
0268   SmallVector<std::unique_ptr<GCOVBlock>, 0> blocks;
0269   SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs;
0270   DenseSet<const GCOVBlock *> visited;
0271 };
0272 
0273 /// GCOVBlock - Collects block information.
0274 class GCOVBlock {
0275 public:
0276   using EdgeIterator = SmallVectorImpl<GCOVArc *>::const_iterator;
0277   using BlockVector = SmallVector<const GCOVBlock *, 1>;
0278   using BlockVectorLists = SmallVector<BlockVector, 4>;
0279   using Edges = SmallVector<GCOVArc *, 4>;
0280 
0281   GCOVBlock(uint32_t N) : number(N) {}
0282 
0283   void addLine(uint32_t N) { lines.push_back(N); }
0284   uint32_t getLastLine() const { return lines.back(); }
0285   uint64_t getCount() const { return count; }
0286 
0287   void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
0288 
0289   void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); }
0290 
0291   iterator_range<EdgeIterator> srcs() const {
0292     return make_range(pred.begin(), pred.end());
0293   }
0294 
0295   iterator_range<EdgeIterator> dsts() const {
0296     return make_range(succ.begin(), succ.end());
0297   }
0298 
0299   void print(raw_ostream &OS) const;
0300   void dump() const;
0301 
0302   static uint64_t
0303   augmentOneCycle(GCOVBlock *src,
0304                   std::vector<std::pair<GCOVBlock *, size_t>> &stack);
0305   static uint64_t getCyclesCount(const BlockVector &blocks);
0306   static uint64_t getLineCount(const BlockVector &Blocks);
0307 
0308 public:
0309   uint32_t number;
0310   uint64_t count = 0;
0311   SmallVector<GCOVArc *, 2> pred;
0312   SmallVector<GCOVArc *, 2> succ;
0313   SmallVector<uint32_t, 4> lines;
0314   bool traversable = false;
0315   GCOVArc *incoming = nullptr;
0316 };
0317 
0318 void gcovOneInput(const GCOV::Options &options, StringRef filename,
0319                   StringRef gcno, StringRef gcda, GCOVFile &file);
0320 
0321 } // end namespace llvm
0322 
0323 #endif // LLVM_PROFILEDATA_GCOV_H