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 
14 #include "llvm/ProfileData/GCOV.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/Config/llvm-config.h"
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/FileSystem.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/MD5.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <algorithm>
24 #include <system_error>
25 #include <unordered_map>
26 
27 using namespace llvm;
28 
29 enum : uint32_t {
30   GCOV_ARC_ON_TREE = 1 << 0,
31   GCOV_ARC_FALLTHROUGH = 1 << 2,
32 
33   GCOV_TAG_FUNCTION = 0x01000000,
34   GCOV_TAG_BLOCKS = 0x01410000,
35   GCOV_TAG_ARCS = 0x01430000,
36   GCOV_TAG_LINES = 0x01450000,
37   GCOV_TAG_COUNTER_ARCS = 0x01a10000,
38   // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
39   GCOV_TAG_OBJECT_SUMMARY = 0xa1000000,
40   GCOV_TAG_PROGRAM_SUMMARY = 0xa3000000,
41 };
42 
43 namespace {
44 struct Summary {
45   Summary(StringRef Name) : Name(Name) {}
46 
47   StringRef Name;
48   uint64_t lines = 0;
49   uint64_t linesExec = 0;
50   uint64_t branches = 0;
51   uint64_t branchesExec = 0;
52   uint64_t branchesTaken = 0;
53 };
54 
55 struct LineInfo {
56   SmallVector<const GCOVBlock *, 1> blocks;
57   uint64_t count = 0;
58   bool exists = false;
59 };
60 
61 struct SourceInfo {
62   StringRef filename;
63   SmallString<0> displayName;
64   std::vector<std::vector<const GCOVFunction *>> startLineToFunctions;
65   std::vector<LineInfo> lines;
66   bool ignored = false;
67   SourceInfo(StringRef filename) : filename(filename) {}
68 };
69 
70 class Context {
71 public:
72   Context(const GCOV::Options &Options) : options(Options) {}
73   void print(StringRef filename, StringRef gcno, StringRef gcda,
74              GCOVFile &file);
75 
76 private:
77   std::string getCoveragePath(StringRef filename, StringRef mainFilename) const;
78   void printFunctionDetails(const GCOVFunction &f, raw_ostream &os) const;
79   void printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
80                        raw_ostream &OS) const;
81   void printSummary(const Summary &summary, raw_ostream &os) const;
82 
83   void collectFunction(GCOVFunction &f, Summary &summary);
84   void collectSourceLine(SourceInfo &si, Summary *summary, LineInfo &line,
85                          size_t lineNum) const;
86   void collectSource(SourceInfo &si, Summary &summary) const;
87   void annotateSource(SourceInfo &si, const GCOVFile &file, StringRef gcno,
88                       StringRef gcda, raw_ostream &os) const;
89   void printSourceToIntermediate(const SourceInfo &si, raw_ostream &os) const;
90 
91   const GCOV::Options &options;
92   std::vector<SourceInfo> sources;
93 };
94 } // namespace
95 
96 //===----------------------------------------------------------------------===//
97 // GCOVFile implementation.
98 
99 /// readGCNO - Read GCNO buffer.
100 bool GCOVFile::readGCNO(GCOVBuffer &buf) {
101   if (!buf.readGCNOFormat())
102     return false;
103   if (!buf.readGCOVVersion(Version))
104     return false;
105 
106   Checksum = buf.getWord();
107   if (Version >= GCOV::V900)
108     cwd = buf.getString();
109   if (Version >= GCOV::V800)
110     buf.getWord(); // hasUnexecutedBlocks
111 
112   uint32_t tag, length;
113   GCOVFunction *fn;
114   while ((tag = buf.getWord())) {
115     if (!buf.readInt(length))
116       return false;
117     if (tag == GCOV_TAG_FUNCTION) {
118       functions.push_back(std::make_unique<GCOVFunction>(*this));
119       fn = functions.back().get();
120       fn->ident = buf.getWord();
121       fn->linenoChecksum = buf.getWord();
122       if (Version >= GCOV::V407)
123         fn->cfgChecksum = buf.getWord();
124       buf.readString(fn->Name);
125       StringRef filename;
126       if (Version < GCOV::V800) {
127         filename = buf.getString();
128         fn->startLine = buf.getWord();
129       } else {
130         fn->artificial = buf.getWord();
131         filename = buf.getString();
132         fn->startLine = buf.getWord();
133         fn->startColumn = buf.getWord();
134         fn->endLine = buf.getWord();
135         if (Version >= GCOV::V900)
136           fn->endColumn = buf.getWord();
137       }
138       auto r = filenameToIdx.try_emplace(filename, filenameToIdx.size());
139       if (r.second)
140         filenames.emplace_back(filename);
141       fn->srcIdx = r.first->second;
142       IdentToFunction[fn->ident] = fn;
143     } else if (tag == GCOV_TAG_BLOCKS && fn) {
144       if (Version < GCOV::V800) {
145         for (uint32_t i = 0; i != length; ++i) {
146           buf.getWord(); // Ignored block flags
147           fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
148         }
149       } else {
150         uint32_t num = buf.getWord();
151         for (uint32_t i = 0; i != num; ++i)
152           fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
153       }
154     } else if (tag == GCOV_TAG_ARCS && fn) {
155       uint32_t srcNo = buf.getWord();
156       if (srcNo >= fn->blocks.size()) {
157         errs() << "unexpected block number: " << srcNo << " (in "
158                << fn->blocks.size() << ")\n";
159         return false;
160       }
161       GCOVBlock *src = fn->blocks[srcNo].get();
162       for (uint32_t i = 0, e = (length - 1) / 2; i != e; ++i) {
163         uint32_t dstNo = buf.getWord(), flags = buf.getWord();
164         GCOVBlock *dst = fn->blocks[dstNo].get();
165         auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
166         src->addDstEdge(arc.get());
167         dst->addSrcEdge(arc.get());
168         if (arc->onTree())
169           fn->treeArcs.push_back(std::move(arc));
170         else
171           fn->arcs.push_back(std::move(arc));
172       }
173     } else if (tag == GCOV_TAG_LINES && fn) {
174       uint32_t srcNo = buf.getWord();
175       if (srcNo >= fn->blocks.size()) {
176         errs() << "unexpected block number: " << srcNo << " (in "
177                << fn->blocks.size() << ")\n";
178         return false;
179       }
180       GCOVBlock &Block = *fn->blocks[srcNo];
181       for (;;) {
182         uint32_t line = buf.getWord();
183         if (line)
184           Block.addLine(line);
185         else {
186           StringRef filename = buf.getString();
187           if (filename.empty())
188             break;
189           // TODO Unhandled
190         }
191       }
192     }
193   }
194 
195   GCNOInitialized = true;
196   return true;
197 }
198 
199 /// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
200 /// called after readGCNO().
201 bool GCOVFile::readGCDA(GCOVBuffer &buf) {
202   assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
203   if (!buf.readGCDAFormat())
204     return false;
205   GCOV::GCOVVersion GCDAVersion;
206   if (!buf.readGCOVVersion(GCDAVersion))
207     return false;
208   if (Version != GCDAVersion) {
209     errs() << "GCOV versions do not match.\n";
210     return false;
211   }
212 
213   uint32_t GCDAChecksum;
214   if (!buf.readInt(GCDAChecksum))
215     return false;
216   if (Checksum != GCDAChecksum) {
217     errs() << "File checksums do not match: " << Checksum
218            << " != " << GCDAChecksum << ".\n";
219     return false;
220   }
221   uint32_t dummy, tag, length;
222   uint32_t ident;
223   GCOVFunction *fn = nullptr;
224   while ((tag = buf.getWord())) {
225     if (!buf.readInt(length))
226       return false;
227     uint32_t pos = buf.cursor.tell();
228     if (tag == GCOV_TAG_OBJECT_SUMMARY) {
229       buf.readInt(RunCount);
230       buf.readInt(dummy);
231       // clang<11 uses a fake 4.2 format which sets length to 9.
232       if (length == 9)
233         buf.readInt(RunCount);
234     } else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
235       // clang<11 uses a fake 4.2 format which sets length to 0.
236       if (length > 0) {
237         buf.readInt(dummy);
238         buf.readInt(dummy);
239         buf.readInt(RunCount);
240       }
241       ++ProgramCount;
242     } else if (tag == GCOV_TAG_FUNCTION) {
243       if (length == 0) // Placeholder
244         continue;
245       // As of GCC 10, GCOV_TAG_FUNCTION_LENGTH has never been larger than 3.
246       // However, clang<11 uses a fake 4.2 format which may set length larger
247       // than 3.
248       if (length < 2 || !buf.readInt(ident))
249         return false;
250       auto It = IdentToFunction.find(ident);
251       uint32_t linenoChecksum, cfgChecksum = 0;
252       buf.readInt(linenoChecksum);
253       if (Version >= GCOV::V407)
254         buf.readInt(cfgChecksum);
255       if (It != IdentToFunction.end()) {
256         fn = It->second;
257         if (linenoChecksum != fn->linenoChecksum ||
258             cfgChecksum != fn->cfgChecksum) {
259           errs() << fn->Name
260                  << format(": checksum mismatch, (%u, %u) != (%u, %u)\n",
261                            linenoChecksum, cfgChecksum, fn->linenoChecksum,
262                            fn->cfgChecksum);
263           return false;
264         }
265       }
266     } else if (tag == GCOV_TAG_COUNTER_ARCS && fn) {
267       if (length != 2 * fn->arcs.size()) {
268         errs() << fn->Name
269                << format(
270                       ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
271                       length, unsigned(2 * fn->arcs.size()));
272         return false;
273       }
274       for (std::unique_ptr<GCOVArc> &arc : fn->arcs) {
275         if (!buf.readInt64(arc->count))
276           return false;
277         arc->src.count += arc->count;
278       }
279 
280       if (fn->blocks.size() >= 2) {
281         GCOVBlock &src = *fn->blocks[0];
282         GCOVBlock &sink =
283             Version < GCOV::V408 ? *fn->blocks.back() : *fn->blocks[1];
284         auto arc = std::make_unique<GCOVArc>(sink, src, GCOV_ARC_ON_TREE);
285         sink.addDstEdge(arc.get());
286         src.addSrcEdge(arc.get());
287         fn->treeArcs.push_back(std::move(arc));
288 
289         for (GCOVBlock &block : fn->blocksRange())
290           fn->propagateCounts(block, nullptr);
291         for (size_t i = fn->treeArcs.size() - 1; i; --i)
292           fn->treeArcs[i - 1]->src.count += fn->treeArcs[i - 1]->count;
293       }
294     }
295     pos += 4 * length;
296     if (pos < buf.cursor.tell())
297       return false;
298     buf.de.skip(buf.cursor, pos - buf.cursor.tell());
299   }
300 
301   return true;
302 }
303 
304 void GCOVFile::print(raw_ostream &OS) const {
305   for (const GCOVFunction &f : *this)
306     f.print(OS);
307 }
308 
309 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
310 /// dump - Dump GCOVFile content to dbgs() for debugging purposes.
311 LLVM_DUMP_METHOD void GCOVFile::dump() const { print(dbgs()); }
312 #endif
313 
314 bool GCOVArc::onTree() const { return flags & GCOV_ARC_ON_TREE; }
315 
316 //===----------------------------------------------------------------------===//
317 // GCOVFunction implementation.
318 
319 StringRef GCOVFunction::getFilename() const { return file.filenames[srcIdx]; }
320 
321 /// getEntryCount - Get the number of times the function was called by
322 /// retrieving the entry block's count.
323 uint64_t GCOVFunction::getEntryCount() const {
324   return blocks.front()->getCount();
325 }
326 
327 GCOVBlock &GCOVFunction::getExitBlock() const {
328   return file.getVersion() < GCOV::V408 ? *blocks.back() : *blocks[1];
329 }
330 
331 // For each basic block, the sum of incoming edge counts equals the sum of
332 // outgoing edge counts by Kirchoff's circuit law. If the unmeasured arcs form a
333 // spanning tree, the count for each unmeasured arc (GCOV_ARC_ON_TREE) can be
334 // uniquely identified.
335 uint64_t GCOVFunction::propagateCounts(const GCOVBlock &v, GCOVArc *pred) {
336   // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed; otherwise
337   // this prevents infinite recursion.
338   if (!visited.insert(&v).second)
339     return 0;
340 
341   uint64_t excess = 0;
342   for (GCOVArc *e : v.srcs())
343     if (e != pred)
344       excess += e->onTree() ? propagateCounts(e->src, e) : e->count;
345   for (GCOVArc *e : v.dsts())
346     if (e != pred)
347       excess -= e->onTree() ? propagateCounts(e->dst, e) : e->count;
348   if (int64_t(excess) < 0)
349     excess = -excess;
350   if (pred)
351     pred->count = excess;
352   return excess;
353 }
354 
355 void GCOVFunction::print(raw_ostream &OS) const {
356   OS << "===== " << Name << " (" << ident << ") @ " << getFilename() << ":"
357      << startLine << "\n";
358   for (const auto &Block : blocks)
359     Block->print(OS);
360 }
361 
362 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
363 /// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
364 LLVM_DUMP_METHOD void GCOVFunction::dump() const { print(dbgs()); }
365 #endif
366 
367 /// collectLineCounts - Collect line counts. This must be used after
368 /// reading .gcno and .gcda files.
369 
370 //===----------------------------------------------------------------------===//
371 // GCOVBlock implementation.
372 
373 void GCOVBlock::print(raw_ostream &OS) const {
374   OS << "Block : " << number << " Counter : " << count << "\n";
375   if (!pred.empty()) {
376     OS << "\tSource Edges : ";
377     for (const GCOVArc *Edge : pred)
378       OS << Edge->src.number << " (" << Edge->count << "), ";
379     OS << "\n";
380   }
381   if (!succ.empty()) {
382     OS << "\tDestination Edges : ";
383     for (const GCOVArc *Edge : succ) {
384       if (Edge->flags & GCOV_ARC_ON_TREE)
385         OS << '*';
386       OS << Edge->dst.number << " (" << Edge->count << "), ";
387     }
388     OS << "\n";
389   }
390   if (!lines.empty()) {
391     OS << "\tLines : ";
392     for (uint32_t N : lines)
393       OS << (N) << ",";
394     OS << "\n";
395   }
396 }
397 
398 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
399 /// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
400 LLVM_DUMP_METHOD void GCOVBlock::dump() const { print(dbgs()); }
401 #endif
402 
403 //===----------------------------------------------------------------------===//
404 // Cycles detection
405 //
406 // The algorithm in GCC is based on the algorithm by Hawick & James:
407 //   "Enumerating Circuits and Loops in Graphs with Self-Arcs and Multiple-Arcs"
408 //   http://complexity.massey.ac.nz/cstn/013/cstn-013.pdf.
409 
410 /// Get the count for the detected cycle.
411 uint64_t GCOVBlock::getCycleCount(const Edges &Path) {
412   uint64_t CycleCount = std::numeric_limits<uint64_t>::max();
413   for (auto E : Path) {
414     CycleCount = std::min(E->cycleCount, CycleCount);
415   }
416   for (auto E : Path) {
417     E->cycleCount -= CycleCount;
418   }
419   return CycleCount;
420 }
421 
422 /// Unblock a vertex previously marked as blocked.
423 void GCOVBlock::unblock(const GCOVBlock *U, BlockVector &Blocked,
424                         BlockVectorLists &BlockLists) {
425   auto it = find(Blocked, U);
426   if (it == Blocked.end()) {
427     return;
428   }
429 
430   const size_t index = it - Blocked.begin();
431   Blocked.erase(it);
432 
433   const BlockVector ToUnblock(BlockLists[index]);
434   BlockLists.erase(BlockLists.begin() + index);
435   for (auto GB : ToUnblock) {
436     GCOVBlock::unblock(GB, Blocked, BlockLists);
437   }
438 }
439 
440 bool GCOVBlock::lookForCircuit(const GCOVBlock *V, const GCOVBlock *Start,
441                                Edges &Path, BlockVector &Blocked,
442                                BlockVectorLists &BlockLists,
443                                const BlockVector &Blocks, uint64_t &Count) {
444   Blocked.push_back(V);
445   BlockLists.emplace_back(BlockVector());
446   bool FoundCircuit = false;
447 
448   for (auto E : V->dsts()) {
449     const GCOVBlock *W = &E->dst;
450     if (W < Start || find(Blocks, W) == Blocks.end()) {
451       continue;
452     }
453 
454     Path.push_back(E);
455 
456     if (W == Start) {
457       // We've a cycle.
458       Count += GCOVBlock::getCycleCount(Path);
459       FoundCircuit = true;
460     } else if (find(Blocked, W) == Blocked.end() && // W is not blocked.
461                GCOVBlock::lookForCircuit(W, Start, Path, Blocked, BlockLists,
462                                          Blocks, Count)) {
463       FoundCircuit = true;
464     }
465 
466     Path.pop_back();
467   }
468 
469   if (FoundCircuit) {
470     GCOVBlock::unblock(V, Blocked, BlockLists);
471   } else {
472     for (auto E : V->dsts()) {
473       const GCOVBlock *W = &E->dst;
474       if (W < Start || find(Blocks, W) == Blocks.end()) {
475         continue;
476       }
477       const size_t index = find(Blocked, W) - Blocked.begin();
478       BlockVector &List = BlockLists[index];
479       if (find(List, V) == List.end()) {
480         List.push_back(V);
481       }
482     }
483   }
484 
485   return FoundCircuit;
486 }
487 
488 /// Get the count for the list of blocks which lie on the same line.
489 void GCOVBlock::getCyclesCount(const BlockVector &Blocks, uint64_t &Count) {
490   for (auto Block : Blocks) {
491     Edges Path;
492     BlockVector Blocked;
493     BlockVectorLists BlockLists;
494 
495     GCOVBlock::lookForCircuit(Block, Block, Path, Blocked, BlockLists, Blocks,
496                               Count);
497   }
498 }
499 
500 //===----------------------------------------------------------------------===//
501 // FileInfo implementation.
502 
503 // Format dividend/divisor as a percentage. Return 1 if the result is greater
504 // than 0% and less than 1%.
505 static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor) {
506   if (!dividend || !divisor)
507     return 0;
508   dividend *= 100;
509   return dividend < divisor ? 1 : dividend / divisor;
510 }
511 
512 // This custom division function mimics gcov's branch ouputs:
513 //   - Round to closest whole number
514 //   - Only output 0% or 100% if it's exactly that value
515 static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
516   if (!Numerator)
517     return 0;
518   if (Numerator == Divisor)
519     return 100;
520 
521   uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
522   if (Res == 0)
523     return 1;
524   if (Res == 100)
525     return 99;
526   return Res;
527 }
528 
529 namespace {
530 struct formatBranchInfo {
531   formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
532       : Options(Options), Count(Count), Total(Total) {}
533 
534   void print(raw_ostream &OS) const {
535     if (!Total)
536       OS << "never executed";
537     else if (Options.BranchCount)
538       OS << "taken " << Count;
539     else
540       OS << "taken " << branchDiv(Count, Total) << "%";
541   }
542 
543   const GCOV::Options &Options;
544   uint64_t Count;
545   uint64_t Total;
546 };
547 
548 static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
549   FBI.print(OS);
550   return OS;
551 }
552 
553 class LineConsumer {
554   std::unique_ptr<MemoryBuffer> Buffer;
555   StringRef Remaining;
556 
557 public:
558   LineConsumer() = default;
559   LineConsumer(StringRef Filename) {
560     // Open source files without requiring a NUL terminator. The concurrent
561     // modification may nullify the NUL terminator condition.
562     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
563         MemoryBuffer::getFileOrSTDIN(Filename, -1,
564                                      /*RequiresNullTerminator=*/false);
565     if (std::error_code EC = BufferOrErr.getError()) {
566       errs() << Filename << ": " << EC.message() << "\n";
567       Remaining = "";
568     } else {
569       Buffer = std::move(BufferOrErr.get());
570       Remaining = Buffer->getBuffer();
571     }
572   }
573   bool empty() { return Remaining.empty(); }
574   void printNext(raw_ostream &OS, uint32_t LineNum) {
575     StringRef Line;
576     if (empty())
577       Line = "/*EOF*/";
578     else
579       std::tie(Line, Remaining) = Remaining.split("\n");
580     OS << format("%5u:", LineNum) << Line << "\n";
581   }
582 };
583 } // end anonymous namespace
584 
585 /// Convert a path to a gcov filename. If PreservePaths is true, this
586 /// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
587 static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
588   if (!PreservePaths)
589     return sys::path::filename(Filename).str();
590 
591   // This behaviour is defined by gcov in terms of text replacements, so it's
592   // not likely to do anything useful on filesystems with different textual
593   // conventions.
594   llvm::SmallString<256> Result("");
595   StringRef::iterator I, S, E;
596   for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
597     if (*I != '/')
598       continue;
599 
600     if (I - S == 1 && *S == '.') {
601       // ".", the current directory, is skipped.
602     } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
603       // "..", the parent directory, is replaced with "^".
604       Result.append("^#");
605     } else {
606       if (S < I)
607         // Leave other components intact,
608         Result.append(S, I);
609       // And separate with "#".
610       Result.push_back('#');
611     }
612     S = I + 1;
613   }
614 
615   if (S < I)
616     Result.append(S, I);
617   return std::string(Result.str());
618 }
619 
620 std::string Context::getCoveragePath(StringRef filename,
621                                      StringRef mainFilename) const {
622   if (options.NoOutput)
623     // This is probably a bug in gcov, but when -n is specified, paths aren't
624     // mangled at all, and the -l and -p options are ignored. Here, we do the
625     // same.
626     return std::string(filename);
627 
628   std::string CoveragePath;
629   if (options.LongFileNames && !filename.equals(mainFilename))
630     CoveragePath =
631         mangleCoveragePath(mainFilename, options.PreservePaths) + "##";
632   CoveragePath += mangleCoveragePath(filename, options.PreservePaths);
633   if (options.HashFilenames) {
634     MD5 Hasher;
635     MD5::MD5Result Result;
636     Hasher.update(filename.str());
637     Hasher.final(Result);
638     CoveragePath += "##" + std::string(Result.digest());
639   }
640   CoveragePath += ".gcov";
641   return CoveragePath;
642 }
643 
644 void Context::collectFunction(GCOVFunction &f, Summary &summary) {
645   SourceInfo &si = sources[f.srcIdx];
646   if (f.startLine >= si.startLineToFunctions.size())
647     si.startLineToFunctions.resize(f.startLine + 1);
648   si.startLineToFunctions[f.startLine].push_back(&f);
649   for (const GCOVBlock &b : f.blocksRange()) {
650     if (b.lines.empty())
651       continue;
652     uint32_t maxLineNum = *std::max_element(b.lines.begin(), b.lines.end());
653     if (maxLineNum >= si.lines.size())
654       si.lines.resize(maxLineNum + 1);
655     for (uint32_t lineNum : b.lines) {
656       LineInfo &line = si.lines[lineNum];
657       if (!line.exists)
658         ++summary.lines;
659       if (line.count == 0 && b.count)
660         ++summary.linesExec;
661       line.exists = true;
662       line.count += b.count;
663       line.blocks.push_back(&b);
664     }
665   }
666 }
667 
668 void Context::collectSourceLine(SourceInfo &si, Summary *summary,
669                                 LineInfo &line, size_t lineNum) const {
670   uint64_t count = 0;
671   for (const GCOVBlock *b : line.blocks) {
672     if (b->number == 0) {
673       // For nonstandard control flows, arcs into the exit block may be
674       // duplicately counted (fork) or not be counted (abnormal exit), and thus
675       // the (exit,entry) counter may be inaccurate. Count the entry block with
676       // the outgoing arcs.
677       for (const GCOVArc *arc : b->succ)
678         count += arc->count;
679     } else {
680       // Add counts from predecessors that are not on the same line.
681       for (const GCOVArc *arc : b->pred)
682         if (!llvm::is_contained(line.blocks, &arc->src))
683           count += arc->count;
684     }
685     for (GCOVArc *arc : b->succ)
686       arc->cycleCount = arc->count;
687   }
688 
689   GCOVBlock::getCyclesCount(line.blocks, count);
690   line.count = count;
691   if (line.exists) {
692     ++summary->lines;
693     if (line.count != 0)
694       ++summary->linesExec;
695   }
696 
697   if (options.BranchInfo)
698     for (const GCOVBlock *b : line.blocks) {
699       if (b->getLastLine() != lineNum)
700         continue;
701       int branches = 0, execBranches = 0, takenBranches = 0;
702       for (const GCOVArc *arc : b->succ) {
703         ++branches;
704         if (count != 0)
705           ++execBranches;
706         if (arc->count != 0)
707           ++takenBranches;
708       }
709       if (branches > 1) {
710         summary->branches += branches;
711         summary->branchesExec += execBranches;
712         summary->branchesTaken += takenBranches;
713       }
714     }
715 }
716 
717 void Context::collectSource(SourceInfo &si, Summary &summary) const {
718   size_t lineNum = 0;
719   for (LineInfo &line : si.lines) {
720     collectSourceLine(si, &summary, line, lineNum);
721     ++lineNum;
722   }
723 }
724 
725 void Context::annotateSource(SourceInfo &si, const GCOVFile &file,
726                              StringRef gcno, StringRef gcda,
727                              raw_ostream &os) const {
728   auto source =
729       options.Intermediate ? LineConsumer() : LineConsumer(si.filename);
730 
731   os << "        -:    0:Source:" << si.displayName << '\n';
732   os << "        -:    0:Graph:" << gcno << '\n';
733   os << "        -:    0:Data:" << gcda << '\n';
734   os << "        -:    0:Runs:" << file.RunCount << '\n';
735   if (file.Version < GCOV::V900)
736     os << "        -:    0:Programs:" << file.ProgramCount << '\n';
737 
738   for (size_t lineNum = 1; !source.empty(); ++lineNum) {
739     if (lineNum >= si.lines.size()) {
740       os << "        -:";
741       source.printNext(os, lineNum);
742       continue;
743     }
744 
745     const LineInfo &line = si.lines[lineNum];
746     if (options.BranchInfo && lineNum < si.startLineToFunctions.size())
747       for (const auto *f : si.startLineToFunctions[lineNum])
748         printFunctionDetails(*f, os);
749     if (!line.exists)
750       os << "        -:";
751     else if (line.count == 0)
752       os << "    #####:";
753     else
754       os << format("%9" PRIu64 ":", line.count);
755     source.printNext(os, lineNum);
756 
757     uint32_t blockIdx = 0, edgeIdx = 0;
758     for (const GCOVBlock *b : line.blocks) {
759       if (b->getLastLine() != lineNum)
760         continue;
761       if (options.AllBlocks) {
762         if (b->getCount() == 0)
763           os << "    $$$$$:";
764         else
765           os << format("%9" PRIu64 ":", b->count);
766         os << format("%5u-block %2u\n", lineNum, blockIdx++);
767       }
768       if (options.BranchInfo) {
769         size_t NumEdges = b->succ.size();
770         if (NumEdges > 1)
771           printBranchInfo(*b, edgeIdx, os);
772         else if (options.UncondBranch && NumEdges == 1) {
773           uint64_t count = b->succ[0]->count;
774           os << format("unconditional %2u ", edgeIdx++)
775              << formatBranchInfo(options, count, count) << '\n';
776         }
777       }
778     }
779   }
780 }
781 
782 void Context::printSourceToIntermediate(const SourceInfo &si,
783                                         raw_ostream &os) const {
784   os << "file:" << si.filename << '\n';
785   for (const auto &fs : si.startLineToFunctions)
786     for (const GCOVFunction *f : fs)
787       os << "function:" << f->startLine << ',' << f->getEntryCount() << ','
788          << f->Name << '\n';
789   for (size_t lineNum = 1, size = si.lines.size(); lineNum < size; ++lineNum) {
790     const LineInfo &line = si.lines[lineNum];
791     if (line.blocks.empty())
792       continue;
793     // GCC 8 (r254259) added third third field for Ada:
794     // lcount:<line>,<count>,<has_unexecuted_blocks>
795     // We don't need the third field.
796     os << "lcount:" << lineNum << ',' << line.count << '\n';
797 
798     if (!options.BranchInfo)
799       continue;
800     for (const GCOVBlock *b : line.blocks) {
801       if (b->succ.size() < 2 || b->getLastLine() != lineNum)
802         continue;
803       for (const GCOVArc *arc : b->succ) {
804         const char *type =
805             b->getCount() ? arc->count ? "taken" : "nottaken" : "notexec";
806         os << "branch:" << lineNum << ',' << type << '\n';
807       }
808     }
809   }
810 }
811 
812 void Context::print(StringRef filename, StringRef gcno, StringRef gcda,
813                     GCOVFile &file) {
814   for (StringRef filename : file.filenames) {
815     sources.emplace_back(filename);
816     SourceInfo &si = sources.back();
817     si.displayName = si.filename;
818     if (!options.SourcePrefix.empty() &&
819         sys::path::replace_path_prefix(si.displayName, options.SourcePrefix,
820                                        "") &&
821         !si.displayName.empty()) {
822       // TODO replace_path_prefix may strip the prefix even if the remaining
823       // part does not start with a separator.
824       if (sys::path::is_separator(si.displayName[0]))
825         si.displayName.erase(si.displayName.begin());
826       else
827         si.displayName = si.filename;
828     }
829     if (options.RelativeOnly && sys::path::is_absolute(si.displayName))
830       si.ignored = true;
831   }
832 
833   raw_ostream &os = llvm::outs();
834   for (GCOVFunction &f : make_pointee_range(file.functions)) {
835     Summary summary(f.Name);
836     collectFunction(f, summary);
837     if (options.FuncCoverage && !options.UseStdout) {
838       os << "Function '" << summary.Name << "'\n";
839       printSummary(summary, os);
840       os << '\n';
841     }
842   }
843 
844   for (SourceInfo &si : sources) {
845     if (si.ignored)
846       continue;
847     Summary summary(si.displayName);
848     collectSource(si, summary);
849 
850     // Print file summary unless -t is specified.
851     std::string gcovName = getCoveragePath(si.filename, filename);
852     if (!options.UseStdout) {
853       os << "File '" << summary.Name << "'\n";
854       printSummary(summary, os);
855       if (!options.NoOutput && !options.Intermediate)
856         os << "Creating '" << gcovName << "'\n";
857       os << '\n';
858     }
859 
860     if (options.NoOutput || options.Intermediate)
861       continue;
862     Optional<raw_fd_ostream> os;
863     if (!options.UseStdout) {
864       std::error_code ec;
865       os.emplace(gcovName, ec, sys::fs::OF_Text);
866       if (ec) {
867         errs() << ec.message() << '\n';
868         continue;
869       }
870     }
871     annotateSource(si, file, gcno, gcda,
872                    options.UseStdout ? llvm::outs() : *os);
873   }
874 
875   if (options.Intermediate && !options.NoOutput) {
876     // gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0
877     // (PR GCC/82702). We create just one file.
878     std::string outputPath(sys::path::filename(filename));
879     std::error_code ec;
880     raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_Text);
881     if (ec) {
882       errs() << ec.message() << '\n';
883       return;
884     }
885 
886     for (const SourceInfo &si : sources)
887       printSourceToIntermediate(si, os);
888   }
889 }
890 
891 void Context::printFunctionDetails(const GCOVFunction &f,
892                                    raw_ostream &os) const {
893   const uint64_t entryCount = f.getEntryCount();
894   uint32_t blocksExec = 0;
895   const GCOVBlock &exitBlock = f.getExitBlock();
896   uint64_t exitCount = 0;
897   for (const GCOVArc *arc : exitBlock.pred)
898     exitCount += arc->count;
899   for (const GCOVBlock &b : f.blocksRange())
900     if (b.number != 0 && &b != &exitBlock && b.getCount())
901       ++blocksExec;
902 
903   os << "function " << f.getName() << " called " << entryCount << " returned "
904      << formatPercentage(exitCount, entryCount) << "% blocks executed "
905      << formatPercentage(blocksExec, f.blocks.size() - 2) << "%\n";
906 }
907 
908 /// printBranchInfo - Print conditional branch probabilities.
909 void Context::printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
910                               raw_ostream &os) const {
911   uint64_t total = 0;
912   for (const GCOVArc *arc : Block.dsts())
913     total += arc->count;
914   for (const GCOVArc *arc : Block.dsts())
915     os << format("branch %2u ", edgeIdx++)
916        << formatBranchInfo(options, arc->count, total) << '\n';
917 }
918 
919 void Context::printSummary(const Summary &summary, raw_ostream &os) const {
920   os << format("Lines executed:%.2f%% of %u\n",
921                double(summary.linesExec) * 100 / summary.lines, summary.lines);
922   if (options.BranchInfo) {
923     if (summary.branches == 0) {
924       os << "No branches\n";
925     } else {
926       os << format("Branches executed:%.2f%% of %u\n",
927                    double(summary.branchesExec) * 100 / summary.branches,
928                    summary.branches);
929       os << format("Taken at least once:%.2f%% of %u\n",
930                    double(summary.branchesTaken) * 100 / summary.branches,
931                    summary.branches);
932     }
933     os << "No calls\n";
934   }
935 }
936 
937 void llvm::gcovOneInput(const GCOV::Options &options, StringRef filename,
938                         StringRef gcno, StringRef gcda, GCOVFile &file) {
939   Context fi(options);
940   fi.print(filename, gcno, gcda, file);
941 }
942