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