1226584Sdim//===-- llvm/Support/GCOV.h - LLVM coverage tool ----------------*- C++ -*-===//
2226584Sdim//
3226584Sdim//                     The LLVM Compiler Infrastructure
4226584Sdim//
5226584Sdim// This file is distributed under the University of Illinois Open Source
6226584Sdim// License. See LICENSE.TXT for details.
7226584Sdim//
8226584Sdim//===----------------------------------------------------------------------===//
9226584Sdim//
10226584Sdim// This header provides the interface to read and write coverage files that
11226584Sdim// use 'gcov' format.
12226584Sdim//
13226584Sdim//===----------------------------------------------------------------------===//
14226584Sdim
15252723Sdim#ifndef LLVM_SUPPORT_GCOV_H
16252723Sdim#define LLVM_SUPPORT_GCOV_H
17226584Sdim
18263509Sdim#include "llvm/ADT/DenseMap.h"
19226584Sdim#include "llvm/ADT/SmallVector.h"
20226584Sdim#include "llvm/ADT/StringMap.h"
21226584Sdim#include "llvm/Support/MemoryBuffer.h"
22226584Sdim#include "llvm/Support/raw_ostream.h"
23226584Sdim
24226584Sdimnamespace llvm {
25226584Sdim
26226584Sdimclass GCOVFunction;
27226584Sdimclass GCOVBlock;
28226584Sdimclass FileInfo;
29226584Sdim
30245431Sdimnamespace GCOV {
31245431Sdim  enum GCOVFormat {
32245431Sdim    InvalidGCOV,
33245431Sdim    GCNO_402,
34245431Sdim    GCNO_404,
35245431Sdim    GCDA_402,
36245431Sdim    GCDA_404
37245431Sdim  };
38245431Sdim} // end GCOV namespace
39226584Sdim
40226584Sdim/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
41226584Sdim/// read operations.
42226584Sdimclass GCOVBuffer {
43226584Sdimpublic:
44226584Sdim  GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {}
45226584Sdim
46226584Sdim  /// readGCOVFormat - Read GCOV signature at the beginning of buffer.
47245431Sdim  GCOV::GCOVFormat readGCOVFormat() {
48226584Sdim    StringRef Magic = Buffer->getBuffer().slice(0, 12);
49226584Sdim    Cursor = 12;
50226584Sdim    if (Magic == "oncg*404MVLL")
51245431Sdim      return GCOV::GCNO_404;
52226584Sdim    else if (Magic == "oncg*204MVLL")
53245431Sdim      return GCOV::GCNO_402;
54226584Sdim    else if (Magic == "adcg*404MVLL")
55245431Sdim      return GCOV::GCDA_404;
56226584Sdim    else if (Magic == "adcg*204MVLL")
57245431Sdim      return GCOV::GCDA_402;
58226584Sdim
59226584Sdim    Cursor = 0;
60245431Sdim    return GCOV::InvalidGCOV;
61226584Sdim  }
62226584Sdim
63226584Sdim  /// readFunctionTag - If cursor points to a function tag then increment the
64226584Sdim  /// cursor and return true otherwise return false.
65226584Sdim  bool readFunctionTag() {
66226584Sdim    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
67226584Sdim    if (Tag.empty() ||
68245431Sdim        Tag[0] != '\0' || Tag[1] != '\0' ||
69245431Sdim        Tag[2] != '\0' || Tag[3] != '\1') {
70226584Sdim      return false;
71226584Sdim    }
72226584Sdim    Cursor += 4;
73226584Sdim    return true;
74226584Sdim  }
75226584Sdim
76226584Sdim  /// readBlockTag - If cursor points to a block tag then increment the
77226584Sdim  /// cursor and return true otherwise return false.
78226584Sdim  bool readBlockTag() {
79226584Sdim    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
80226584Sdim    if (Tag.empty() ||
81245431Sdim        Tag[0] != '\0' || Tag[1] != '\0' ||
82245431Sdim        Tag[2] != '\x41' || Tag[3] != '\x01') {
83226584Sdim      return false;
84226584Sdim    }
85226584Sdim    Cursor += 4;
86226584Sdim    return true;
87226584Sdim  }
88226584Sdim
89226584Sdim  /// readEdgeTag - If cursor points to an edge tag then increment the
90226584Sdim  /// cursor and return true otherwise return false.
91226584Sdim  bool readEdgeTag() {
92226584Sdim    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
93226584Sdim    if (Tag.empty() ||
94245431Sdim        Tag[0] != '\0' || Tag[1] != '\0' ||
95245431Sdim        Tag[2] != '\x43' || Tag[3] != '\x01') {
96226584Sdim      return false;
97226584Sdim    }
98226584Sdim    Cursor += 4;
99226584Sdim    return true;
100226584Sdim  }
101226584Sdim
102226584Sdim  /// readLineTag - If cursor points to a line tag then increment the
103226584Sdim  /// cursor and return true otherwise return false.
104226584Sdim  bool readLineTag() {
105226584Sdim    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
106226584Sdim    if (Tag.empty() ||
107245431Sdim        Tag[0] != '\0' || Tag[1] != '\0' ||
108245431Sdim        Tag[2] != '\x45' || Tag[3] != '\x01') {
109226584Sdim      return false;
110226584Sdim    }
111226584Sdim    Cursor += 4;
112226584Sdim    return true;
113226584Sdim  }
114226584Sdim
115226584Sdim  /// readArcTag - If cursor points to an gcda arc tag then increment the
116226584Sdim  /// cursor and return true otherwise return false.
117226584Sdim  bool readArcTag() {
118226584Sdim    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
119226584Sdim    if (Tag.empty() ||
120245431Sdim        Tag[0] != '\0' || Tag[1] != '\0' ||
121245431Sdim        Tag[2] != '\xa1' || Tag[3] != '\1') {
122226584Sdim      return false;
123226584Sdim    }
124226584Sdim    Cursor += 4;
125226584Sdim    return true;
126226584Sdim  }
127226584Sdim
128263509Sdim  /// readObjectTag - If cursor points to an object summary tag then increment
129263509Sdim  /// the cursor and return true otherwise return false.
130263509Sdim  bool readObjectTag() {
131263509Sdim    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
132263509Sdim    if (Tag.empty() ||
133263509Sdim        Tag[0] != '\0' || Tag[1] != '\0' ||
134263509Sdim        Tag[2] != '\0' || Tag[3] != '\xa1') {
135263509Sdim      return false;
136263509Sdim    }
137263509Sdim    Cursor += 4;
138263509Sdim    return true;
139263509Sdim  }
140263509Sdim
141263509Sdim  /// readProgramTag - If cursor points to a program summary tag then increment
142263509Sdim  /// the cursor and return true otherwise return false.
143263509Sdim  bool readProgramTag() {
144263509Sdim    StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor+4);
145263509Sdim    if (Tag.empty() ||
146263509Sdim        Tag[0] != '\0' || Tag[1] != '\0' ||
147263509Sdim        Tag[2] != '\0' || Tag[3] != '\xa3') {
148263509Sdim      return false;
149263509Sdim    }
150263509Sdim    Cursor += 4;
151263509Sdim    return true;
152263509Sdim  }
153263509Sdim
154263509Sdim  bool readInt(uint32_t &Val) {
155263509Sdim    if (Buffer->getBuffer().size() < Cursor+4) {
156263509Sdim      errs() << "Unexpected end of memory buffer: " << Cursor+4 << ".\n";
157263509Sdim      return false;
158263509Sdim    }
159226584Sdim    StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor+4);
160226584Sdim    Cursor += 4;
161263509Sdim    Val = *(const uint32_t *)(Str.data());
162263509Sdim    return true;
163226584Sdim  }
164226584Sdim
165263509Sdim  bool readInt64(uint64_t &Val) {
166263509Sdim    uint32_t Lo, Hi;
167263509Sdim    if (!readInt(Lo) || !readInt(Hi)) return false;
168263509Sdim    Val = ((uint64_t)Hi << 32) | Lo;
169263509Sdim    return true;
170226584Sdim  }
171226584Sdim
172263509Sdim  bool readString(StringRef &Str) {
173263509Sdim    uint32_t Len;
174263509Sdim    if (!readInt(Len)) return false;
175263509Sdim    Len *= 4;
176263509Sdim    if (Buffer->getBuffer().size() < Cursor+Len) {
177263509Sdim      errs() << "Unexpected end of memory buffer: " << Cursor+Len << ".\n";
178263509Sdim      return false;
179263509Sdim    }
180263509Sdim    Str = Buffer->getBuffer().slice(Cursor, Cursor+Len).split('\0').first;
181226584Sdim    Cursor += Len;
182263509Sdim    return true;
183226584Sdim  }
184226584Sdim
185226584Sdim  uint64_t getCursor() const { return Cursor; }
186263509Sdim  void advanceCursor(uint32_t n) { Cursor += n*4; }
187226584Sdimprivate:
188226584Sdim  MemoryBuffer *Buffer;
189226584Sdim  uint64_t Cursor;
190226584Sdim};
191226584Sdim
192226584Sdim/// GCOVFile - Collects coverage information for one pair of coverage file
193226584Sdim/// (.gcno and .gcda).
194226584Sdimclass GCOVFile {
195226584Sdimpublic:
196263509Sdim  GCOVFile() : Functions(), RunCount(0), ProgramCount(0) {}
197226584Sdim  ~GCOVFile();
198226584Sdim  bool read(GCOVBuffer &Buffer);
199226584Sdim  void dump();
200226584Sdim  void collectLineCounts(FileInfo &FI);
201226584Sdimprivate:
202226584Sdim  SmallVector<GCOVFunction *, 16> Functions;
203263509Sdim  uint32_t RunCount;
204263509Sdim  uint32_t ProgramCount;
205226584Sdim};
206226584Sdim
207226584Sdim/// GCOVFunction - Collects function information.
208226584Sdimclass GCOVFunction {
209226584Sdimpublic:
210226584Sdim  GCOVFunction() : Ident(0), LineNumber(0) {}
211226584Sdim  ~GCOVFunction();
212245431Sdim  bool read(GCOVBuffer &Buffer, GCOV::GCOVFormat Format);
213263509Sdim  StringRef getFilename() const { return Filename; }
214226584Sdim  void dump();
215226584Sdim  void collectLineCounts(FileInfo &FI);
216226584Sdimprivate:
217226584Sdim  uint32_t Ident;
218226584Sdim  uint32_t LineNumber;
219226584Sdim  StringRef Name;
220226584Sdim  StringRef Filename;
221226584Sdim  SmallVector<GCOVBlock *, 16> Blocks;
222226584Sdim};
223226584Sdim
224226584Sdim/// GCOVBlock - Collects block information.
225226584Sdimclass GCOVBlock {
226226584Sdimpublic:
227263509Sdim  GCOVBlock(GCOVFunction &P, uint32_t N) :
228263509Sdim    Parent(P), Number(N), Counter(0), Edges(), Lines() {}
229226584Sdim  ~GCOVBlock();
230226584Sdim  void addEdge(uint32_t N) { Edges.push_back(N); }
231263509Sdim  void addLine(uint32_t N) { Lines.push_back(N); }
232263509Sdim  void addCount(uint64_t N) { Counter += N; }
233263509Sdim  size_t getNumEdges() { return Edges.size(); }
234226584Sdim  void dump();
235226584Sdim  void collectLineCounts(FileInfo &FI);
236226584Sdimprivate:
237263509Sdim  GCOVFunction &Parent;
238226584Sdim  uint32_t Number;
239226584Sdim  uint64_t Counter;
240226584Sdim  SmallVector<uint32_t, 16> Edges;
241263509Sdim  SmallVector<uint32_t, 16> Lines;
242226584Sdim};
243226584Sdim
244263509Sdimtypedef DenseMap<uint32_t, uint64_t> LineCounts;
245226584Sdimclass FileInfo {
246226584Sdimpublic:
247263509Sdim  void addLineCount(StringRef Filename, uint32_t Line, uint64_t Count) {
248263509Sdim    LineInfo[Filename][Line-1] += Count;
249263509Sdim  }
250263509Sdim  void setRunCount(uint32_t Runs) { RunCount = Runs; }
251263509Sdim  void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
252263509Sdim  void print(raw_fd_ostream &OS, StringRef gcnoFile, StringRef gcdaFile);
253226584Sdimprivate:
254226584Sdim  StringMap<LineCounts> LineInfo;
255263509Sdim  uint32_t RunCount;
256263509Sdim  uint32_t ProgramCount;
257226584Sdim};
258226584Sdim
259226584Sdim}
260226584Sdim
261226584Sdim#endif
262