GCOV.h revision 263508
1//===-- llvm/Support/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_SUPPORT_GCOV_H
16#define LLVM_SUPPORT_GCOV_H
17
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringMap.h"
21#include "llvm/Support/MemoryBuffer.h"
22#include "llvm/Support/raw_ostream.h"
23
24namespace llvm {
25
26class GCOVFunction;
27class GCOVBlock;
28class FileInfo;
29
30namespace GCOV {
31  enum GCOVFormat {
32    InvalidGCOV,
33    GCNO_402,
34    GCNO_404,
35    GCDA_402,
36    GCDA_404
37  };
38} // end GCOV namespace
39
40/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
41/// read operations.
42class GCOVBuffer {
43public:
44  GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
45
46  /// readGCOVFormat - Read GCOV signature at the beginning of buffer.
47  GCOV::GCOVFormat readGCOVFormat() {
48    StringRef Magic = Buffer->getBuffer().slice(0, 12);
49    Cursor = 12;
50    if (Magic == "oncg*404MVLL")
51      return GCOV::GCNO_404;
52    else if (Magic == "oncg*204MVLL")
53      return GCOV::GCNO_402;
54    else if (Magic == "adcg*404MVLL")
55      return GCOV::GCDA_404;
56    else if (Magic == "adcg*204MVLL")
57      return GCOV::GCDA_402;
58
59    Cursor = 0;
60    return GCOV::InvalidGCOV;
61  }
62
63  /// readFunctionTag - If cursor points to a function tag then increment the
64  /// cursor and return true otherwise return false.
65  bool readFunctionTag() {
66    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
67    if (Tag.empty() ||
68        Tag[0] != '\0' || Tag[1] != '\0' ||
69        Tag[2] != '\0' || Tag[3] != '\1') {
70      return false;
71    }
72    Cursor += 4;
73    return true;
74  }
75
76  /// readBlockTag - If cursor points to a block tag then increment the
77  /// cursor and return true otherwise return false.
78  bool readBlockTag() {
79    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
80    if (Tag.empty() ||
81        Tag[0] != '\0' || Tag[1] != '\0' ||
82        Tag[2] != '\x41' || Tag[3] != '\x01') {
83      return false;
84    }
85    Cursor += 4;
86    return true;
87  }
88
89  /// readEdgeTag - If cursor points to an edge tag then increment the
90  /// cursor and return true otherwise return false.
91  bool readEdgeTag() {
92    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
93    if (Tag.empty() ||
94        Tag[0] != '\0' || Tag[1] != '\0' ||
95        Tag[2] != '\x43' || Tag[3] != '\x01') {
96      return false;
97    }
98    Cursor += 4;
99    return true;
100  }
101
102  /// readLineTag - If cursor points to a line tag then increment the
103  /// cursor and return true otherwise return false.
104  bool readLineTag() {
105    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
106    if (Tag.empty() ||
107        Tag[0] != '\0' || Tag[1] != '\0' ||
108        Tag[2] != '\x45' || Tag[3] != '\x01') {
109      return false;
110    }
111    Cursor += 4;
112    return true;
113  }
114
115  /// readArcTag - If cursor points to an gcda arc tag then increment the
116  /// cursor and return true otherwise return false.
117  bool readArcTag() {
118    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
119    if (Tag.empty() ||
120        Tag[0] != '\0' || Tag[1] != '\0' ||
121        Tag[2] != '\xa1' || Tag[3] != '\1') {
122      return false;
123    }
124    Cursor += 4;
125    return true;
126  }
127
128  /// readObjectTag - If cursor points to an object summary tag then increment
129  /// the cursor and return true otherwise return false.
130  bool readObjectTag() {
131    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
132    if (Tag.empty() ||
133        Tag[0] != '\0' || Tag[1] != '\0' ||
134        Tag[2] != '\0' || Tag[3] != '\xa1') {
135      return false;
136    }
137    Cursor += 4;
138    return true;
139  }
140
141  /// readProgramTag - If cursor points to a program summary tag then increment
142  /// the cursor and return true otherwise return false.
143  bool readProgramTag() {
144    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
145    if (Tag.empty() ||
146        Tag[0] != '\0' || Tag[1] != '\0' ||
147        Tag[2] != '\0' || Tag[3] != '\xa3') {
148      return false;
149    }
150    Cursor += 4;
151    return true;
152  }
153
154  bool readInt(uint32_t &Val) {
155    if (Buffer->getBuffer().size() < Cursor+4) {
156      errs() << "Unexpected end of memory buffer: " << Cursor+4 << ".\n";
157      return false;
158    }
159    StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4);
160    Cursor += 4;
161    Val = *(const uint32_t *)(Str.data());
162    return true;
163  }
164
165  bool readInt64(uint64_t &Val) {
166    uint32_t Lo, Hi;
167    if (!readInt(Lo) || !readInt(Hi)) return false;
168    Val = ((uint64_t)Hi << 32) | Lo;
169    return true;
170  }
171
172  bool readString(StringRef &Str) {
173    uint32_t Len;
174    if (!readInt(Len)) return false;
175    Len *= 4;
176    if (Buffer->getBuffer().size() < Cursor+Len) {
177      errs() << "Unexpected end of memory buffer: " << Cursor+Len << ".\n";
178      return false;
179    }
180    Str = Buffer->getBuffer().slice(Cursor, Cursor+Len).split('\0').first;
181    Cursor += Len;
182    return true;
183  }
184
185  uint64_t getCursor() const { return Cursor; }
186  void advanceCursor(uint32_t n) { Cursor += n*4; }
187private:
188  MemoryBuffer *Buffer;
189  uint64_t Cursor;
190};
191
192/// GCOVFile - Collects coverage information for one pair of coverage file
193/// (.gcno and .gcda).
194class GCOVFile {
195public:
196  GCOVFile() : Functions(), RunCount(0), ProgramCount(0) {}
197  ~GCOVFile();
198  bool read(GCOVBuffer &Buffer);
199  void dump();
200  void collectLineCounts(FileInfo &FI);
201private:
202  SmallVector<GCOVFunction *, 16> Functions;
203  uint32_t RunCount;
204  uint32_t ProgramCount;
205};
206
207/// GCOVFunction - Collects function information.
208class GCOVFunction {
209public:
210  GCOVFunction() : Ident(0), LineNumber(0) {}
211  ~GCOVFunction();
212  bool read(GCOVBuffer &Buffer, GCOV::GCOVFormat Format);
213  StringRef getFilename() const { return Filename; }
214  void dump();
215  void collectLineCounts(FileInfo &FI);
216private:
217  uint32_t Ident;
218  uint32_t LineNumber;
219  StringRef Name;
220  StringRef Filename;
221  SmallVector<GCOVBlock *, 16> Blocks;
222};
223
224/// GCOVBlock - Collects block information.
225class GCOVBlock {
226public:
227  GCOVBlock(GCOVFunction &P, uint32_t N) :
228    Parent(P), Number(N), Counter(0), Edges(), Lines() {}
229  ~GCOVBlock();
230  void addEdge(uint32_t N) { Edges.push_back(N); }
231  void addLine(uint32_t N) { Lines.push_back(N); }
232  void addCount(uint64_t N) { Counter += N; }
233  size_t getNumEdges() { return Edges.size(); }
234  void dump();
235  void collectLineCounts(FileInfo &FI);
236private:
237  GCOVFunction &Parent;
238  uint32_t Number;
239  uint64_t Counter;
240  SmallVector<uint32_t, 16> Edges;
241  SmallVector<uint32_t, 16> Lines;
242};
243
244typedef DenseMap<uint32_t, uint64_t> LineCounts;
245class FileInfo {
246public:
247  void addLineCount(StringRef Filename, uint32_t Line, uint64_t Count) {
248    LineInfo[Filename][Line-1] += Count;
249  }
250  void setRunCount(uint32_t Runs) { RunCount = Runs; }
251  void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
252  void print(raw_fd_ostream &OS, StringRef gcnoFile, StringRef gcdaFile);
253private:
254  StringMap<LineCounts> LineInfo;
255  uint32_t RunCount;
256  uint32_t ProgramCount;
257};
258
259}
260
261#endif
262