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 // Name is guaranteed to be NUL-terminated.
341 if (char *res = itaniumDemangle(Name.data())) {
342 demangled = res;
343 free(res);
344 break;
345 }
346 }
347 demangled = Name;
348 } while (false);
349 }
350 return demangled;
351}
353
354/// getEntryCount - Get the number of times the function was called by
355/// retrieving the entry block's count.
357 return blocks.front()->getCount();
358}
359
361 return file.getVersion() < GCOV::V408 ? *blocks.back() : *blocks[1];
362}
363
364// For each basic block, the sum of incoming edge counts equals the sum of
365// outgoing edge counts by Kirchoff's circuit law. If the unmeasured arcs form a
366// spanning tree, the count for each unmeasured arc (GCOV_ARC_ON_TREE) can be
367// uniquely identified.
369 // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed; otherwise
370 // this prevents infinite recursion.
371 if (!visited.insert(&v).second)
372 return 0;
373
374 uint64_t excess = 0;
375 for (GCOVArc *e : v.srcs())
376 if (e != pred)
377 excess += e->onTree() ? propagateCounts(e->src, e) : e->count;
378 for (GCOVArc *e : v.dsts())
379 if (e != pred)
380 excess -= e->onTree() ? propagateCounts(e->dst, e) : e->count;
381 if (int64_t(excess) < 0)
382 excess = -excess;
383 if (pred)
384 pred->count = excess;
385 return excess;
386}
387
389 OS << "===== " << Name << " (" << ident << ") @ " << getFilename() << ":"
390 << startLine << "\n";
391 for (const auto &Block : blocks)
392 Block->print(OS);
393}
394
395#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
396/// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
398#endif
399
400/// collectLineCounts - Collect line counts. This must be used after
401/// reading .gcno and .gcda files.
402
403//===----------------------------------------------------------------------===//
404// GCOVBlock implementation.
405
407 OS << "Block : " << number << " Counter : " << count << "\n";
408 if (!pred.empty()) {
409 OS << "\tSource Edges : ";
410 for (const GCOVArc *Edge : pred)
411 OS << Edge->src.number << " (" << Edge->count << "), ";
412 OS << "\n";
413 }
414 if (!succ.empty()) {
415 OS << "\tDestination Edges : ";
416 for (const GCOVArc *Edge : succ) {
417 if (Edge->flags & GCOV_ARC_ON_TREE)
418 OS << '*';
419 OS << Edge->dst.number << " (" << Edge->count << "), ";
420 }
421 OS << "\n";
422 }
423 if (!lines.empty()) {
424 OS << "\tLines : ";
425 for (uint32_t N : lines)
426 OS << (N) << ",";
427 OS << "\n";
428 }
429}
430
431#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
432/// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
434#endif
435
438 std::vector<std::pair<GCOVBlock *, size_t>> &stack) {
439 GCOVBlock *u;
440 size_t i;
441 stack.clear();
442 stack.emplace_back(src, 0);
443 src->incoming = (GCOVArc *)1; // Mark u available for cycle detection
444 for (;;) {
445 std::tie(u, i) = stack.back();
446 if (i == u->succ.size()) {
447 u->traversable = false;
448 stack.pop_back();
449 if (stack.empty())
450 break;
451 continue;
452 }
453 ++stack.back().second;
454 GCOVArc *succ = u->succ[i];
455 // Ignore saturated arcs (cycleCount has been reduced to 0) and visited
456 // blocks. Ignore self arcs to guard against bad input (.gcno has no
457 // self arcs).
458 if (succ->cycleCount == 0 || !succ->dst.traversable || &succ->dst == u)
459 continue;
460 if (succ->dst.incoming == nullptr) {
461 succ->dst.incoming = succ;
462 stack.emplace_back(&succ->dst, 0);
463 continue;
464 }
465 uint64_t minCount = succ->cycleCount;
466 for (GCOVBlock *v = u;;) {
467 minCount = std::min(minCount, v->incoming->cycleCount);
468 v = &v->incoming->src;
469 if (v == &succ->dst)
470 break;
471 }
472 succ->cycleCount -= minCount;
473 for (GCOVBlock *v = u;;) {
474 v->incoming->cycleCount -= minCount;
475 v = &v->incoming->src;
476 if (v == &succ->dst)
477 break;
478 }
479 return minCount;
480 }
481 return 0;
482}
483
484// Get the total execution count of loops among blocks on the same line.
485// Assuming a reducible flow graph, the count is the sum of back edge counts.
486// Identifying loops is complex, so we simply find cycles and perform cycle
487// cancelling iteratively.
489 std::vector<std::pair<GCOVBlock *, size_t>> stack;
490 uint64_t count = 0, d;
491 for (;;) {
492 // Make blocks on the line traversable and try finding a cycle.
493 for (const auto *b : blocks) {
494 const_cast<GCOVBlock *>(b)->traversable = true;
495 const_cast<GCOVBlock *>(b)->incoming = nullptr;
496 }
497 d = 0;
498 for (const auto *block : blocks) {
499 auto *b = const_cast<GCOVBlock *>(block);
500 if (b->traversable && (d = augmentOneCycle(b, stack)) > 0)
501 break;
502 }
503 if (d == 0)
504 break;
505 count += d;
506 }
507 // If there is no more loop, all traversable bits should have been cleared.
508 // This property is needed by subsequent calls.
509 for (const auto *b : blocks) {
510 assert(!b->traversable);
511 (void)b;
512 }
513 return count;
514}
515
516//===----------------------------------------------------------------------===//
517// FileInfo implementation.
518
519// Format dividend/divisor as a percentage. Return 1 if the result is greater
520// than 0% and less than 1%.
521static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor) {
522 if (!dividend || !divisor)
523 return 0;
524 dividend *= 100;
525 return dividend < divisor ? 1 : dividend / divisor;
526}
527
528// This custom division function mimics gcov's branch ouputs:
529// - Round to closest whole number
530// - Only output 0% or 100% if it's exactly that value
531static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
532 if (!Numerator)
533 return 0;
534 if (Numerator == Divisor)
535 return 100;
536
537 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
538 if (Res == 0)
539 return 1;
540 if (Res == 100)
541 return 99;
542 return Res;
543}
544
545namespace {
546struct formatBranchInfo {
547 formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
548 : Options(Options), Count(Count), Total(Total) {}
549
550 void print(raw_ostream &OS) const {
551 if (!Total)
552 OS << "never executed";
553 else if (Options.BranchCount)
554 OS << "taken " << Count;
555 else
556 OS << "taken " << branchDiv(Count, Total) << "%";
557 }
558
559 const GCOV::Options &Options;
560 uint64_t Count;
562};
563
564static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
565 FBI.print(OS);
566 return OS;
567}
568
569class LineConsumer {
570 std::unique_ptr<MemoryBuffer> Buffer;
571 StringRef Remaining;
572
573public:
574 LineConsumer() = default;
575 LineConsumer(StringRef Filename) {
576 // Open source files without requiring a NUL terminator. The concurrent
577 // modification may nullify the NUL terminator condition.
579 MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/false,
580 /*RequiresNullTerminator=*/false);
581 if (std::error_code EC = BufferOrErr.getError()) {
582 errs() << Filename << ": " << EC.message() << "\n";
583 Remaining = "";
584 } else {
585 Buffer = std::move(BufferOrErr.get());
586 Remaining = Buffer->getBuffer();
587 }
588 }
589 bool empty() { return Remaining.empty(); }
590 void printNext(raw_ostream &OS, uint32_t LineNum) {
592 if (empty())
593 Line = "/*EOF*/";
594 else
595 std::tie(Line, Remaining) = Remaining.split("\n");
596 OS << format("%5u:", LineNum) << Line << "\n";
597 }
598};
599} // end anonymous namespace
600
601/// Convert a path to a gcov filename. If PreservePaths is true, this
602/// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
603static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
604 if (!PreservePaths)
605 return sys::path::filename(Filename).str();
606
607 // This behaviour is defined by gcov in terms of text replacements, so it's
608 // not likely to do anything useful on filesystems with different textual
609 // conventions.
610 llvm::SmallString<256> Result("");
612 for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
613 if (*I != '/')
614 continue;
615
616 if (I - S == 1 && *S == '.') {
617 // ".", the current directory, is skipped.
618 } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
619 // "..", the parent directory, is replaced with "^".
620 Result.append("^#");
621 } else {
622 if (S < I)
623 // Leave other components intact,
624 Result.append(S, I);
625 // And separate with "#".
626 Result.push_back('#');
627 }
628 S = I + 1;
629 }
630
631 if (S < I)
632 Result.append(S, I);
633 return std::string(Result.str());
634}
635
636std::string Context::getCoveragePath(StringRef filename,
637 StringRef mainFilename) const {
638 if (options.NoOutput)
639 // This is probably a bug in gcov, but when -n is specified, paths aren't
640 // mangled at all, and the -l and -p options are ignored. Here, we do the
641 // same.
642 return std::string(filename);
643
644 std::string CoveragePath;
645 if (options.LongFileNames && !filename.equals(mainFilename))
646 CoveragePath =
647 mangleCoveragePath(mainFilename, options.PreservePaths) + "##";
648 CoveragePath += mangleCoveragePath(filename, options.PreservePaths);
649 if (options.HashFilenames) {
650 MD5 Hasher;
652 Hasher.update(filename.str());
653 Hasher.final(Result);
654 CoveragePath += "##" + std::string(Result.digest());
655 }
656 CoveragePath += ".gcov";
657 return CoveragePath;
658}
659
660void Context::collectFunction(GCOVFunction &f, Summary &summary) {
661 SourceInfo &si = sources[f.srcIdx];
662 if (f.startLine >= si.startLineToFunctions.size())
663 si.startLineToFunctions.resize(f.startLine + 1);
664 si.startLineToFunctions[f.startLine].push_back(&f);
666 SmallSet<uint32_t, 16> linesExec;
667 for (const GCOVBlock &b : f.blocksRange()) {
668 if (b.lines.empty())
669 continue;
670 uint32_t maxLineNum = *std::max_element(b.lines.begin(), b.lines.end());
671 if (maxLineNum >= si.lines.size())
672 si.lines.resize(maxLineNum + 1);
673 for (uint32_t lineNum : b.lines) {
674 LineInfo &line = si.lines[lineNum];
675 if (lines.insert(lineNum).second)
676 ++summary.lines;
677 if (b.count && linesExec.insert(lineNum).second)
678 ++summary.linesExec;
679 line.exists = true;
680 line.count += b.count;
681 line.blocks.push_back(&b);
682 }
683 }
684}
685
686void Context::collectSourceLine(SourceInfo &si, Summary *summary,
687 LineInfo &line, size_t lineNum) const {
688 uint64_t count = 0;
689 for (const GCOVBlock *b : line.blocks) {
690 if (b->number == 0) {
691 // For nonstandard control flows, arcs into the exit block may be
692 // duplicately counted (fork) or not be counted (abnormal exit), and thus
693 // the (exit,entry) counter may be inaccurate. Count the entry block with
694 // the outgoing arcs.
695 for (const GCOVArc *arc : b->succ)
696 count += arc->count;
697 } else {
698 // Add counts from predecessors that are not on the same line.
699 for (const GCOVArc *arc : b->pred)
700 if (!llvm::is_contained(line.blocks, &arc->src))
701 count += arc->count;
702 }
703 for (GCOVArc *arc : b->succ)
704 arc->cycleCount = arc->count;
705 }
706
707 count += GCOVBlock::getCyclesCount(line.blocks);
708 line.count = count;
709 if (line.exists) {
710 ++summary->lines;
711 if (line.count != 0)
712 ++summary->linesExec;
713 }
714
715 if (options.BranchInfo)
716 for (const GCOVBlock *b : line.blocks) {
717 if (b->getLastLine() != lineNum)
718 continue;
719 int branches = 0, execBranches = 0, takenBranches = 0;
720 for (const GCOVArc *arc : b->succ) {
721 ++branches;
722 if (count != 0)
723 ++execBranches;
724 if (arc->count != 0)
725 ++takenBranches;
726 }
727 if (branches > 1) {
728 summary->branches += branches;
729 summary->branchesExec += execBranches;
730 summary->branchesTaken += takenBranches;
731 }
732 }
733}
734
735void Context::collectSource(SourceInfo &si, Summary &summary) const {
736 size_t lineNum = 0;
737 for (LineInfo &line : si.lines) {
738 collectSourceLine(si, &summary, line, lineNum);
739 ++lineNum;
740 }
741}
742
743void Context::annotateSource(SourceInfo &si, const GCOVFile &file,
744 StringRef gcno, StringRef gcda,
745 raw_ostream &os) const {
746 auto source =
747 options.Intermediate ? LineConsumer() : LineConsumer(si.filename);
748
749 os << " -: 0:Source:" << si.displayName << '\n';
750 os << " -: 0:Graph:" << gcno << '\n';
751 os << " -: 0:Data:" << gcda << '\n';
752 os << " -: 0:Runs:" << file.runCount << '\n';
753 if (file.version < GCOV::V900)
754 os << " -: 0:Programs:" << file.programCount << '\n';
755
756 for (size_t lineNum = 1; !source.empty(); ++lineNum) {
757 if (lineNum >= si.lines.size()) {
758 os << " -:";
759 source.printNext(os, lineNum);
760 continue;
761 }
762
763 const LineInfo &line = si.lines[lineNum];
764 if (options.BranchInfo && lineNum < si.startLineToFunctions.size())
765 for (const auto *f : si.startLineToFunctions[lineNum])
766 printFunctionDetails(*f, os);
767 if (!line.exists)
768 os << " -:";
769 else if (line.count == 0)
770 os << " #####:";
771 else
772 os << format("%9" PRIu64 ":", line.count);
773 source.printNext(os, lineNum);
774
775 uint32_t blockIdx = 0, edgeIdx = 0;
776 for (const GCOVBlock *b : line.blocks) {
777 if (b->getLastLine() != lineNum)
778 continue;
779 if (options.AllBlocks) {
780 if (b->getCount() == 0)
781 os << " $$$$$:";
782 else
783 os << format("%9" PRIu64 ":", b->count);
784 os << format("%5u-block %2u\n", lineNum, blockIdx++);
785 }
786 if (options.BranchInfo) {
787 size_t NumEdges = b->succ.size();
788 if (NumEdges > 1)
789 printBranchInfo(*b, edgeIdx, os);
790 else if (options.UncondBranch && NumEdges == 1) {
791 uint64_t count = b->succ[0]->count;
792 os << format("unconditional %2u ", edgeIdx++)
793 << formatBranchInfo(options, count, count) << '\n';
794 }
795 }
796 }
797 }
798}
799
800void Context::printSourceToIntermediate(const SourceInfo &si,
801 raw_ostream &os) const {
802 os << "file:" << si.filename << '\n';
803 for (const auto &fs : si.startLineToFunctions)
804 for (const GCOVFunction *f : fs)
805 os << "function:" << f->startLine << ',' << f->getEntryCount() << ','
806 << f->getName(options.Demangle) << '\n';
807 for (size_t lineNum = 1, size = si.lines.size(); lineNum < size; ++lineNum) {
808 const LineInfo &line = si.lines[lineNum];
809 if (line.blocks.empty())
810 continue;
811 // GCC 8 (r254259) added third third field for Ada:
812 // lcount:<line>,<count>,<has_unexecuted_blocks>
813 // We don't need the third field.
814 os << "lcount:" << lineNum << ',' << line.count << '\n';
815
816 if (!options.BranchInfo)
817 continue;
818 for (const GCOVBlock *b : line.blocks) {
819 if (b->succ.size() < 2 || b->getLastLine() != lineNum)
820 continue;
821 for (const GCOVArc *arc : b->succ) {
822 const char *type =
823 b->getCount() ? arc->count ? "taken" : "nottaken" : "notexec";
824 os << "branch:" << lineNum << ',' << type << '\n';
825 }
826 }
827 }
828}
829
830void Context::print(StringRef filename, StringRef gcno, StringRef gcda,
831 GCOVFile &file) {
832 for (StringRef filename : file.filenames) {
833 sources.emplace_back(filename);
834 SourceInfo &si = sources.back();
835 si.displayName = si.filename;
836 if (!options.SourcePrefix.empty() &&
837 sys::path::replace_path_prefix(si.displayName, options.SourcePrefix,
838 "") &&
839 !si.displayName.empty()) {
840 // TODO replace_path_prefix may strip the prefix even if the remaining
841 // part does not start with a separator.
842 if (sys::path::is_separator(si.displayName[0]))
843 si.displayName.erase(si.displayName.begin());
844 else
845 si.displayName = si.filename;
846 }
847 if (options.RelativeOnly && sys::path::is_absolute(si.displayName))
848 si.ignored = true;
849 }
850
851 raw_ostream &os = llvm::outs();
852 for (GCOVFunction &f : make_pointee_range(file.functions)) {
853 Summary summary(f.getName(options.Demangle));
854 collectFunction(f, summary);
855 if (options.FuncCoverage && !options.UseStdout) {
856 os << "Function '" << summary.Name << "'\n";
857 printSummary(summary, os);
858 os << '\n';
859 }
860 }
861
862 for (SourceInfo &si : sources) {
863 if (si.ignored)
864 continue;
865 Summary summary(si.displayName);
866 collectSource(si, summary);
867
868 // Print file summary unless -t is specified.
869 std::string gcovName = getCoveragePath(si.filename, filename);
870 if (!options.UseStdout) {
871 os << "File '" << summary.Name << "'\n";
872 printSummary(summary, os);
873 if (!options.NoOutput && !options.Intermediate)
874 os << "Creating '" << gcovName << "'\n";
875 os << '\n';
876 }
877
878 if (options.NoOutput || options.Intermediate)
879 continue;
880 std::optional<raw_fd_ostream> os;
881 if (!options.UseStdout) {
882 std::error_code ec;
883 os.emplace(gcovName, ec, sys::fs::OF_TextWithCRLF);
884 if (ec) {
885 errs() << ec.message() << '\n';
886 continue;
887 }
888 }
889 annotateSource(si, file, gcno, gcda,
890 options.UseStdout ? llvm::outs() : *os);
891 }
892
893 if (options.Intermediate && !options.NoOutput) {
894 // gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0
895 // (PR GCC/82702). We create just one file.
896 std::string outputPath(sys::path::filename(filename));
897 std::error_code ec;
898 raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_TextWithCRLF);
899 if (ec) {
900 errs() << ec.message() << '\n';
901 return;
902 }
903
904 for (const SourceInfo &si : sources)
905 printSourceToIntermediate(si, os);
906 }
907}
908
909void Context::printFunctionDetails(const GCOVFunction &f,
910 raw_ostream &os) const {
911 const uint64_t entryCount = f.getEntryCount();
912 uint32_t blocksExec = 0;
913 const GCOVBlock &exitBlock = f.getExitBlock();
914 uint64_t exitCount = 0;
915 for (const GCOVArc *arc : exitBlock.pred)
916 exitCount += arc->count;
917 for (const GCOVBlock &b : f.blocksRange())
918 if (b.number != 0 && &b != &exitBlock && b.getCount())
919 ++blocksExec;
920
921 os << "function " << f.getName(options.Demangle) << " called " << entryCount
922 << " returned " << formatPercentage(exitCount, entryCount)
923 << "% blocks executed "
924 << formatPercentage(blocksExec, f.blocks.size() - 2) << "%\n";
925}
926
927/// printBranchInfo - Print conditional branch probabilities.
928void Context::printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
929 raw_ostream &os) const {
930 uint64_t total = 0;
931 for (const GCOVArc *arc : Block.dsts())
932 total += arc->count;
933 for (const GCOVArc *arc : Block.dsts())
934 os << format("branch %2u ", edgeIdx++)
935 << formatBranchInfo(options, arc->count, total) << '\n';
936}
937
938void Context::printSummary(const Summary &summary, raw_ostream &os) const {
939 os << format("Lines executed:%.2f%% of %" PRIu64 "\n",
940 double(summary.linesExec) * 100 / summary.lines, summary.lines);
941 if (options.BranchInfo) {
942 if (summary.branches == 0) {
943 os << "No branches\n";
944 } else {
945 os << format("Branches executed:%.2f%% of %" PRIu64 "\n",
946 double(summary.branchesExec) * 100 / summary.branches,
947 summary.branches);
948 os << format("Taken at least once:%.2f%% of %" PRIu64 "\n",
949 double(summary.branchesTaken) * 100 / summary.branches,
950 summary.branches);
951 }
952 os << "No calls\n";
953 }
954}
955
956void llvm::gcovOneInput(const GCOV::Options &options, StringRef filename,
957 StringRef gcno, StringRef gcda, GCOVFile &file) {
958 Context fi(options);
959 fi.print(filename, gcno, gcda, file);
960}
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:603
static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor)
Definition: GCOV.cpp:521
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor)
Definition: GCOV.cpp:531
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:1617
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:149
std::error_code getError() const
Definition: ErrorOr.h:152
GCOVBlock - Collects block information.
Definition: GCOV.h:270
static uint64_t getCyclesCount(const BlockVector &blocks)
Definition: GCOV.cpp:488
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:406
GCOVArc * incoming
Definition: GCOV.h:311
static uint64_t augmentOneCycle(GCOVBlock *src, std::vector< std::pair< GCOVBlock *, size_t > > &stack)
Definition: GCOV.cpp:437
SmallVector< GCOVArc *, 2 > pred
Definition: GCOV.h:307
void dump() const
dump - Dump GCOVBlock content to dbgs() for debugging purposes.
Definition: GCOV.cpp:433
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:356
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:397
StringRef Name
Definition: GCOV.h:261
uint8_t artificial
Definition: GCOV.h:260
uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred)
Definition: GCOV.cpp:368
uint32_t endLine
Definition: GCOV.h:258
SmallVector< std::unique_ptr< GCOVBlock >, 0 > blocks
Definition: GCOV.h:264
GCOVBlock & getExitBlock() const
Definition: GCOV.cpp:360
StringRef getFilename() const
Definition: GCOV.cpp:352
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:388
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:179
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:698
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:1078
@ 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:578
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
Definition: Path.cpp:672
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:519
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:602
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
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:956
char * itaniumDemangle(std::string_view mangled_name)
Returns a non-NULL pointer to a NUL-terminated C style string that should be explicitly freed,...
#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