Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This header provides the interface to read and write coverage files that
10
// use 'gcov' format.
11
//
12
//===----------------------------------------------------------------------===//
13
 
14
#ifndef LLVM_PROFILEDATA_GCOV_H
15
#define LLVM_PROFILEDATA_GCOV_H
16
 
17
#include "llvm/ADT/DenseSet.h"
18
#include "llvm/ADT/SmallVector.h"
19
#include "llvm/ADT/StringMap.h"
20
#include "llvm/ADT/StringRef.h"
21
#include "llvm/ADT/iterator.h"
22
#include "llvm/ADT/iterator_range.h"
23
#include "llvm/Support/DataExtractor.h"
24
#include "llvm/Support/MemoryBuffer.h"
25
#include "llvm/Support/raw_ostream.h"
26
#include <algorithm>
27
#include <cstddef>
28
#include <cstdint>
29
#include <map>
30
#include <memory>
31
#include <string>
32
#include <utility>
33
 
34
namespace llvm {
35
 
36
class GCOVFunction;
37
class GCOVBlock;
38
 
39
namespace GCOV {
40
 
41
enum GCOVVersion { V304, V407, V408, V800, V900, V1200 };
42
 
43
/// A struct for passing gcov options between functions.
44
struct Options {
45
  Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L,
46
          bool M, bool N, bool R, bool T, bool X, std::string SourcePrefix)
47
      : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F),
48
        PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L),
49
        Demangle(M), NoOutput(N), RelativeOnly(R), UseStdout(T),
50
        HashFilenames(X), SourcePrefix(std::move(SourcePrefix)) {}
51
 
52
  bool AllBlocks;
53
  bool BranchInfo;
54
  bool BranchCount;
55
  bool FuncCoverage;
56
  bool PreservePaths;
57
  bool UncondBranch;
58
  bool Intermediate;
59
  bool LongFileNames;
60
  bool Demangle;
61
  bool NoOutput;
62
  bool RelativeOnly;
63
  bool UseStdout;
64
  bool HashFilenames;
65
  std::string SourcePrefix;
66
};
67
 
68
} // end namespace GCOV
69
 
70
/// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific
71
/// read operations.
72
class GCOVBuffer {
73
public:
74
  GCOVBuffer(MemoryBuffer *B) : Buffer(B) {}
75
  ~GCOVBuffer() { consumeError(cursor.takeError()); }
76
 
77
  /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
78
  bool readGCNOFormat() {
79
    StringRef buf = Buffer->getBuffer();
80
    StringRef magic = buf.substr(0, 4);
81
    if (magic == "gcno") {
82
      de = DataExtractor(buf.substr(4), false, 0);
83
    } else if (magic == "oncg") {
84
      de = DataExtractor(buf.substr(4), true, 0);
85
    } else {
86
      errs() << "unexpected magic: " << magic << "\n";
87
      return false;
88
    }
89
    return true;
90
  }
91
 
92
  /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
93
  bool readGCDAFormat() {
94
    StringRef buf = Buffer->getBuffer();
95
    StringRef magic = buf.substr(0, 4);
96
    if (magic == "gcda") {
97
      de = DataExtractor(buf.substr(4), false, 0);
98
    } else if (magic == "adcg") {
99
      de = DataExtractor(buf.substr(4), true, 0);
100
    } else {
101
      return false;
102
    }
103
    return true;
104
  }
105
 
106
  /// readGCOVVersion - Read GCOV version.
107
  bool readGCOVVersion(GCOV::GCOVVersion &version) {
108
    std::string str(de.getBytes(cursor, 4));
109
    if (str.size() != 4)
110
      return false;
111
    if (de.isLittleEndian())
112
      std::reverse(str.begin(), str.end());
113
    int ver = str[0] >= 'A'
114
                  ? (str[0] - 'A') * 100 + (str[1] - '0') * 10 + str[2] - '0'
115
                  : (str[0] - '0') * 10 + str[2] - '0';
116
    if (ver >= 120) {
117
      this->version = version = GCOV::V1200;
118
      return true;
119
    } else if (ver >= 90) {
120
      // PR gcov-profile/84846, r269678
121
      this->version = version = GCOV::V900;
122
      return true;
123
    } else if (ver >= 80) {
124
      // PR gcov-profile/48463
125
      this->version = version = GCOV::V800;
126
      return true;
127
    } else if (ver >= 48) {
128
      // r189778: the exit block moved from the last to the second.
129
      this->version = version = GCOV::V408;
130
      return true;
131
    } else if (ver >= 47) {
132
      // r173147: split checksum into cfg checksum and line checksum.
133
      this->version = version = GCOV::V407;
134
      return true;
135
    } else if (ver >= 34) {
136
      this->version = version = GCOV::V304;
137
      return true;
138
    }
139
    errs() << "unexpected version: " << str << "\n";
140
    return false;
141
  }
142
 
143
  uint32_t getWord() { return de.getU32(cursor); }
144
  StringRef getString() {
145
    uint32_t len;
146
    if (!readInt(len) || len == 0)
147
      return {};
148
    return de.getBytes(cursor, len * 4).split('\0').first;
149
  }
150
 
151
  bool readInt(uint32_t &Val) {
152
    if (cursor.tell() + 4 > de.size()) {
153
      Val = 0;
154
      errs() << "unexpected end of memory buffer: " << cursor.tell() << "\n";
155
      return false;
156
    }
157
    Val = de.getU32(cursor);
158
    return true;
159
  }
160
 
161
  bool readInt64(uint64_t &Val) {
162
    uint32_t Lo, Hi;
163
    if (!readInt(Lo) || !readInt(Hi))
164
      return false;
165
    Val = ((uint64_t)Hi << 32) | Lo;
166
    return true;
167
  }
168
 
169
  bool readString(StringRef &str) {
170
    uint32_t len;
171
    if (!readInt(len) || len == 0)
172
      return false;
173
    if (version >= GCOV::V1200)
174
      str = de.getBytes(cursor, len).drop_back();
175
    else
176
      str = de.getBytes(cursor, len * 4).split('\0').first;
177
    return bool(cursor);
178
  }
179
 
180
  DataExtractor de{ArrayRef<uint8_t>{}, false, 0};
181
  DataExtractor::Cursor cursor{0};
182
 
183
private:
184
  MemoryBuffer *Buffer;
185
  GCOV::GCOVVersion version{};
186
};
187
 
