GCOV.h 9.3 KB

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