1 //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This header provides the interface to read and write coverage files that
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_PROFILEDATA_GCOV_H
15 #define LLVM_PROFILEDATA_GCOV_H
17 #include "llvm/ADT/DenseMap.h"
18 #include "llvm/ADT/MapVector.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/ADT/iterator.h"
23 #include "llvm/ADT/iterator_range.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/raw_ostream.h"
43 enum GCOVVersion
{ V402
, V404
, V704
};
45 /// A struct for passing gcov options between functions.
47 Options(bool A
, bool B
, bool C
, bool F
, bool P
, bool U
, bool L
, bool N
, bool X
)
48 : AllBlocks(A
), BranchInfo(B
), BranchCount(C
), FuncCoverage(F
),
49 PreservePaths(P
), UncondBranch(U
), LongFileNames(L
), NoOutput(N
),
63 } // end namespace GCOV
65 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
69 GCOVBuffer(MemoryBuffer
*B
) : Buffer(B
) {}
71 /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
72 bool readGCNOFormat() {
73 StringRef File
= Buffer
->getBuffer().slice(0, 4);
75 errs() << "Unexpected file type: " << File
<< ".\n";
82 /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
83 bool readGCDAFormat() {
84 StringRef File
= Buffer
->getBuffer().slice(0, 4);
86 errs() << "Unexpected file type: " << File
<< ".\n";
93 /// readGCOVVersion - Read GCOV version.
94 bool readGCOVVersion(GCOV::GCOVVersion
&Version
) {
95 StringRef VersionStr
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
96 if (VersionStr
== "*204") {
101 if (VersionStr
== "*404") {
103 Version
= GCOV::V404
;
106 if (VersionStr
== "*704") {
108 Version
= GCOV::V704
;
111 errs() << "Unexpected version: " << VersionStr
<< ".\n";
115 /// readFunctionTag - If cursor points to a function tag then increment the
116 /// cursor and return true otherwise return false.
117 bool readFunctionTag() {
118 StringRef Tag
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
119 if (Tag
.empty() || Tag
[0] != '\0' || Tag
[1] != '\0' || Tag
[2] != '\0' ||
127 /// readBlockTag - If cursor points to a block tag then increment the
128 /// cursor and return true otherwise return false.
129 bool readBlockTag() {
130 StringRef Tag
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
131 if (Tag
.empty() || Tag
[0] != '\0' || Tag
[1] != '\0' || Tag
[2] != '\x41' ||
139 /// readEdgeTag - If cursor points to an edge tag then increment the
140 /// cursor and return true otherwise return false.
142 StringRef Tag
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
143 if (Tag
.empty() || Tag
[0] != '\0' || Tag
[1] != '\0' || Tag
[2] != '\x43' ||
151 /// readLineTag - If cursor points to a line tag then increment the
152 /// cursor and return true otherwise return false.
154 StringRef Tag
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
155 if (Tag
.empty() || Tag
[0] != '\0' || Tag
[1] != '\0' || Tag
[2] != '\x45' ||
163 /// readArcTag - If cursor points to an gcda arc tag then increment the
164 /// cursor and return true otherwise return false.
166 StringRef Tag
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
167 if (Tag
.empty() || Tag
[0] != '\0' || Tag
[1] != '\0' || Tag
[2] != '\xa1' ||
175 /// readObjectTag - If cursor points to an object summary tag then increment
176 /// the cursor and return true otherwise return false.
177 bool readObjectTag() {
178 StringRef Tag
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
179 if (Tag
.empty() || Tag
[0] != '\0' || Tag
[1] != '\0' || Tag
[2] != '\0' ||
187 /// readProgramTag - If cursor points to a program summary tag then increment
188 /// the cursor and return true otherwise return false.
189 bool readProgramTag() {
190 StringRef Tag
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
191 if (Tag
.empty() || Tag
[0] != '\0' || Tag
[1] != '\0' || Tag
[2] != '\0' ||
199 bool readInt(uint32_t &Val
) {
200 if (Buffer
->getBuffer().size() < Cursor
+ 4) {
201 errs() << "Unexpected end of memory buffer: " << Cursor
+ 4 << ".\n";
204 StringRef Str
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ 4);
206 Val
= *(const uint32_t *)(Str
.data());
210 bool readInt64(uint64_t &Val
) {
212 if (!readInt(Lo
) || !readInt(Hi
))
214 Val
= ((uint64_t)Hi
<< 32) | Lo
;
218 bool readString(StringRef
&Str
) {
220 // Keep reading until we find a non-zero length. This emulates gcov's
221 // behaviour, which appears to do the same.
226 if (Buffer
->getBuffer().size() < Cursor
+ Len
) {
227 errs() << "Unexpected end of memory buffer: " << Cursor
+ Len
<< ".\n";
230 Str
= Buffer
->getBuffer().slice(Cursor
, Cursor
+ Len
).split('\0').first
;
235 uint64_t getCursor() const { return Cursor
; }
236 void advanceCursor(uint32_t n
) { Cursor
+= n
* 4; }
239 MemoryBuffer
*Buffer
;
243 /// GCOVFile - Collects coverage information for one pair of coverage file
244 /// (.gcno and .gcda).
247 GCOVFile() = default;
249 bool readGCNO(GCOVBuffer
&Buffer
);
250 bool readGCDA(GCOVBuffer
&Buffer
);
251 uint32_t getChecksum() const { return Checksum
; }
252 void print(raw_ostream
&OS
) const;
254 void collectLineCounts(FileInfo
&FI
);
257 bool GCNOInitialized
= false;
258 GCOV::GCOVVersion Version
;
259 uint32_t Checksum
= 0;
260 SmallVector
<std::unique_ptr
<GCOVFunction
>, 16> Functions
;
261 uint32_t RunCount
= 0;
262 uint32_t ProgramCount
= 0;
265 /// GCOVEdge - Collects edge information.
267 GCOVEdge(GCOVBlock
&S
, GCOVBlock
&D
) : Src(S
), Dst(D
) {}
272 uint64_t CyclesCount
= 0;
275 /// GCOVFunction - Collects function information.
278 using BlockIterator
= pointee_iterator
<
279 SmallVectorImpl
<std::unique_ptr
<GCOVBlock
>>::const_iterator
>;
281 GCOVFunction(GCOVFile
&P
) : Parent(P
) {}
283 bool readGCNO(GCOVBuffer
&Buffer
, GCOV::GCOVVersion Version
);
284 bool readGCDA(GCOVBuffer
&Buffer
, GCOV::GCOVVersion Version
);
285 StringRef
getName() const { return Name
; }
286 StringRef
getFilename() const { return Filename
; }
287 size_t getNumBlocks() const { return Blocks
.size(); }
288 uint64_t getEntryCount() const;
289 uint64_t getExitCount() const;
291 BlockIterator
block_begin() const { return Blocks
.begin(); }
292 BlockIterator
block_end() const { return Blocks
.end(); }
293 iterator_range
<BlockIterator
> blocks() const {
294 return make_range(block_begin(), block_end());
297 void print(raw_ostream
&OS
) const;
299 void collectLineCounts(FileInfo
&FI
);
305 uint32_t LineNumber
= 0;
308 SmallVector
<std::unique_ptr
<GCOVBlock
>, 16> Blocks
;
309 SmallVector
<std::unique_ptr
<GCOVEdge
>, 16> Edges
;
312 /// GCOVBlock - Collects block information.
315 EdgeWeight(GCOVBlock
*D
) : Dst(D
) {}
322 using EdgeIterator
= SmallVectorImpl
<GCOVEdge
*>::const_iterator
;
323 using BlockVector
= SmallVector
<const GCOVBlock
*, 4>;
324 using BlockVectorLists
= SmallVector
<BlockVector
, 4>;
325 using Edges
= SmallVector
<GCOVEdge
*, 4>;
327 GCOVBlock(GCOVFunction
&P
, uint32_t N
) : Parent(P
), Number(N
) {}
330 const GCOVFunction
&getParent() const { return Parent
; }
331 void addLine(uint32_t N
) { Lines
.push_back(N
); }
332 uint32_t getLastLine() const { return Lines
.back(); }
333 void addCount(size_t DstEdgeNo
, uint64_t N
);
334 uint64_t getCount() const { return Counter
; }
336 void addSrcEdge(GCOVEdge
*Edge
) {
337 assert(&Edge
->Dst
== this); // up to caller to ensure edge is valid
338 SrcEdges
.push_back(Edge
);
341 void addDstEdge(GCOVEdge
*Edge
) {
342 assert(&Edge
->Src
== this); // up to caller to ensure edge is valid
343 // Check if adding this edge causes list to become unsorted.
344 if (DstEdges
.size() && DstEdges
.back()->Dst
.Number
> Edge
->Dst
.Number
)
345 DstEdgesAreSorted
= false;
346 DstEdges
.push_back(Edge
);
349 size_t getNumSrcEdges() const { return SrcEdges
.size(); }
350 size_t getNumDstEdges() const { return DstEdges
.size(); }
353 EdgeIterator
src_begin() const { return SrcEdges
.begin(); }
354 EdgeIterator
src_end() const { return SrcEdges
.end(); }
355 iterator_range
<EdgeIterator
> srcs() const {
356 return make_range(src_begin(), src_end());
359 EdgeIterator
dst_begin() const { return DstEdges
.begin(); }
360 EdgeIterator
dst_end() const { return DstEdges
.end(); }
361 iterator_range
<EdgeIterator
> dsts() const {
362 return make_range(dst_begin(), dst_end());
365 void print(raw_ostream
&OS
) const;
367 void collectLineCounts(FileInfo
&FI
);
369 static uint64_t getCycleCount(const Edges
&Path
);
370 static void unblock(const GCOVBlock
*U
, BlockVector
&Blocked
,
371 BlockVectorLists
&BlockLists
);
372 static bool lookForCircuit(const GCOVBlock
*V
, const GCOVBlock
*Start
,
373 Edges
&Path
, BlockVector
&Blocked
,
374 BlockVectorLists
&BlockLists
,
375 const BlockVector
&Blocks
, uint64_t &Count
);
376 static void getCyclesCount(const BlockVector
&Blocks
, uint64_t &Count
);
377 static uint64_t getLineCount(const BlockVector
&Blocks
);
380 GCOVFunction
&Parent
;
382 uint64_t Counter
= 0;
383 bool DstEdgesAreSorted
= true;
384 SmallVector
<GCOVEdge
*, 16> SrcEdges
;
385 SmallVector
<GCOVEdge
*, 16> DstEdges
;
386 SmallVector
<uint32_t, 16> Lines
;
391 // It is unlikely--but possible--for multiple functions to be on the same
393 // Therefore this typedef allows LineData.Functions to store multiple
395 // per instance. This is rare, however, so optimize for the common case.
396 using FunctionVector
= SmallVector
<const GCOVFunction
*, 1>;
397 using FunctionLines
= DenseMap
<uint32_t, FunctionVector
>;
398 using BlockVector
= SmallVector
<const GCOVBlock
*, 4>;
399 using BlockLines
= DenseMap
<uint32_t, BlockVector
>;
402 LineData() = default;
405 FunctionLines Functions
;
406 uint32_t LastLine
= 0;
409 struct GCOVCoverage
{
410 GCOVCoverage(StringRef Name
) : Name(Name
) {}
414 uint32_t LogicalLines
= 0;
415 uint32_t LinesExec
= 0;
417 uint32_t Branches
= 0;
418 uint32_t BranchesExec
= 0;
419 uint32_t BranchesTaken
= 0;
423 FileInfo(const GCOV::Options
&Options
) : Options(Options
) {}
425 void addBlockLine(StringRef Filename
, uint32_t Line
, const GCOVBlock
*Block
) {
426 if (Line
> LineInfo
[Filename
].LastLine
)
427 LineInfo
[Filename
].LastLine
= Line
;
428 LineInfo
[Filename
].Blocks
[Line
- 1].push_back(Block
);
431 void addFunctionLine(StringRef Filename
, uint32_t Line
,
432 const GCOVFunction
*Function
) {
433 if (Line
> LineInfo
[Filename
].LastLine
)
434 LineInfo
[Filename
].LastLine
= Line
;
435 LineInfo
[Filename
].Functions
[Line
- 1].push_back(Function
);
438 void setRunCount(uint32_t Runs
) { RunCount
= Runs
; }
439 void setProgramCount(uint32_t Programs
) { ProgramCount
= Programs
; }
440 void print(raw_ostream
&OS
, StringRef MainFilename
, StringRef GCNOFile
,
444 std::string
getCoveragePath(StringRef Filename
, StringRef MainFilename
);
445 std::unique_ptr
<raw_ostream
> openCoveragePath(StringRef CoveragePath
);
446 void printFunctionSummary(raw_ostream
&OS
, const FunctionVector
&Funcs
) const;
447 void printBlockInfo(raw_ostream
&OS
, const GCOVBlock
&Block
,
448 uint32_t LineIndex
, uint32_t &BlockNo
) const;
449 void printBranchInfo(raw_ostream
&OS
, const GCOVBlock
&Block
,
450 GCOVCoverage
&Coverage
, uint32_t &EdgeNo
);
451 void printUncondBranchInfo(raw_ostream
&OS
, uint32_t &EdgeNo
,
452 uint64_t Count
) const;
454 void printCoverage(raw_ostream
&OS
, const GCOVCoverage
&Coverage
) const;
455 void printFuncCoverage(raw_ostream
&OS
) const;
456 void printFileCoverage(raw_ostream
&OS
) const;
458 const GCOV::Options
&Options
;
459 StringMap
<LineData
> LineInfo
;
460 uint32_t RunCount
= 0;
461 uint32_t ProgramCount
= 0;
463 using FileCoverageList
= SmallVector
<std::pair
<std::string
, GCOVCoverage
>, 4>;
464 using FuncCoverageMap
= MapVector
<const GCOVFunction
*, GCOVCoverage
>;
466 FileCoverageList FileCoverages
;
467 FuncCoverageMap FuncCoverages
;
470 } // end namespace llvm
472 #endif // LLVM_SUPPORT_GCOV_H