188
/// GCOVFile - Collects coverage information for one pair of coverage file
189
/// (.gcno and .gcda).
190
class GCOVFile {
191
public:
192
  GCOVFile() = default;
193
 
194
  bool readGCNO(GCOVBuffer &Buffer);
195
  bool readGCDA(GCOVBuffer &Buffer);
196
  GCOV::GCOVVersion getVersion() const { return version; }
197
  void print(raw_ostream &OS) const;
198
  void dump() const;
199
 
200
  std::vector<std::string> filenames;
201
  StringMap<unsigned> filenameToIdx;
202
 
203
public:
204
  bool GCNOInitialized = false;
205
  GCOV::GCOVVersion version{};
206
  uint32_t checksum = 0;
207
  StringRef cwd;
208
  SmallVector<std::unique_ptr<GCOVFunction>, 16> functions;
209
  std::map<uint32_t, GCOVFunction *> identToFunction;
210
  uint32_t runCount = 0;
211
  uint32_t programCount = 0;
212
 
213
  using iterator = pointee_iterator<
214
      SmallVectorImpl<std::unique_ptr<GCOVFunction>>::const_iterator>;
215
  iterator begin() const { return iterator(functions.begin()); }
216
  iterator end() const { return iterator(functions.end()); }
217
};
218
 
219
struct GCOVArc {
220
  GCOVArc(GCOVBlock &src, GCOVBlock &dst, uint32_t flags)
221
      : src(src), dst(dst), flags(flags) {}
222
  bool onTree() const;
223
 
224
  GCOVBlock &src;
225
  GCOVBlock &dst;
226
  uint32_t flags;
227
  uint64_t count = 0;
228
  uint64_t cycleCount = 0;
229
};
230
 
231
/// GCOVFunction - Collects function information.
232
class GCOVFunction {
233
public:
234
  using BlockIterator = pointee_iterator<
235
      SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
236
 
237
  GCOVFunction(GCOVFile &file) : file(file) {}
238
 
239
  StringRef getName(bool demangle) const;
240
  StringRef getFilename() const;
241
  uint64_t getEntryCount() const;
242
  GCOVBlock &getExitBlock() const;
243
 
244
  iterator_range<BlockIterator> blocksRange() const {
245
    return make_range(blocks.begin(), blocks.end());
246
  }
247
 
248
  uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred);
249
  void print(raw_ostream &OS) const;
250
  void dump() const;
251
 
252
  GCOVFile &file;
253
  uint32_t ident = 0;
254
  uint32_t linenoChecksum;
255
  uint32_t cfgChecksum = 0;
256
  uint32_t startLine = 0;
257
  uint32_t startColumn = 0;
258
  uint32_t endLine = 0;
259
  uint32_t endColumn = 0;
260
  uint8_t artificial = 0;
261
  StringRef Name;
262
  mutable SmallString<0> demangled;
263
  unsigned srcIdx;
264
  SmallVector<std::unique_ptr<GCOVBlock>, 0> blocks;
265
  SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs;
266
  DenseSet<const GCOVBlock *> visited;
267
};
268
 
269
/// GCOVBlock - Collects block information.
270
class GCOVBlock {
271
public:
272
  using EdgeIterator = SmallVectorImpl<GCOVArc *>::const_iterator;
273
  using BlockVector = SmallVector<const GCOVBlock *, 1>;
274
  using BlockVectorLists = SmallVector<BlockVector, 4>;
275
  using Edges = SmallVector<GCOVArc *, 4>;
276
 
277
  GCOVBlock(uint32_t N) : number(N) {}
278
 
279
  void addLine(uint32_t N) { lines.push_back(N); }
280
  uint32_t getLastLine() const { return lines.back(); }
281
  uint64_t getCount() const { return count; }
282
 
283
  void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
284
 
285
  void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); }
286
 
287
  iterator_range<EdgeIterator> srcs() const {
288
    return make_range(pred.begin(), pred.end());
289
  }
290
 
291
  iterator_range<EdgeIterator> dsts() const {
292
    return make_range(succ.begin(), succ.end());
293
  }
294
 
295
  void print(raw_ostream &OS) const;
296
  void dump() const;
297
 
298
  static uint64_t
299
  augmentOneCycle(GCOVBlock *src,
300
                  std::vector<std::pair<GCOVBlock *, size_t>> &stack);
301
  static uint64_t getCyclesCount(const BlockVector &blocks);
302
  static uint64_t getLineCount(const BlockVector &Blocks);
303
 
304
public:
305
  uint32_t number;
306
  uint64_t count = 0;
307
  SmallVector<GCOVArc *, 2> pred;
308
  SmallVector<GCOVArc *, 2> succ;
309
  SmallVector<uint32_t, 4> lines;
310
  bool traversable = false;
311
  GCOVArc *incoming = nullptr;
312
};
313
 
314
void gcovOneInput(const GCOV::Options &options, StringRef filename,
315
                  StringRef gcno, StringRef gcda, GCOVFile &file);
316
 
317
} // end namespace llvm
318
 
319
#endif // LLVM_PROFILEDATA_GCOV_H