Coverage Report

Created: 2019-07-24 05:18

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