LLVM 17.0.0git
GCOV.cpp
Go to the documentation of this file.
1//===- GCOV.cpp - LLVM coverage tool --------------------------------------===//
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// GCOV implements the interface to read and write coverage files that use
10// 'gcov' format.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/SmallSet.h"
17#include "llvm/Config/llvm-config.h"
19#include "llvm/Support/Debug.h"
21#include "llvm/Support/Format.h"
22#include "llvm/Support/MD5.h"
23#include "llvm/Support/Path.h"
25#include <algorithm>
26#include <optional>
27#include <system_error>
28
29using namespace llvm;
30
31enum : uint32_t {
34
35 GCOV_TAG_FUNCTION = 0x01000000,
36 GCOV_TAG_BLOCKS = 0x01410000,
37 GCOV_TAG_ARCS = 0x01430000,
38 GCOV_TAG_LINES = 0x01450000,
40 // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
43};
44
45namespace {
46struct Summary {
48
50 uint64_t lines = 0;
51 uint64_t linesExec = 0;
53 uint64_t branchesExec = 0;
54 uint64_t branchesTaken = 0;
55};
56
57struct LineInfo {
59 uint64_t count = 0;
60 bool exists = false;
61};
62
63struct SourceInfo {
65 SmallString<0> displayName;
66 std::vector<std::vector<const GCOVFunction *>> startLineToFunctions;
67 std::vector<LineInfo> lines;
68 bool ignored = false;
69 SourceInfo(StringRef filename) : filename(filename) {}
70};
71
72class Context {
73public:
75 void print(StringRef filename, StringRef gcno, StringRef gcda,
76 GCOVFile &file);
77
78private:
79 std::string getCoveragePath(StringRef filename, StringRef mainFilename) const;
80 void printFunctionDetails(const GCOVFunction &f, raw_ostream &os) const;
81 void printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
82 raw_ostream &OS) const;
83 void printSummary(const Summary &summary, raw_ostream &os) const;
84
85 void collectFunction(GCOVFunction &f, Summary &summary);
86 void collectSourceLine(SourceInfo &si, Summary *summary, LineInfo &line,
87 size_t lineNum) const;
88 void collectSource(SourceInfo &si, Summary &summary) const;
89 void annotateSource(SourceInfo &si, const GCOVFile &file, StringRef gcno,
90 StringRef gcda, raw_ostream &os) const;
91 void printSourceToIntermediate(const SourceInfo &si, raw_ostream &os) const;
92
94 std::vector<SourceInfo> sources;
95};
96} // namespace
97
98//===----------------------------------------------------------------------===//
99// GCOVFile implementation.
100
101/// readGCNO - Read GCNO buffer.
103 if (!buf.readGCNOFormat())
104 return false;
105 if (!buf.readGCOVVersion(version))
106 return false;
107
108 checksum = buf.getWord();
109 if (version >= GCOV::V900 && !buf.readString(cwd))
110 return false;
111 if (version >= GCOV::V800)
112 buf.getWord(); // hasUnexecutedBlocks
113
114 uint32_t tag, length;
115 GCOVFunction *fn = nullptr;
116 while ((tag = buf.getWord())) {
117 if (!buf.readInt(length))
118 return false;
119 uint32_t pos = buf.cursor.tell();
120 if (tag == GCOV_TAG_FUNCTION) {
121 functions.push_back(std::make_unique<GCOVFunction>(*this));
122 fn = functions.back().get();
123 fn->ident = buf.getWord();
124 fn->linenoChecksum = buf.getWord();
125 if (version >= GCOV::V407)
126 fn->cfgChecksum = buf.getWord();
127 buf.readString(fn->Name);
128 StringRef filename;
129 if (version < GCOV::V800) {
130 if (!buf.readString(filename))
131 return false;
132 fn->startLine = buf.getWord();
133 } else {
134 fn->artificial = buf.getWord();
135 if (!buf.readString(filename))
136 return false;
137 fn->startLine = buf.getWord();
138 fn->startColumn = buf.getWord();
139 fn->endLine = buf.getWord();
140 if (version >= GCOV::V900)
141 fn->endColumn = buf.getWord();
142 }
143 auto r = filenameToIdx.try_emplace(filename, filenameToIdx.size());
144 if (r.second)
145 filenames.emplace_back(filename);
146 fn->srcIdx = r.first->second;
147 identToFunction[fn->ident] = fn;
148 } else if (tag == GCOV_TAG_BLOCKS && fn) {
149 if (version < GCOV::V800) {
150 for (uint32_t i = 0; i != length; ++i) {
151 buf.getWord(); // Ignored block flags
152 fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
153 }
154 } else {
155 uint32_t num = buf.getWord();
156 for (uint32_t i = 0; i != num; ++i)
157 fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
158 }
159 } else if (tag == GCOV_TAG_ARCS && fn) {
160 uint32_t srcNo = buf.getWord();
161 if (srcNo >= fn->blocks.size()) {
162 errs() << "unexpected block number: " << srcNo << " (in "
163 << fn->blocks.size() << ")\n";
164 return false;
165 }
166 GCOVBlock *src = fn->blocks[srcNo].get();
167 const uint32_t e =
168 version >= GCOV::V1200 ? (length / 4 - 1) / 2 : (length - 1) / 2;
169 for (uint32_t i = 0; i != e; ++i) {
170 uint32_t dstNo = buf.getWord(), flags = buf.getWord();
171 GCOVBlock *dst = fn->blocks[dstNo].get();
172 auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
173 src->addDstEdge(arc.get());
174 dst->addSrcEdge(arc.get());
175 if (arc->onTree())
176 fn->treeArcs.push_back(std::move(arc));
177 else
178 fn->arcs.push_back(std::move(arc));
179 }
180 } else if (tag == GCOV_TAG_LINES && fn) {
181 uint32_t srcNo = buf.getWord();
182 if (srcNo >= fn->blocks.size()) {
183 errs() << "unexpected block number: " << srcNo << " (in "
184 << fn->blocks.size() << ")\n";
185 return false;
186 }
187 GCOVBlock &Block = *fn->blocks[srcNo];
188 for (;;) {
189 uint32_t line = buf.getWord();
190 if (line)
191 Block.addLine(line);
192 else {
193 StringRef filename;
194 buf.readString(filename);
195 if (filename.empty())
196 break;
197 // TODO Unhandled
198 }
199 }
200 }
201 pos += version >= GCOV::V1200 ? length : 4 * length;
202 if (pos < buf.cursor.tell())
203 return false;
204 buf.de.skip(buf.cursor, pos - buf.cursor.tell());
205 }
206
207 GCNOInitialized = true;
208 return true;
209}
210
211/// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
212/// called after readGCNO().
214 assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
215 if (!buf.readGCDAFormat())
216 return false;
217 GCOV::GCOVVersion GCDAVersion;
218 if (!buf.readGCOVVersion(GCDAVersion))
219 return false;
220 if (version != GCDAVersion) {
221 errs() << "GCOV versions do not match.\n";
222 return false;
223 }
224
225 uint32_t GCDAChecksum;
226 if (!buf.readInt(GCDAChecksum))
227 return false;
228 if (checksum != GCDAChecksum) {
229 errs() << "file checksums do not match: " << checksum
230 << " != " << GCDAChecksum << "\n";
231 return false;
232 }
233 uint32_t dummy, tag, length;
234 uint32_t ident;
235 GCOVFunction *fn = nullptr;
236 while ((tag = buf.getWord())) {
237 if (!buf.readInt(length))
238 return false;
239 uint32_t pos = buf.cursor.tell();
240 if (tag == GCOV_TAG_OBJECT_SUMMARY) {
241 buf.readInt(runCount);
242 buf.readInt(dummy);
243 // clang<11 uses a fake 4.2 format which sets length to 9.
244 if (length == 9)
245 buf.readInt(runCount);
246 } else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
247 // clang<11 uses a fake 4.2 format which sets length to 0.
248 if (length > 0) {
249 buf.readInt(dummy);
250 buf.readInt(dummy);
251 buf.readInt(runCount);
252 }
253 ++programCount;
254 } else if (tag == GCOV_TAG_FUNCTION) {
255 if (length == 0) // Placeholder
256 continue;
257 // As of GCC 10, GCOV_TAG_FUNCTION_LENGTH has never been larger than 3.
258 // However, clang<11 uses a fake 4.2 format which may set length larger
259 // than 3.
260 if (length < 2 || !buf.readInt(ident))
261 return false;
262 auto It = identToFunction.find(ident);
263 uint32_t linenoChecksum, cfgChecksum = 0;
264 buf.readInt(linenoChecksum);
265 if (version >= GCOV::V407)
266 buf.readInt(cfgChecksum);
267 if (It != identToFunction.end()) {
268 fn = It->second;
269 if (linenoChecksum != fn->linenoChecksum ||
270 cfgChecksum != fn->cfgChecksum) {
271 errs() << fn->Name
272 << format(": checksum mismatch, (%u, %u) != (%u, %u)\n",
273 linenoChecksum, cfgChecksum, fn->linenoChecksum,
274 fn->cfgChecksum);
275 return false;
276 }
277 }
278 } else if (tag == GCOV_TAG_COUNTER_ARCS && fn) {
279 uint32_t expected = 2 * fn->arcs.size();
280 if (version >= GCOV::V1200)
281 expected *= 4;
282 if (length != expected) {
283 errs() << fn->Name
284 << format(
285 ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
286 length, expected);
287 return false;
288 }
289 for (std::unique_ptr<GCOVArc> &arc : fn->arcs) {
290 if (!buf.readInt64(arc->count))
291 return false;
292 arc->src.count += arc->count;
293 }
294
295 if (fn->blocks.size() >= 2) {
296 GCOVBlock &src = *fn->blocks[0];
297 GCOVBlock &sink =
298 version < GCOV::V408 ? *fn->blocks.back() : *fn->blocks[1];
299 auto arc = std::make_unique<GCOVArc>(sink, src, GCOV_ARC_ON_TREE);
300 sink.addDstEdge(arc.get());
301 src.addSrcEdge(arc.get());
302 fn->treeArcs.push_back(std::move(arc));
303
304 for (GCOVBlock &block : fn->blocksRange())
305 fn->propagateCounts(block, nullptr);
306 for (size_t i = fn->treeArcs.size() - 1; i; --i)
307 fn->treeArcs[i - 1]->src.count += fn->treeArcs[i - 1]->count;
308 }
309 }
310 pos += version >= GCOV::V1200 ? length : 4 * length;
311 if (pos < buf.cursor.tell())
312 return false;
313 buf.de.skip(buf.cursor, pos - buf.cursor.tell());
314 }
315
316 return true;
317}
318
320 for (const GCOVFunction &f : *this)
321 f.print(OS);
322}
323
324#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
325/// dump - Dump GCOVFile content to dbgs() for debugging purposes.
327#endif
328
329bool GCOVArc::onTree() const { return flags & GCOV_ARC_ON_TREE; }
330
331//===----------------------------------------------------------------------===//
332// GCOVFunction implementation.
333
335 if (!demangle)
336 return Name;
337 if (demangled.empty()) {
338 do {
339 if (Name.startswith("_Z")) {
340 int status = 0;
341 // Name is guaranteed to be NUL-terminated.
342 char *res = itaniumDemangle(Name.data(), nullptr, nullptr, &status);
343 if (status == 0) {
344 demangled = res;
345 free(res);
346 break;
347 }
348 }
349 demangled = Name;
350 } while (false);
351 }
352 return demangled;
353}
355
356/// getEntryCount - Get the number of times the function was called by
357/// retrieving the entry block's count.
359 return blocks.front()->getCount();
360}
361
363 return file.getVersion() < GCOV::V408 ? *blocks.back() : *blocks[1];
364}
365
366// For each basic block, the sum of incoming edge counts equals the sum of
367// outgoing edge counts by Kirchoff's circuit law. If the unmeasured arcs form a
368// spanning tree, the count for each unmeasured arc (GCOV_ARC_ON_TREE) can be
369// uniquely identified.
371 // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed; otherwise
372 // this prevents infinite recursion.
373 if (!visited.insert(&v).second)
374 return 0;
375
376 uint64_t excess = 0;
377 for (GCOVArc *e : v.srcs())
378 if (e != pred)
379 excess += e->onTree() ? propagateCounts(e->src, e) : e->count;
380 for (GCOVArc *e : v.dsts())
381 if (e != pred)
382 excess -= e->onTree() ? propagateCounts(e->dst, e) : e->count;
383 if (int64_t(excess) < 0)
384 excess = -excess;
385 if (pred)
386 pred->count = excess;
387 return excess;
388}
389
391 OS << "===== " << Name << " (" << ident << ") @ " << getFilename() << ":"
392 << startLine << "\n";
393 for (const auto &Block : blocks)
394 Block->print(OS);
395}
396
397#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
398/// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
400#endif
401
402/// collectLineCounts - Collect line counts. This must be used after
403/// reading .gcno and .gcda files.
404
405//===----------------------------------------------------------------------===//
406// GCOVBlock implementation.
407
409 OS << "Block : " << number << " Counter : " << count << "\n";
410 if (!pred.empty()) {
411 OS << "\tSource Edges : ";
412 for (const GCOVArc *Edge : pred)
413 OS << Edge->src.number << " (" << Edge->count << "), ";
414 OS << "\n";
415 }
416 if (!succ.empty()) {
417 OS << "\tDestination Edges : ";
418 for (const GCOVArc *Edge : succ) {
419 if (Edge->flags & GCOV_ARC_ON_TREE)
420 OS << '*';
421 OS << Edge->dst.number << " (" << Edge->count << "), ";
422 }
423 OS << "\n";
424 }
425 if (!lines.empty()) {
426 OS << "\tLines : ";
427 for (uint32_t N : lines)
428 OS << (N) << ",";
429 OS << "\n";
430 }
431}
432
433#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
434/// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
436#endif
437
440 std::vector<std::pair<GCOVBlock *, size_t>> &stack) {
441 GCOVBlock *u;
442 size_t i;
443 stack.clear();
444 stack.emplace_back(src, 0);
445 src->incoming = (GCOVArc *)1; // Mark u available for cycle detection
446 for (;;) {
447 std::tie(u, i) = stack.back();
448 if (i == u->succ.size()) {
449 u->traversable = false;
450 stack.pop_back();
451 if (stack.empty())
452 break;
453 continue;
454 }
455 ++stack.back().second;
456 GCOVArc *succ = u->succ[i];
457 // Ignore saturated arcs (cycleCount has been reduced to 0) and visited
458 // blocks. Ignore self arcs to guard against bad input (.gcno has no
459 // self arcs).
460 if (succ->cycleCount == 0 || !succ->dst.traversable || &succ->dst == u)
461 continue;
462 if (succ->dst.incoming == nullptr) {
463 succ->dst.incoming = succ;
464 stack.emplace_back(&succ->dst, 0);
465 continue;
466 }
467 uint64_t minCount = succ->cycleCount;
468 for (GCOVBlock *v = u;;) {
469 minCount = std::min(minCount, v->incoming->cycleCount);
470 v = &v->incoming->src;
471 if (v == &succ->dst)
472 break;
473 }
474 succ->cycleCount -= minCount;
475 for (GCOVBlock *v = u;;) {
476 v->incoming->cycleCount -= minCount;
477 v = &v->incoming->src;
478 if (v == &succ->dst)
479 break;
480 }
481 return minCount;
482 }
483 return 0;
484}
485
486// Get the total execution count of loops among blocks on the same line.
487// Assuming a reducible flow graph, the count is the sum of back edge counts.
488// Identifying loops is complex, so we simply find cycles and perform cycle
489// cancelling iteratively.
491 std::vector<std::pair<GCOVBlock *, size_t>> stack;
492 uint64_t count = 0, d;
493 for (;;) {
494 // Make blocks on the line traversable and try finding a cycle.
495 for (const auto *b : blocks) {
496 const_cast<GCOVBlock *>(b)->traversable = true;
497 const_cast<GCOVBlock *>(b)->incoming = nullptr;
498 }
499 d = 0;
500 for (const auto *block : blocks) {
501 auto *b = const_cast<GCOVBlock *>(block);
502 if (b->traversable && (d = augmentOneCycle(b, stack)) > 0)
503 break;
504 }
505 if (d == 0)
506 break;
507 count += d;
508 }
509 // If there is no more loop, all traversable bits should have been cleared.
510 // This property is needed by subsequent calls.
511 for (const auto *b : blocks) {
512 assert(!b->traversable);
513 (void)b;
514 }
515 return count;
516}
517
518//===----------------------------------------------------------------------===//
519// FileInfo implementation.
520
521// Format dividend/divisor as a percentage. Return 1 if the result is greater
522// than 0% and less than 1%.
523static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor) {
524 if (!dividend || !divisor)
525 return 0;
526 dividend *= 100;
527 return dividend < divisor ? 1 : dividend / divisor;
528}
529
530// This custom division function mimics gcov's branch ouputs:
531// - Round to closest whole number
532// - Only output 0% or 100% if it's exactly that value
533static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
534 if (!Numerator)
535 return 0;
536 if (Numerator == Divisor)
537 return 100;
538
539 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
540 if (Res == 0)
541 return 1;
542 if (Res == 100)
543 return 99;
544 return Res;
545}
546
547namespace {
548struct formatBranchInfo {
549 formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
550 : Options(Options), Count(Count), Total(Total) {}
551
552 void print(raw_ostream &OS) const {
553 if (!Total)
554 OS << "never executed";
555 else if (Options.BranchCount)
556 OS << "taken " << Count;
557 else
558 OS << "taken " << branchDiv(Count, Total) << "%";
559 }
560
561 const GCOV::Options &Options;
562 uint64_t Count;
564};
565
566static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
567 FBI.print(OS);
568 return OS;
569}
570
571class LineConsumer {
572 std::unique_ptr<MemoryBuffer> Buffer;
573 StringRef Remaining;
574
575public:
576 LineConsumer() = default;
577 LineConsumer(StringRef Filename) {
578 // Open source files without requiring a NUL terminator. The concurrent
579 // modification may nullify the NUL terminator condition.
581 MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/false,
582 /*RequiresNullTerminator=*/false);
583 if (std::error_code EC = BufferOrErr.getError()) {
584 errs() << Filename << ": " << EC.message() << "\n";
585 Remaining = "";
586 } else {
587 Buffer = std::move(BufferOrErr.get());
588 Remaining = Buffer->getBuffer();
589 }
590 }
591 bool empty() { return Remaining.empty(); }
592 void printNext(raw_ostream &OS, uint32_t LineNum) {
594 if (empty())
595 Line = "/*EOF*/";
596 else
597 std::tie(Line, Remaining) = Remaining.split("\n");
598 OS << format("%5u:", LineNum) << Line << "\n";
599 }
600};
601} // end anonymous namespace
602
603/// Convert a path to a gcov filename. If PreservePaths is true, this
604/// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
605static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
606 if (!PreservePaths)
607 return sys::path::filename(Filename).str();
608
609 // This behaviour is defined by gcov in terms of text replacements, so it's
610 // not likely to do anything useful on filesystems with different textual
611 // conventions.
612 llvm::SmallString<256> Result("");
614 for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
615 if (*I != '/')
616 continue;
617
618 if (I - S == 1 && *S == '.') {
619 // ".", the current directory, is skipped.
620 } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
621 // "..", the parent directory, is replaced with "^".
622 Result.append("^#");
623 } else {
624 if (S < I)
625 // Leave other components intact,
626 Result.append(S, I);
627 // And separate with "#".
628 Result.push_back('#');
629 }
630 S = I + 1;
631 }
632
633 if (S < I)
634 Result.append(S, I);
635 return std::string(Result.str());
636}
637
638std::string Context::getCoveragePath(StringRef filename,
639 StringRef mainFilename) const {
640 if (options.NoOutput)
641 // This is probably a bug in gcov, but when -n is specified, paths aren't
642 // mangled at all, and the -l and -p options are ignored. Here, we do the
643 // same.
644 return std::string(filename);
645
646 std::string CoveragePath;
647 if (options.LongFileNames && !filename.equals(mainFilename))
648 CoveragePath =
649 mangleCoveragePath(mainFilename, options.PreservePaths) + "##";
650 CoveragePath += mangleCoveragePath(filename, options.PreservePaths);
651 if (options.HashFilenames) {
652 MD5 Hasher;
654 Hasher.update(filename.str());
655 Hasher.final(Result);
656 CoveragePath += "##" + std::string(Result.digest());
657 }
658 CoveragePath += ".gcov";
659 return CoveragePath;
660}
661
662void Context::collectFunction(GCOVFunction &f, Summary &summary) {
663 SourceInfo &si = sources[f.srcIdx];
664 if (f.startLine >= si.startLineToFunctions.size())
665 si.startLineToFunctions.resize(f.startLine + 1);
666 si.startLineToFunctions[f.startLine].push_back(&f);
668 SmallSet<uint32_t, 16> linesExec;
669 for (const GCOVBlock &b : f.blocksRange()) {
670 if (b.lines.empty())
671 continue;
672 uint32_t maxLineNum = *std::max_element(b.lines.begin(), b.lines.end());
673 if (maxLineNum >= si.lines.size())
674 si.lines.resize(maxLineNum + 1);
675 for (uint32_t lineNum : b.lines) {
676 LineInfo &line = si.lines[lineNum];
677 if (lines.insert(lineNum).second)
678 ++summary.lines;
679 if (b.count && linesExec.insert(lineNum).second)
680 ++summary.linesExec;
681 line.exists = true;
682 line.count += b.count;
683 line.blocks.push_back(&b);
684 }
685 }
686}
687
688void Context::collectSourceLine(SourceInfo &si, Summary *summary,
689 LineInfo &line, size_t lineNum) const {
690 uint64_t count = 0;
691 for (const GCOVBlock *b : line.blocks) {
692 if (b->number == 0) {
693 // For nonstandard control flows, arcs into the exit block may be
694 // duplicately counted (fork) or not be counted (abnormal exit), and thus
695 // the (exit,entry) counter may be inaccurate. Count the entry block with
696 // the outgoing arcs.
697 for (const GCOVArc *arc : b->succ)
698 count += arc->count;
699 } else {
700 // Add counts from predecessors that are not on the same line.
701 for (const GCOVArc *arc : b->pred)
702 if (!llvm::is_contained(line.blocks, &arc->src))
703 count += arc->count;
704 }
705 for (GCOVArc *arc : b->succ)
706 arc->cycleCount = arc->count;
707 }
708
709 count += GCOVBlock::getCyclesCount(line.blocks);
710 line.count = count;
711 if (line.exists) {
712 ++summary->lines;
713 if (line.count != 0)
714 ++summary->linesExec;
715 }
716
717 if (options.BranchInfo)
718 for (const GCOVBlock *b : line.blocks) {
719 if (b->getLastLine() != lineNum)
720 continue;
721 int branches = 0, execBranches = 0, takenBranches = 0;
722 for (const GCOVArc *arc : b->succ) {
723 ++branches;
724 if (count != 0)
725 ++execBranches;
726 if (arc->count != 0)
727 ++takenBranches;
728 }
729 if (branches > 1) {
730 summary->branches += branches;
731 summary->branchesExec += execBranches;
732 summary->branchesTaken += takenBranches;
733 }
734 }
735}
736
737void Context::collectSource(SourceInfo &si, Summary &summary) const {
738 size_t lineNum = 0;
739 for (LineInfo &line : si.lines) {
740 collectSourceLine(si, &summary, line, lineNum);
741 ++lineNum;
742 }
743}
744
745void Context::annotateSource(SourceInfo &si, const GCOVFile &file,
746 StringRef gcno, StringRef gcda,
747 raw_ostream &os) const {
748 auto source =
749 options.Intermediate ? LineConsumer() : LineConsumer(si.filename);
750
751 os << " -: 0:Source:" << si.displayName << '\n';
752 os << " -: 0:Graph:" << gcno << '\n';
753 os << " -: 0:Data:" << gcda << '\n';
754 os << " -: 0:Runs:" << file.runCount << '\n';
755 if (file.version < GCOV::V900)
756 os << " -: 0:Programs:" << file.programCount << '\n';
757
758 for (size_t lineNum = 1; !source.empty(); ++lineNum) {
759 if (lineNum >= si.lines.size()) {
760 os << " -:";
761 source.printNext(os, lineNum);
762 continue;
763 }
764
765 const LineInfo &line = si.lines[lineNum];
766 if (options.BranchInfo && lineNum < si.startLineToFunctions.size())
767 for (const auto *f : si.startLineToFunctions[lineNum])
768 printFunctionDetails(*f, os);
769 if (!line.exists)
770 os << " -:";
771 else if (line.count == 0)
772 os << " #####:";
773 else
774 os << format("%9" PRIu64 ":", line.count);
775 source.printNext(os, lineNum);
776
777 uint32_t blockIdx = 0, edgeIdx = 0;
778 for (const GCOVBlock *b : line.blocks) {
779 if (b->getLastLine() != lineNum)
780 continue;
781 if (options.AllBlocks) {
782 if (b->getCount() == 0)
783 os << " $$$$$:";
784 else
785 os << format("%9" PRIu64 ":", b->count);
786 os << format("%5u-block %2u\n", lineNum, blockIdx++);
787 }
788 if (options.BranchInfo) {
789 size_t NumEdges = b->succ.size();
790 if (NumEdges > 1)
791 printBranchInfo(*b, edgeIdx, os);
792 else if (options.UncondBranch && NumEdges == 1) {
793 uint64_t count = b->succ[0]->count;
794 os << format("unconditional %2u ", edgeIdx++)
795 << formatBranchInfo(options, count, count) << '\n';
796 }
797 }
798 }
799 }
800}
801
802void Context::printSourceToIntermediate(const SourceInfo &si,
803 raw_ostream &os) const {
804 os << "file:" << si.filename << '\n';
805 for (const auto &fs : si.startLineToFunctions)
806 for (const GCOVFunction *f : fs)
807 os << "function:" << f->startLine << ',' << f->getEntryCount() << ','
808 << f->getName(options.Demangle) << '\n';
809 for (size_t lineNum = 1, size = si.lines.size(); lineNum < size; ++lineNum) {
810 const LineInfo &line = si.lines[lineNum];
811 if (line.blocks.empty())
812 continue;
813 // GCC 8 (r254259) added third third field for Ada:
814 // lcount:<line>,<count>,<has_unexecuted_blocks>
815 // We don't need the third field.
816 os << "lcount:" << lineNum << ',' << line.count << '\n';
817
818 if (!options.BranchInfo)
819 continue;
820 for (const GCOVBlock *b : line.blocks) {
821 if (b->succ.size() < 2 || b->getLastLine() != lineNum)
822 continue;
823 for (const GCOVArc *arc : b->succ) {
824 const char *type =
825 b->getCount() ? arc->count ? "taken" : "nottaken" : "notexec";
826 os << "branch:" << lineNum << ',' << type << '\n';
827 }
828 }
829 }
830}
831
832void Context::print(StringRef filename, StringRef gcno, StringRef gcda,
833 GCOVFile &file) {
834 for (StringRef filename : file.filenames) {
835 sources.emplace_back(filename);
836 SourceInfo &si = sources.back();
837 si.displayName = si.filename;
838 if (!options.SourcePrefix.empty() &&
839 sys::path::replace_path_prefix(si.displayName, options.SourcePrefix,
840 "") &&
841 !si.displayName.empty()) {
842 // TODO replace_path_prefix may strip the prefix even if the remaining
843 // part does not start with a separator.
844 if (sys::path::is_separator(si.displayName[0]))
845 si.displayName.erase(si.displayName.begin());
846 else
847 si.displayName = si.filename;
848 }
849 if (options.RelativeOnly && sys::path::is_absolute(si.displayName))
850 si.ignored = true;
851 }
852
853 raw_ostream &os = llvm::outs();
854 for (GCOVFunction &f : make_pointee_range(file.functions)) {
855 Summary summary(f.getName(options.Demangle));
856 collectFunction(f, summary);
857 if (options.FuncCoverage && !options.UseStdout) {
858 os << "Function '" << summary.Name << "'\n";
859 printSummary(summary, os);
860 os << '\n';
861 }
862 }
863
864 for (SourceInfo &si : sources) {
865 if (si.ignored)
866 continue;
867 Summary summary(si.displayName);
868 collectSource(si, summary);
869
870 // Print file summary unless -t is specified.
871 std::string gcovName = getCoveragePath(si.filename, filename);
872 if (!options.UseStdout) {
873 os << "File '" << summary.Name << "'\n";
874 printSummary(summary, os);
875 if (!options.NoOutput && !options.Intermediate)
876 os << "Creating '" << gcovName << "'\n";
877 os << '\n';
878 }
879
880 if (options.NoOutput || options.Intermediate)
881 continue;
882 std::optional<raw_fd_ostream> os;
883 if (!options.UseStdout) {
884 std::error_code ec;
885 os.emplace(gcovName, ec, sys::fs::OF_TextWithCRLF);
886 if (ec) {
887 errs() << ec.message() << '\n';
888 continue;
889 }
890 }
891 annotateSource(si, file, gcno, gcda,
892 options.UseStdout ? llvm::outs() : *os);
893 }
894
895 if (options.Intermediate && !options.NoOutput) {
896 // gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0
897 // (PR GCC/82702). We create just one file.
898 std::string outputPath(sys::path::filename(filename));
899 std::error_code ec;
900 raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_TextWithCRLF);
901 if (ec) {
902 errs() << ec.message() << '\n';
903 return;
904 }
905
906 for (const SourceInfo &si : sources)
907 printSourceToIntermediate(si, os);
908 }
909}
910
911void Context::printFunctionDetails(const GCOVFunction &f,
912 raw_ostream &os) const {
913 const uint64_t entryCount = f.getEntryCount();
914 uint32_t blocksExec = 0;
915 const GCOVBlock &exitBlock = f.getExitBlock();
916 uint64_t exitCount = 0;
917 for (const GCOVArc *arc : exitBlock.pred)
918 exitCount += arc->count;
919 for (const GCOVBlock &b : f.blocksRange())
920 if (b.number != 0 && &b != &exitBlock && b.getCount())
921 ++blocksExec;
922
923 os << "function " << f.getName(options.Demangle) << " called " << entryCount
924 << " returned " << formatPercentage(exitCount, entryCount)
925 << "% blocks executed "
926 << formatPercentage(blocksExec, f.blocks.size() - 2) << "%\n";
927}
928
929/// printBranchInfo - Print conditional branch probabilities.
930void Context::printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
931 raw_ostream &os) const {
932 uint64_t total = 0;
933 for (const GCOVArc *arc : Block.dsts())
934 total += arc->count;
935 for (const GCOVArc *arc : Block.dsts())
936 os << format("branch %2u ", edgeIdx++)
937 << formatBranchInfo(options, arc->count, total) << '\n';
938}
939
940void Context::printSummary(const Summary &summary, raw_ostream &os) const {
941 os << format("Lines executed:%.2f%% of %" PRIu64 "\n",
942 double(summary.linesExec) * 100 / summary.lines, summary.lines);
943 if (options.BranchInfo) {
944 if (summary.branches == 0) {
945 os << "No branches\n";
946 } else {
947 os << format("Branches executed:%.2f%% of %" PRIu64 "\n",
948 double(summary.branchesExec) * 100 / summary.branches,
949 summary.branches);
950 os << format("Taken at least once:%.2f%% of %" PRIu64 "\n",
951 double(summary.branchesTaken) * 100 / summary.branches,
952 summary.branches);
953 }
954 os << "No calls\n";
955 }
956}
957
958void llvm::gcovOneInput(const GCOV::Options &options, StringRef filename,
959 StringRef gcno, StringRef gcda, GCOVFile &file) {
960 Context fi(options);
961 fi.print(filename, gcno, gcda, file);
962}
arc branch ARC finalize branches
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:492
Looks at all the uses of the given value Returns the Liveness deduced from the uses of this value Adds all uses that cause the result to be MaybeLive to MaybeLiveRetUses If the result is MaybeLiveUses might be modified but its content should be ignored(since it might not be complete). DeadArgumentEliminationPass
@ GCOV_TAG_LINES
Definition: GCOV.cpp:38
@ GCOV_TAG_COUNTER_ARCS
Definition: GCOV.cpp:39
@ GCOV_TAG_PROGRAM_SUMMARY
Definition: GCOV.cpp:42
@ GCOV_ARC_FALLTHROUGH
Definition: GCOV.cpp:33
@ GCOV_TAG_OBJECT_SUMMARY
Definition: GCOV.cpp:41
@ GCOV_ARC_ON_TREE
Definition: GCOV.cpp:32
@ GCOV_TAG_ARCS
Definition: GCOV.cpp:37
@ GCOV_TAG_FUNCTION
Definition: GCOV.cpp:35
@ GCOV_TAG_BLOCKS
Definition: GCOV.cpp:36
static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths)
Convert a path to a gcov filename.
Definition: GCOV.cpp:605
static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor)
Definition: GCOV.cpp:523
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor)
Definition: GCOV.cpp:533
hexagon gen pred
static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT, const Loop *CurLoop, ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater &MSSAU, OptimizationRemarkEmitter *ORE)
When an instruction is found to only be used outside of the loop, this function moves it to the exit ...
Definition: LICM.cpp:1618
static LVOptions Options
Definition: LVOptions.cpp:25
#define I(x, y, z)
Definition: MD5.cpp:58
LLVMContext & Context
dot regions Print regions of function to dot file(with no function bodies)"
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This file defines the SmallSet class.
unify loop Fixup each natural loop to have a single exit block
uint64_t tell() const
Return the current position of this Cursor.
Definition: DataExtractor.h:71
void skip(Cursor &C, uint64_t Length) const
Advance the Cursor position by the given number of bytes.
Represents either an error or a value T.
Definition: ErrorOr.h:56
reference get()
Definition: ErrorOr.h:150
std::error_code getError() const
Definition: ErrorOr.h:153
GCOVBlock - Collects block information.
Definition: GCOV.h:270
static uint64_t getCyclesCount(const BlockVector &blocks)
Definition: GCOV.cpp:490
SmallVector< uint32_t, 4 > lines
Definition: GCOV.h:309
void addDstEdge(GCOVArc *Edge)
Definition: GCOV.h:285
uint32_t number
Definition: GCOV.h:305
void addSrcEdge(GCOVArc *Edge)
Definition: GCOV.h:283
bool traversable
Definition: GCOV.h:310
void print(raw_ostream &OS) const
collectLineCounts - Collect line counts.
Definition: GCOV.cpp:408
GCOVArc * incoming
Definition: GCOV.h:311
static uint64_t augmentOneCycle(GCOVBlock *src, std::vector< std::pair< GCOVBlock *, size_t > > &stack)
Definition: GCOV.cpp:439
SmallVector< GCOVArc *, 2 > pred
Definition: GCOV.h:307
void dump() const
dump - Dump GCOVBlock content to dbgs() for debugging purposes.
Definition: GCOV.cpp:435
uint64_t count
Definition: GCOV.h:306
SmallVector< GCOVArc *, 2 > succ
Definition: GCOV.h:308
GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific read operations.
Definition: GCOV.h:72
bool readInt(uint32_t &Val)
Definition: GCOV.h:151
DataExtractor::Cursor cursor
Definition: GCOV.h:181
bool readInt64(uint64_t &Val)
Definition: GCOV.h:161
bool readGCOVVersion(GCOV::GCOVVersion &version)
readGCOVVersion - Read GCOV version.
Definition: GCOV.h:107
bool readString(StringRef &str)
Definition: GCOV.h:169
DataExtractor de
Definition: GCOV.h:180
uint32_t getWord()
Definition: GCOV.h:143
bool readGCNOFormat()
readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
Definition: GCOV.h:78
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
Definition: GCOV.h:93
GCOVFile - Collects coverage information for one pair of coverage file (.gcno and ....
Definition: GCOV.h:190
SmallVector< std::unique_ptr< GCOVFunction >, 16 > functions
Definition: GCOV.h:208
uint32_t checksum
Definition: GCOV.h:206
void print(raw_ostream &OS) const
Definition: GCOV.cpp:319
uint32_t programCount
Definition: GCOV.h:211
uint32_t runCount
Definition: GCOV.h:210
GCOV::GCOVVersion version
Definition: GCOV.h:205
std::vector< std::string > filenames
Definition: GCOV.h:200
GCOV::GCOVVersion getVersion() const
Definition: GCOV.h:196
void dump() const
dump - Dump GCOVFile content to dbgs() for debugging purposes.
Definition: GCOV.cpp:326
std::map< uint32_t, GCOVFunction * > identToFunction
Definition: GCOV.h:209
StringRef cwd
Definition: GCOV.h:207
bool GCNOInitialized
Definition: GCOV.h:204
StringMap< unsigned > filenameToIdx
Definition: GCOV.h:201
bool readGCNO(GCOVBuffer &Buffer)
readGCNO - Read GCNO buffer.
Definition: GCOV.cpp:102
bool readGCDA(GCOVBuffer &Buffer)
readGCDA - Read GCDA buffer.
Definition: GCOV.cpp:213
GCOVFunction - Collects function information.
Definition: GCOV.h:232
uint64_t getEntryCount() const
getEntryCount - Get the number of times the function was called by retrieving the entry block's count...
Definition: GCOV.cpp:358
uint32_t endColumn
Definition: GCOV.h:259
SmallVector< std::unique_ptr< GCOVArc >, 0 > treeArcs
Definition: GCOV.h:265
StringRef getName(bool demangle) const
Definition: GCOV.cpp:334
uint32_t cfgChecksum
Definition: GCOV.h:255
void dump() const
dump - Dump GCOVFunction content to dbgs() for debugging purposes.
Definition: GCOV.cpp:399
StringRef Name
Definition: GCOV.h:261
uint8_t artificial
Definition: GCOV.h:260
uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred)
Definition: GCOV.cpp:370
uint32_t endLine
Definition: GCOV.h:258
SmallVector< std::unique_ptr< GCOVBlock >, 0 > blocks
Definition: GCOV.h:264
GCOVBlock & getExitBlock() const
Definition: GCOV.cpp:362
StringRef getFilename() const
Definition: GCOV.cpp:354
DenseSet< const GCOVBlock * > visited
Definition: GCOV.h:266
uint32_t startLine
Definition: GCOV.h:256
SmallString< 0 > demangled
Definition: GCOV.h:262
void print(raw_ostream &OS) const
Definition: GCOV.cpp:390
uint32_t startColumn
Definition: GCOV.h:257
uint32_t linenoChecksum
Definition: GCOV.h:254
iterator_range< BlockIterator > blocksRange() const
Definition: GCOV.h:244
SmallVector< std::unique_ptr< GCOVArc >, 0 > arcs
Definition: GCOV.h:265
uint32_t ident
Definition: GCOV.h:253
unsigned srcIdx
Definition: GCOV.h:263
GCOVFile & file
Definition: GCOV.h:252
Definition: MD5.h:41
void update(ArrayRef< uint8_t > Data)
Updates the hash for the byte stream provided.
Definition: MD5.cpp:189
void final(MD5Result &Result)
Finishes off the hash and puts the result in result.
Definition: MD5.cpp:234
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:135
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:177
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
bool empty() const
Definition: SmallVector.h:94
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
unsigned size() const
Definition: StringMap.h:95
std::pair< iterator, bool > try_emplace(StringRef Key, ArgsTy &&...Args)
Emplace a new element for the specified key into the map if the key isn't already in the map.
Definition: StringMap.h:340
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:687
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:222
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
Definition: StringRef.h:164
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:454
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
GCOVVersion
Definition: GCOV.h:41
@ V407
Definition: GCOV.h:41
@ V800
Definition: GCOV.h:41
@ V408
Definition: GCOV.h:41
@ V900
Definition: GCOV.h:41
@ V1200
Definition: GCOV.h:41
LVOptions & options()
Definition: LVOptions.h:445
bool exists(const basic_file_status &status)
Does file exist?
Definition: Path.cpp:1077
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
Definition: FileSystem.h:770
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:577
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
Definition: Path.cpp:671
bool replace_path_prefix(SmallVectorImpl< char > &Path, StringRef OldPrefix, StringRef NewPrefix, Style style=Style::native)
Replace matching path prefix with another path.
Definition: Path.cpp:518
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
Definition: Path.cpp:601
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::string demangle(const std::string &MangledName)
Attempt to demangle a string using different demangling schemes.
Definition: Demangle.cpp:29
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
iterator_range< pointee_iterator< WrappedIteratorT > > make_pointee_range(RangeT &&Range)
Definition: iterator.h:336
char * itaniumDemangle(const char *mangled_name, char *buf, size_t *n, int *status)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:124
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition: STLExtras.h:2011
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
Definition: APFixedPoint.h:292
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1976
void gcovOneInput(const GCOV::Options &options, StringRef filename, StringRef gcno, StringRef gcda, GCOVFile &file)
Definition: GCOV.cpp:958
#define N
uint64_t count
Definition: GCOV.h:227
bool onTree() const
Definition: GCOV.cpp:329
GCOVBlock & src
Definition: GCOV.h:224
uint64_t cycleCount
Definition: GCOV.h:228
uint32_t flags
Definition: GCOV.h:226
A struct for passing gcov options between functions.
Definition: GCOV.h:44