File indexing completed on 2026-05-10 08:44:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
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 }
0070
0071
0072
0073 class GCOVBuffer {
0074 public:
0075 GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
0076 ~GCOVBuffer() { consumeError(cursor.takeError()); }
0077
0078
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
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
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
0122 this->version = version = GCOV::V900;
0123 return true;
0124 } else if (ver >= 80) {
0125
0126 this->version = version = GCOV::V800;
0127 return true;
0128 } else if (ver >= 48) {
0129
0130 this->version = version = GCOV::V408;
0131 return true;
0132 } else if (ver >= 47) {
0133
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
0190
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
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
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 }
0322
0323 #endif