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_SUPPORT_GCOV_H
16 #define LLVM_SUPPORT_GCOV_H
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/iterator.h"
20 #include "llvm/ADT/iterator_range.h"
21 #include "llvm/ADT/MapVector.h"
22 #include "llvm/ADT/SmallVector.h"
23 #include "llvm/ADT/StringMap.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/raw_ostream.h"
42 enum GCOVVersion { V402, V404, V704 };
44 /// \brief A struct for passing gcov options between functions.
46 Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N)
47 : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
48 PreservePaths(P), UncondBranch(U), LongFileNames(L), NoOutput(N) {}
60 } // end namespace GCOV
62 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
66 GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
68 /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
69 bool readGCNOFormat() {
70 StringRef File = Buffer->getBuffer().slice(0, 4);
72 errs() << "Unexpected file type: " << File << ".\n";
79 /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
80 bool readGCDAFormat() {
81 StringRef File = Buffer->getBuffer().slice(0, 4);
83 errs() << "Unexpected file type: " << File << ".\n";
90 /// readGCOVVersion - Read GCOV version.
91 bool readGCOVVersion(GCOV::GCOVVersion &Version) {
92 StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
93 if (VersionStr == "*204") {
98 if (VersionStr == "*404") {
100 Version = GCOV::V404;
103 if (VersionStr == "*704") {
105 Version = GCOV::V704;
108 errs() << "Unexpected version: " << VersionStr << ".\n";
112 /// readFunctionTag - If cursor points to a function tag then increment the
113 /// cursor and return true otherwise return false.
114 bool readFunctionTag() {
115 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
116 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
124 /// readBlockTag - If cursor points to a block tag then increment the
125 /// cursor and return true otherwise return false.
126 bool readBlockTag() {
127 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
128 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x41' ||
136 /// readEdgeTag - If cursor points to an edge tag then increment the
137 /// cursor and return true otherwise return false.
139 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
140 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x43' ||
148 /// readLineTag - If cursor points to a line tag then increment the
149 /// cursor and return true otherwise return false.
151 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
152 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\x45' ||
160 /// readArcTag - If cursor points to an gcda arc tag then increment the
161 /// cursor and return true otherwise return false.
163 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
164 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
172 /// readObjectTag - If cursor points to an object summary tag then increment
173 /// the cursor and return true otherwise return false.
174 bool readObjectTag() {
175 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
176 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
184 /// readProgramTag - If cursor points to a program summary tag then increment
185 /// the cursor and return true otherwise return false.
186 bool readProgramTag() {
187 StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
188 if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
196 bool readInt(uint32_t &Val) {
197 if (Buffer->getBuffer().size() < Cursor + 4) {
198 errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
201 StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
203 Val = *(const uint32_t *)(Str.data());
207 bool readInt64(uint64_t &Val) {
209 if (!readInt(Lo) || !readInt(Hi))
211 Val = ((uint64_t)Hi << 32) | Lo;
215 bool readString(StringRef &Str) {
217 // Keep reading until we find a non-zero length. This emulates gcov's
218 // behaviour, which appears to do the same.
223 if (Buffer->getBuffer().size() < Cursor + Len) {
224 errs() << "Unexpected end of memory buffer: " << Cursor + Len << ".\n";
227 Str = Buffer->getBuffer().slice(Cursor, Cursor + Len).split('\0').first;
232 uint64_t getCursor() const { return Cursor; }
233 void advanceCursor(uint32_t n) { Cursor += n * 4; }
236 MemoryBuffer *Buffer;
240 /// GCOVFile - Collects coverage information for one pair of coverage file
241 /// (.gcno and .gcda).
244 GCOVFile() = default;
246 bool readGCNO(GCOVBuffer &Buffer);
247 bool readGCDA(GCOVBuffer &Buffer);
248 uint32_t getChecksum() const { return Checksum; }
249 void print(raw_ostream &OS) const;
251 void collectLineCounts(FileInfo &FI);
254 bool GCNOInitialized = false;
255 GCOV::GCOVVersion Version;
256 uint32_t Checksum = 0;
257 SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
258 uint32_t RunCount = 0;
259 uint32_t ProgramCount = 0;
262 /// GCOVEdge - Collects edge information.
264 GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
271 /// GCOVFunction - Collects function information.
274 typedef pointee_iterator<SmallVectorImpl<
275 std::unique_ptr<GCOVBlock>>::const_iterator> BlockIterator;
277 GCOVFunction(GCOVFile &P) : Parent(P) {}
279 bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
280 bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
281 StringRef getName() const { return Name; }
282 StringRef getFilename() const { return Filename; }
283 size_t getNumBlocks() const { return Blocks.size(); }
284 uint64_t getEntryCount() const;
285 uint64_t getExitCount() const;
287 BlockIterator block_begin() const { return Blocks.begin(); }
288 BlockIterator block_end() const { return Blocks.end(); }
289 iterator_range<BlockIterator> blocks() const {
290 return make_range(block_begin(), block_end());
293 void print(raw_ostream &OS) const;
295 void collectLineCounts(FileInfo &FI);
301 uint32_t LineNumber = 0;
304 SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
305 SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
308 /// GCOVBlock - Collects block information.
311 EdgeWeight(GCOVBlock *D) : Dst(D) {}
317 struct SortDstEdgesFunctor {
318 bool operator()(const GCOVEdge *E1, const GCOVEdge *E2) {
319 return E1->Dst.Number < E2->Dst.Number;
324 typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator;
326 GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
329 const GCOVFunction &getParent() const { return Parent; }
330 void addLine(uint32_t N) { Lines.push_back(N); }
331 uint32_t getLastLine() const { return Lines.back(); }
332 void addCount(size_t DstEdgeNo, uint64_t N);
333 uint64_t getCount() const { return Counter; }
335 void addSrcEdge(GCOVEdge *Edge) {
336 assert(&Edge->Dst == this); // up to caller to ensure edge is valid
337 SrcEdges.push_back(Edge);
340 void addDstEdge(GCOVEdge *Edge) {
341 assert(&Edge->Src == this); // up to caller to ensure edge is valid
342 // Check if adding this edge causes list to become unsorted.
343 if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
344 DstEdgesAreSorted = false;
345 DstEdges.push_back(Edge);
348 size_t getNumSrcEdges() const { return SrcEdges.size(); }
349 size_t getNumDstEdges() const { return DstEdges.size(); }
352 EdgeIterator src_begin() const { return SrcEdges.begin(); }
353 EdgeIterator src_end() const { return SrcEdges.end(); }
354 iterator_range<EdgeIterator> srcs() const {
355 return make_range(src_begin(), src_end());
358 EdgeIterator dst_begin() const { return DstEdges.begin(); }
359 EdgeIterator dst_end() const { return DstEdges.end(); }
360 iterator_range<EdgeIterator> dsts() const {
361 return make_range(dst_begin(), dst_end());
364 void print(raw_ostream &OS) const;
366 void collectLineCounts(FileInfo &FI);
369 GCOVFunction &Parent;
371 uint64_t Counter = 0;
372 bool DstEdgesAreSorted = true;
373 SmallVector<GCOVEdge *, 16> SrcEdges;
374 SmallVector<GCOVEdge *, 16> DstEdges;
375 SmallVector<uint32_t, 16> Lines;
379 // It is unlikely--but possible--for multiple functions to be on the same
381 // Therefore this typedef allows LineData.Functions to store multiple
383 // per instance. This is rare, however, so optimize for the common case.
384 typedef SmallVector<const GCOVFunction *, 1> FunctionVector;
385 typedef DenseMap<uint32_t, FunctionVector> FunctionLines;
386 typedef SmallVector<const GCOVBlock *, 4> BlockVector;
387 typedef DenseMap<uint32_t, BlockVector> BlockLines;
390 LineData() = default;
393 FunctionLines Functions;
394 uint32_t LastLine = 0;
397 struct GCOVCoverage {
398 GCOVCoverage(StringRef Name) : Name(Name) {}
402 uint32_t LogicalLines = 0;
403 uint32_t LinesExec = 0;
405 uint32_t Branches = 0;
406 uint32_t BranchesExec = 0;
407 uint32_t BranchesTaken = 0;
411 FileInfo(const GCOV::Options &Options) : Options(Options) {}
413 void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) {
414 if (Line > LineInfo[Filename].LastLine)
415 LineInfo[Filename].LastLine = Line;
416 LineInfo[Filename].Blocks[Line - 1].push_back(Block);
419 void addFunctionLine(StringRef Filename, uint32_t Line,
420 const GCOVFunction *Function) {
421 if (Line > LineInfo[Filename].LastLine)
422 LineInfo[Filename].LastLine = Line;
423 LineInfo[Filename].Functions[Line - 1].push_back(Function);
426 void setRunCount(uint32_t Runs) { RunCount = Runs; }
427 void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
428 void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
432 std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
433 std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath);
434 void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const;
435 void printBlockInfo(raw_ostream &OS, const GCOVBlock &Block,
436 uint32_t LineIndex, uint32_t &BlockNo) const;
437 void printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
438 GCOVCoverage &Coverage, uint32_t &EdgeNo);
439 void printUncondBranchInfo(raw_ostream &OS, uint32_t &EdgeNo,
440 uint64_t Count) const;
442 void printCoverage(raw_ostream &OS, const GCOVCoverage &Coverage) const;
443 void printFuncCoverage(raw_ostream &OS) const;
444 void printFileCoverage(raw_ostream &OS) const;
446 const GCOV::Options &Options;
447 StringMap<LineData> LineInfo;
448 uint32_t RunCount = 0;
449 uint32_t ProgramCount = 0;
451 typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4> FileCoverageList;
452 typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap;
454 FileCoverageList FileCoverages;
455 FuncCoverageMap FuncCoverages;
458 } // end namespace llvm
460 #endif // LLVM_SUPPORT_GCOV_H