Line data Source code
1 : //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This header provides the interface to read and write coverage files that
11 : // use 'gcov' format.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #ifndef LLVM_PROFILEDATA_GCOV_H
16 : #define LLVM_PROFILEDATA_GCOV_H
17 :
18 : #include "llvm/ADT/DenseMap.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/MemoryBuffer.h"
26 : #include "llvm/Support/raw_ostream.h"
27 : #include <algorithm>
28 : #include <cassert>
29 : #include <cstddef>
30 : #include <cstdint>
31 : #include <limits>
32 : #include <memory>
33 : #include <string>
34 : #include <utility>
35 :
36 : namespace llvm {
37 :
38 : class GCOVFunction;
39 : class GCOVBlock;
40 : class FileInfo;
41 :
42 : namespace GCOV {
43 :
44 : enum GCOVVersion { V402, V404, V704 };
45 :
46 : /// A struct for passing gcov options between functions.
47 : struct Options {
48 : Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
49 30 : : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
50 30 : PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
51 :
52 : bool AllBlocks;
53 : bool BranchInfo;
54 : bool BranchCount;
55 : bool FuncCoverage;
56 : bool PreservePaths;
57 : bool UncondBranch;
58 : bool LongFileNames;
59 : bool NoOutput;
60 : };
61 :
62 : } // end namespace GCOV
63 :
64 : /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
65 : /// read operations.
66 : class GCOVBuffer {
67 : public:
68 60 : GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
69 :
70 : /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
71 30 : bool readGCNOFormat() {
72 90 : StringRef File = Buffer->getBuffer().slice(0, 4);
73 : if (File != "oncg") {
74 0 : errs() << "Unexpected file type: " << File << ".\n";
75 0 : return false;
76 : }
77 30 : Cursor = 4;
78 30 : return true;
79 : }
80 :
81 : /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
82 30 : bool readGCDAFormat() {
83 90 : StringRef File = Buffer->getBuffer().slice(0, 4);
84 : if (File != "adcg") {
85 0 : errs() << "Unexpected file type: " << File << ".\n";
86 0 : return false;
87 : }
88 30 : Cursor = 4;
89 30 : return true;
90 : }
91 :
92 : /// readGCOVVersion - Read GCOV version.
93 60 : bool readGCOVVersion(GCOV::GCOVVersion &Version) {
94 180 : StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
95 : if (VersionStr == "*204") {
96 50 : Cursor += 4;
97 50 : Version = GCOV::V402;
98 50 : return true;
99 : }
100 : if (VersionStr == "*404") {
101 0 : Cursor += 4;
102 0 : Version = GCOV::V404;
103 0 : return true;
104 : }
105 : if (VersionStr == "*704") {
106 10 : Cursor += 4;
107 10 : Version = GCOV::V704;
108 10 : return true;
109 : }
110 0 : errs() << "Unexpected version: " << VersionStr << ".\n";
111 0 : return false;
112 : }
113 :
114 : /// readFunctionTag - If cursor points to a function tag then increment the
115 : /// cursor and return true otherwise return false.
116 406 : bool readFunctionTag() {
117 812 : StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
118 406 : if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
119 : Tag[3] != '\1') {
120 : return false;
121 : }
122 377 : Cursor += 4;
123 377 : return true;
124 : }
125 :
126 : /// readBlockTag - If cursor points to a block tag then increment the
127 : /// cursor and return true otherwise return false.
128 208 : bool readBlockTag() {
129 416 : StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
130 208 : if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' ||
131 : Tag[3] != '\x01') {
132 : return false;
133 : }
134 208 : Cursor += 4;
135 208 : return true;
136 : }
137 :
138 : /// readEdgeTag - If cursor points to an edge tag then increment the
139 : /// cursor and return true otherwise return false.
140 1089 : bool readEdgeTag() {
141 2178 : StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
142 1089 : if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' ||
143 : Tag[3] != '\x01') {
144 : return false;
145 : }
146 882 : Cursor += 4;
147 882 : return true;
148 : }
149 :
150 : /// readLineTag - If cursor points to a line tag then increment the
151 : /// cursor and return true otherwise return false.
152 1089 : bool readLineTag() {
153 2178 : StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
154 1089 : if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' ||
155 : Tag[3] != '\x01') {
156 : return false;
157 : }
158 882 : Cursor += 4;
159 882 : return true;
160 : }
161 :
162 : /// readArcTag - If cursor points to an gcda arc tag then increment the
163 : /// cursor and return true otherwise return false.
164 169 : bool readArcTag() {
165 338 : StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
166 169 : if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
167 : Tag[3] != '\1') {
168 : return false;
169 : }
170 169 : Cursor += 4;
171 169 : return true;
172 : }
173 :
174 : /// readObjectTag - If cursor points to an object summary tag then increment
175 : /// the cursor and return true otherwise return false.
176 20 : bool readObjectTag() {
177 40 : StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
178 20 : if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
179 : Tag[3] != '\xa1') {
180 : return false;
181 : }
182 20 : Cursor += 4;
183 20 : return true;
184 : }
185 :
186 : /// readProgramTag - If cursor points to a program summary tag then increment
187 : /// the cursor and return true otherwise return false.
188 40 : bool readProgramTag() {
189 80 : StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
190 40 : if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
191 : Tag[3] != '\xa3') {
192 : return false;
193 : }
194 20 : Cursor += 4;
195 20 : return true;
196 : }
197 :
198 15750 : bool readInt(uint32_t &Val) {
199 31500 : if (Buffer->getBuffer().size() < Cursor + 4) {
200 1 : errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
201 1 : return false;
202 : }
203 15749 : StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
204 15749 : Cursor += 4;
205 15749 : Val = *(const uint32_t *)(Str.data());
206 15749 : return true;
207 : }
208 :
209 1003 : bool readInt64(uint64_t &Val) {
210 : uint32_t Lo, Hi;
211 1003 : if (!readInt(Lo) || !readInt(Hi))
212 0 : return false;
213 1003 : Val = ((uint64_t)Hi << 32) | Lo;
214 1003 : return true;
215 : }
216 :
217 1300 : bool readString(StringRef &Str) {
218 1300 : uint32_t Len = 0;
219 : // Keep reading until we find a non-zero length. This emulates gcov's
220 : // behaviour, which appears to do the same.
221 2600 : while (Len == 0)
222 1300 : if (!readInt(Len))
223 : return false;
224 1300 : Len *= 4;
225 2600 : if (Buffer->getBuffer().size() < Cursor + Len) {
226 0 : errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n";
227 0 : return false;
228 : }
229 2600 : Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first;
230 1300 : Cursor += Len;
231 1300 : return true;
232 : }
233 :
234 0 : uint64_t getCursor() const { return Cursor; }
235 40 : void advanceCursor(uint32_t n) { Cursor += n * 4; }
236 :
237 : private:
238 : MemoryBuffer *Buffer;
239 : uint64_t Cursor = 0;
240 : };
241 :
242 : /// GCOVFile - Collects coverage information for one pair of coverage file
243 : /// (.gcno and .gcda).
244 30 : class GCOVFile {
245 : public:
246 60 : GCOVFile() = default;
247 :
248 : bool readGCNO(GCOVBuffer &Buffer);
249 : bool readGCDA(GCOVBuffer &Buffer);
250 0 : uint32_t getChecksum() const { return Checksum; }
251 : void print(raw_ostream &OS) const;
252 : void dump() const;
253 : void collectLineCounts(FileInfo &FI);
254 :
255 : private:
256 : bool GCNOInitialized = false;
257 : GCOV::GCOVVersion Version;
258 : uint32_t Checksum = 0;
259 : SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
260 : uint32_t RunCount = 0;
261 : uint32_t ProgramCount = 0;
262 : };
263 :
264 : /// GCOVEdge - Collects edge information.
265 : struct GCOVEdge {
266 1058 : GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
267 :
268 : GCOVBlock &Src;
269 : GCOVBlock &Dst;
270 : uint64_t Count = 0;
271 : uint64_t CyclesCount = 0;
272 : };
273 :
274 : /// GCOVFunction - Collects function information.
275 0 : class GCOVFunction {
276 : public:
277 : using BlockIterator = pointee_iterator<
278 : SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
279 :
280 208 : GCOVFunction(GCOVFile &P) : Parent(P) {}
281 :
282 : bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
283 : bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
284 0 : StringRef getName() const { return Name; }
285 0 : StringRef getFilename() const { return Filename; }
286 40 : size_t getNumBlocks() const { return Blocks.size(); }
287 : uint64_t getEntryCount() const;
288 : uint64_t getExitCount() const;
289 :
290 : BlockIterator block_begin() const { return Blocks.begin(); }
291 : BlockIterator block_end() const { return Blocks.end(); }
292 : iterator_range<BlockIterator> blocks() const {
293 : return make_range(block_begin(), block_end());
294 : }
295 :
296 : void print(raw_ostream &OS) const;
297 : void dump() const;
298 : void collectLineCounts(FileInfo &FI);
299 :
300 : private:
301 : GCOVFile &Parent;
302 : uint32_t Ident = 0;
303 : uint32_t Checksum;
304 : uint32_t LineNumber = 0;
305 : StringRef Name;
306 : StringRef Filename;
307 : SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
308 : SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
309 : };
310 :
311 : /// GCOVBlock - Collects block information.
312 : class GCOVBlock {
313 : struct EdgeWeight {
314 : EdgeWeight(GCOVBlock *D) : Dst(D) {}
315 :
316 : GCOVBlock *Dst;
317 : uint64_t Count = 0;
318 : };
319 :
320 : struct SortDstEdgesFunctor {
321 0 : bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
322 144 : return E1->Dst.Number < E2->Dst.Number;
323 : }
324 : };
325 :
326 : public:
327 : using EdgeIterator = SmallVectorImpl<GCOVEdge *>::const_iterator;
328 : using BlockVector = SmallVector<const GCOVBlock *, 4>;
329 : using BlockVectorLists = SmallVector<BlockVector, 4>;
330 : using Edges = SmallVector<GCOVEdge *, 4>;
331 :
332 0 : GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
333 : ~GCOVBlock();
334 :
335 0 : const GCOVFunction &getParent() const { return Parent; }
336 990 : void addLine(uint32_t N) { Lines.push_back(N); }
337 892 : uint32_t getLastLine() const { return Lines.back(); }
338 : void addCount(size_t DstEdgeNo, uint64_t N);
339 0 : uint64_t getCount() const { return Counter; }
340 :
341 : void addSrcEdge(GCOVEdge *Edge) {
342 : assert(&Edge->Dst == this); // up to caller to ensure edge is valid
343 1058 : SrcEdges.push_back(Edge);
344 : }
345 :
346 1058 : void addDstEdge(GCOVEdge *Edge) {
347 : assert(&Edge->Src == this); // up to caller to ensure edge is valid
348 : // Check if adding this edge causes list to become unsorted.
349 2116 : if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
350 23 : DstEdgesAreSorted = false;
351 1058 : DstEdges.push_back(Edge);
352 1058 : }
353 :
354 892 : size_t getNumSrcEdges() const { return SrcEdges.size(); }
355 1950 : size_t getNumDstEdges() const { return DstEdges.size(); }
356 : void sortDstEdges();
357 :
358 : EdgeIterator src_begin() const { return SrcEdges.begin(); }
359 : EdgeIterator src_end() const { return SrcEdges.end(); }
360 : iterator_range<EdgeIterator> srcs() const {
361 : return make_range(src_begin(), src_end());
362 : }
363 :
364 : EdgeIterator dst_begin() const { return DstEdges.begin(); }
365 : EdgeIterator dst_end() const { return DstEdges.end(); }
366 : iterator_range<EdgeIterator> dsts() const {
367 : return make_range(dst_begin(), dst_end());
368 : }
369 :
370 : void print(raw_ostream &OS) const;
371 : void dump() const;
372 : void collectLineCounts(FileInfo &FI);
373 :
374 : static uint64_t getCycleCount(const Edges &Path);
375 : static void unblock(const GCOVBlock *U, BlockVector &Blocked,
376 : BlockVectorLists &BlockLists);
377 : static bool lookForCircuit(const GCOVBlock *V, const GCOVBlock *Start,
378 : Edges &Path, BlockVector &Blocked,
379 : BlockVectorLists &BlockLists,
380 : const BlockVector &Blocks, uint64_t &Count);
381 : static void getCyclesCount(const BlockVector &Blocks, uint64_t &Count);
382 : static uint64_t getLineCount(const BlockVector &Blocks);
383 :
384 : private:
385 : GCOVFunction &Parent;
386 : uint32_t Number;
387 : uint64_t Counter = 0;
388 : bool DstEdgesAreSorted = true;
389 : SmallVector<GCOVEdge *, 16> SrcEdges;
390 : SmallVector<GCOVEdge *, 16> DstEdges;
391 : SmallVector<uint32_t, 16> Lines;
392 : };
393 :
394 : class FileInfo {
395 : protected:
396 : // It is unlikely--but possible--for multiple functions to be on the same
397 : // line.
398 : // Therefore this typedef allows LineData.Functions to store multiple
399 : // functions
400 : // per instance. This is rare, however, so optimize for the common case.
401 : using FunctionVector = SmallVector<const GCOVFunction *, 1>;
402 : using FunctionLines = DenseMap<uint32_t, FunctionVector>;
403 : using BlockVector = SmallVector<const GCOVBlock *, 4>;
404 : using BlockLines = DenseMap<uint32_t, BlockVector>;
405 :
406 : struct LineData {
407 44 : LineData() = default;
408 :
409 : BlockLines Blocks;
410 : FunctionLines Functions;
411 : uint32_t LastLine = 0;
412 : };
413 :
414 : struct GCOVCoverage {
415 44 : GCOVCoverage(StringRef Name) : Name(Name) {}
416 :
417 : StringRef Name;
418 :
419 : uint32_t LogicalLines = 0;
420 : uint32_t LinesExec = 0;
421 :
422 : uint32_t Branches = 0;
423 : uint32_t BranchesExec = 0;
424 : uint32_t BranchesTaken = 0;
425 : };
426 :
427 : public:
428 54 : FileInfo(const GCOV::Options &Options) : Options(Options) {}
429 :
430 892 : void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
431 892 : if (Line > LineInfo[Filename].LastLine)
432 698 : LineInfo[Filename].LastLine = Line;
433 892 : LineInfo[Filename].Blocks[Line - 1].push_back(Block);
434 892 : }
435 :
436 185 : void addFunctionLine(StringRef Filename, uint32_t Line,
437 : const GCOVFunction *Function) {
438 185 : if (Line > LineInfo[Filename].LastLine)
439 0 : LineInfo[Filename].LastLine = Line;
440 185 : LineInfo[Filename].Functions[Line - 1].push_back(Function);
441 185 : }
442 :
443 27 : void setRunCount(uint32_t Runs) { RunCount = Runs; }
444 27 : void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
445 : void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
446 : StringRef GCDAFile);
447 :
448 : protected:
449 : std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
450 : std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath);
451 : void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const;
452 : void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
453 : uint32_t LineIndex, uint32_t &BlockNo) const;
454 : void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
455 : GCOVCoverage &Coverage, uint32_t &EdgeNo);
456 : void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
457 : uint64_t Count) const;
458 :
459 : void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const;
460 : void printFuncCoverage(raw_ostream &OS) const;
461 : void printFileCoverage(raw_ostream &OS) const;
462 :
463 : const GCOV::Options &Options;
464 : StringMap<LineData> LineInfo;
465 : uint32_t RunCount = 0;
466 : uint32_t ProgramCount = 0;
467 :
468 : using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>;
469 : using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>;
470 :
471 : FileCoverageList FileCoverages;
472 : FuncCoverageMap FuncCoverages;
473 : };
474 :
475 : } // end namespace llvm
476 :
477 : #endif // LLVM_SUPPORT_GCOV_H
|