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