xref: /netbsd-src/external/apache2/llvm/dist/llvm/include/llvm/ProfileData/GCOV.h (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 {
OptionsOptions49   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:
GCOVBuffer(MemoryBuffer * B)78   GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
~GCOVBuffer()79   ~GCOVBuffer() { consumeError(cursor.takeError()); }
80 
81   /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
readGCNOFormat()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.
readGCDAFormat()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.
readGCOVVersion(GCOV::GCOVVersion & 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 
getWord()144   uint32_t getWord() { return de.getU32(cursor); }
getString()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 
readInt(uint32_t & Val)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 
readInt64(uint64_t & Val)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 
readString(StringRef & Str)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);
getVersion()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>;
begin()212   iterator begin() const { return iterator(functions.begin()); }
end()213   iterator end() const { return iterator(functions.end()); }
214 };
215 
216 struct GCOVArc {
GCOVArcGCOVArc217   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 
GCOVFunction(GCOVFile & file)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 
blocksRange()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 
GCOVBlock(uint32_t N)274   GCOVBlock(uint32_t N) : number(N) {}
275 
addLine(uint32_t N)276   void addLine(uint32_t N) { lines.push_back(N); }
getLastLine()277   uint32_t getLastLine() const { return lines.back(); }
getCount()278   uint64_t getCount() const { return count; }
279 
addSrcEdge(GCOVArc * Edge)280   void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
281 
addDstEdge(GCOVArc * Edge)282   void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); }
283 
srcs()284   iterator_range<EdgeIterator> srcs() const {
285     return make_range(pred.begin(), pred.end());
286   }
287 
dsts()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