1 //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This header provides the interface to read and write coverage files that
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_PROFILEDATA_GCOV_H
16 #define LLVM_PROFILEDATA_GCOV_H
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"
44 enum GCOVVersion { V402, V404, V704 };
46 /// A struct for passing gcov options between functions.
48 Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
49 : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
50 PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
62 } // end namespace GCOV
64 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
68 GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
70 /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
71 bool readGCNOFormat() {
72 StringRef File = Buffer->getBuffer().slice(0, 4);
74 errs() << "Unexpected file type: " << File << ".\n";
81 /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
82 bool readGCDAFormat() {
83 StringRef File = Buffer->getBuffer().slice(0, 4);
85 errs() << "Unexpected file type: " << File << ".\n";
92 /// readGCOVVersion - Read GCOV version.
93 bool readGCOVVersion(GCOV::GCOVVersion &Version) {
94 StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
95 if (VersionStr == "*204") {
100 if (VersionStr == "*404") {
102 Version = GCOV::V404;
105 if (VersionStr == "*704") {
107 Version = GCOV::V704;
110 errs() << "Unexpected version: " << VersionStr << ".\n";
114 /// readFunctionTag - If cursor points to a function tag then increment the
115 /// cursor and return true otherwise return false.
116 bool readFunctionTag() {
117 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
118 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
126 /// readBlockTag - If cursor points to a block tag then increment the
127 /// cursor and return true otherwise return false.
128 bool readBlockTag() {
129 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
130 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' ||
138 /// readEdgeTag - If cursor points to an edge tag then increment the
139 /// cursor and return true otherwise return false.
141 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
142 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' ||
150 /// readLineTag - If cursor points to a line tag then increment the
151 /// cursor and return true otherwise return false.
153 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
154 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' ||
162 /// readArcTag - If cursor points to an gcda arc tag then increment the
163 /// cursor and return true otherwise return false.
165 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
166 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
174 /// readObjectTag - If cursor points to an object summary tag then increment
175 /// the cursor and return true otherwise return false.
176 bool readObjectTag() {
177 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
178 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
186 /// readProgramTag - If cursor points to a program summary tag then increment
187 /// the cursor and return true otherwise return false.
188 bool readProgramTag() {
189 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
190 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
198 bool readInt(uint32_t &Val) {
199 if (Buffer->getBuffer().size() < Cursor + 4) {
200 errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
203 StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
205 Val = *(const uint32_t *)(Str.data());
209 bool readInt64(uint64_t &Val) {
211 if (!readInt(Lo) || !readInt(Hi))
213 Val = ((uint64_t)Hi << 32) | Lo;
217 bool readString(StringRef &Str) {
219 // Keep reading until we find a non-zero length. This emulates gcov's
220 // behaviour, which appears to do the same.
225 if (Buffer->getBuffer().size() < Cursor + Len) {
226 errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n";
229 Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first;
234 uint64_t getCursor() const { return Cursor; }
235 void advanceCursor(uint32_t n) { Cursor += n * 4; }
238 MemoryBuffer *Buffer;
242 /// GCOVFile - Collects coverage information for one pair of coverage file
243 /// (.gcno and .gcda).
246 GCOVFile() = default;
248 bool readGCNO(GCOVBuffer &Buffer);
249 bool readGCDA(GCOVBuffer &Buffer);
250 uint32_t getChecksum() const { return Checksum; }
251 void print(raw_ostream &OS) const;
253 void collectLineCounts(FileInfo &FI);
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;
264 /// GCOVEdge - Collects edge information.
266 GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
271 uint64_t CyclesCount = 0;
274 /// GCOVFunction - Collects function information.
277 using BlockIterator = pointee_iterator<
278 SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
280 GCOVFunction(GCOVFile &P) : Parent(P) {}
282 bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
283 bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
284 StringRef getName() const { return Name; }
285 StringRef getFilename() const { return Filename; }
286 size_t getNumBlocks() const { return Blocks.size(); }
287 uint64_t getEntryCount() const;
288 uint64_t getExitCount() const;
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());
296 void print(raw_ostream &OS) const;
298 void collectLineCounts(FileInfo &FI);
304 uint32_t LineNumber = 0;
307 SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
308 SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
311 /// GCOVBlock - Collects block information.
314 EdgeWeight(GCOVBlock *D) : Dst(D) {}
320 struct SortDstEdgesFunctor {
321 bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
322 return E1->Dst.Number < E2->Dst.Number;
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>;
332 GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
335 const GCOVFunction &getParent() const { return Parent; }
336 void addLine(uint32_t N) { Lines.push_back(N); }
337 uint32_t getLastLine() const { return Lines.back(); }
338 void addCount(size_t DstEdgeNo, uint64_t N);
339 uint64_t getCount() const { return Counter; }
341 void addSrcEdge(GCOVEdge *Edge) {
342 assert(&Edge->Dst == this); // up to caller to ensure edge is valid
343 SrcEdges.push_back(Edge);
346 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 if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
350 DstEdgesAreSorted = false;
351 DstEdges.push_back(Edge);
354 size_t getNumSrcEdges() const { return SrcEdges.size(); }
355 size_t getNumDstEdges() const { return DstEdges.size(); }
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());
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());
370 void print(raw_ostream &OS) const;
372 void collectLineCounts(FileInfo &FI);
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);
385 GCOVFunction &Parent;
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;
396 // It is unlikely--but possible--for multiple functions to be on the same
398 // Therefore this typedef allows LineData.Functions to store multiple
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>;
407 LineData() = default;
410 FunctionLines Functions;
411 uint32_t LastLine = 0;
414 struct GCOVCoverage {
415 GCOVCoverage(StringRef Name) : Name(Name) {}
419 uint32_t LogicalLines = 0;
420 uint32_t LinesExec = 0;
422 uint32_t Branches = 0;
423 uint32_t BranchesExec = 0;
424 uint32_t BranchesTaken = 0;
428 FileInfo(const GCOV::Options &Options) : Options(Options) {}
430 void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
431 if (Line > LineInfo[Filename].LastLine)
432 LineInfo[Filename].LastLine = Line;
433 LineInfo[Filename].Blocks[Line - 1].push_back(Block);
436 void addFunctionLine(StringRef Filename, uint32_t Line,
437 const GCOVFunction *Function) {
438 if (Line > LineInfo[Filename].LastLine)
439 LineInfo[Filename].LastLine = Line;
440 LineInfo[Filename].Functions[Line - 1].push_back(Function);
443 void setRunCount(uint32_t Runs) { RunCount = Runs; }
444 void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
445 void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
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;
459 void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const;
460 void printFuncCoverage(raw_ostream &OS) const;
461 void printFileCoverage(raw_ostream &OS) const;
463 const GCOV::Options &Options;
464 StringMap<LineData> LineInfo;
465 uint32_t RunCount = 0;
466 uint32_t ProgramCount = 0;
468 using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>;
469 using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>;
471 FileCoverageList FileCoverages;
472 FuncCoverageMap FuncCoverages;
475 } // end namespace llvm
477 #endif // LLVM_SUPPORT_GCOV_H