10b57cec5SDimitry Andric //===- GCOV.cpp - LLVM coverage tool --------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // GCOV implements the interface to read and write coverage files that use
100b57cec5SDimitry Andric // 'gcov' format.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ProfileData/GCOV.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
160b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
17e8d8bef9SDimitry Andric #include "llvm/Demangle/Demangle.h"
180b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
190b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
200b57cec5SDimitry Andric #include "llvm/Support/Format.h"
210b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
22e8d8bef9SDimitry Andric #include "llvm/Support/Path.h"
230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
240b57cec5SDimitry Andric #include <algorithm>
250b57cec5SDimitry Andric #include <system_error>
26e8d8bef9SDimitry Andric #include <unordered_map>
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric using namespace llvm;
290b57cec5SDimitry Andric 
305ffd83dbSDimitry Andric enum : uint32_t {
315ffd83dbSDimitry Andric   GCOV_ARC_ON_TREE = 1 << 0,
325ffd83dbSDimitry Andric   GCOV_ARC_FALLTHROUGH = 1 << 2,
335ffd83dbSDimitry Andric 
345ffd83dbSDimitry Andric   GCOV_TAG_FUNCTION = 0x01000000,
355ffd83dbSDimitry Andric   GCOV_TAG_BLOCKS = 0x01410000,
365ffd83dbSDimitry Andric   GCOV_TAG_ARCS = 0x01430000,
375ffd83dbSDimitry Andric   GCOV_TAG_LINES = 0x01450000,
385ffd83dbSDimitry Andric   GCOV_TAG_COUNTER_ARCS = 0x01a10000,
395ffd83dbSDimitry Andric   // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
405ffd83dbSDimitry Andric   GCOV_TAG_OBJECT_SUMMARY = 0xa1000000,
415ffd83dbSDimitry Andric   GCOV_TAG_PROGRAM_SUMMARY = 0xa3000000,
425ffd83dbSDimitry Andric };
435ffd83dbSDimitry Andric 
44e8d8bef9SDimitry Andric namespace {
45e8d8bef9SDimitry Andric struct Summary {
46e8d8bef9SDimitry Andric   Summary(StringRef Name) : Name(Name) {}
47e8d8bef9SDimitry Andric 
48e8d8bef9SDimitry Andric   StringRef Name;
49e8d8bef9SDimitry Andric   uint64_t lines = 0;
50e8d8bef9SDimitry Andric   uint64_t linesExec = 0;
51e8d8bef9SDimitry Andric   uint64_t branches = 0;
52e8d8bef9SDimitry Andric   uint64_t branchesExec = 0;
53e8d8bef9SDimitry Andric   uint64_t branchesTaken = 0;
54e8d8bef9SDimitry Andric };
55e8d8bef9SDimitry Andric 
56e8d8bef9SDimitry Andric struct LineInfo {
57e8d8bef9SDimitry Andric   SmallVector<const GCOVBlock *, 1> blocks;
58e8d8bef9SDimitry Andric   uint64_t count = 0;
59e8d8bef9SDimitry Andric   bool exists = false;
60e8d8bef9SDimitry Andric };
61e8d8bef9SDimitry Andric 
62e8d8bef9SDimitry Andric struct SourceInfo {
63e8d8bef9SDimitry Andric   StringRef filename;
64e8d8bef9SDimitry Andric   SmallString<0> displayName;
65e8d8bef9SDimitry Andric   std::vector<std::vector<const GCOVFunction *>> startLineToFunctions;
66e8d8bef9SDimitry Andric   std::vector<LineInfo> lines;
67e8d8bef9SDimitry Andric   bool ignored = false;
68e8d8bef9SDimitry Andric   SourceInfo(StringRef filename) : filename(filename) {}
69e8d8bef9SDimitry Andric };
70e8d8bef9SDimitry Andric 
71e8d8bef9SDimitry Andric class Context {
72e8d8bef9SDimitry Andric public:
73e8d8bef9SDimitry Andric   Context(const GCOV::Options &Options) : options(Options) {}
74e8d8bef9SDimitry Andric   void print(StringRef filename, StringRef gcno, StringRef gcda,
75e8d8bef9SDimitry Andric              GCOVFile &file);
76e8d8bef9SDimitry Andric 
77e8d8bef9SDimitry Andric private:
78e8d8bef9SDimitry Andric   std::string getCoveragePath(StringRef filename, StringRef mainFilename) const;
79e8d8bef9SDimitry Andric   void printFunctionDetails(const GCOVFunction &f, raw_ostream &os) const;
80e8d8bef9SDimitry Andric   void printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
81e8d8bef9SDimitry Andric                        raw_ostream &OS) const;
82e8d8bef9SDimitry Andric   void printSummary(const Summary &summary, raw_ostream &os) const;
83e8d8bef9SDimitry Andric 
84e8d8bef9SDimitry Andric   void collectFunction(GCOVFunction &f, Summary &summary);
85e8d8bef9SDimitry Andric   void collectSourceLine(SourceInfo &si, Summary *summary, LineInfo &line,
86e8d8bef9SDimitry Andric                          size_t lineNum) const;
87e8d8bef9SDimitry Andric   void collectSource(SourceInfo &si, Summary &summary) const;
88e8d8bef9SDimitry Andric   void annotateSource(SourceInfo &si, const GCOVFile &file, StringRef gcno,
89e8d8bef9SDimitry Andric                       StringRef gcda, raw_ostream &os) const;
90e8d8bef9SDimitry Andric   void printSourceToIntermediate(const SourceInfo &si, raw_ostream &os) const;
91e8d8bef9SDimitry Andric 
92e8d8bef9SDimitry Andric   const GCOV::Options &options;
93e8d8bef9SDimitry Andric   std::vector<SourceInfo> sources;
94e8d8bef9SDimitry Andric };
95e8d8bef9SDimitry Andric } // namespace
96e8d8bef9SDimitry Andric 
970b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
980b57cec5SDimitry Andric // GCOVFile implementation.
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric /// readGCNO - Read GCNO buffer.
1015ffd83dbSDimitry Andric bool GCOVFile::readGCNO(GCOVBuffer &buf) {
1025ffd83dbSDimitry Andric   if (!buf.readGCNOFormat())
1030b57cec5SDimitry Andric     return false;
104fe6060f1SDimitry Andric   if (!buf.readGCOVVersion(version))
1050b57cec5SDimitry Andric     return false;
1060b57cec5SDimitry Andric 
107fe6060f1SDimitry Andric   checksum = buf.getWord();
108fe6060f1SDimitry Andric   if (version >= GCOV::V900 && !buf.readString(cwd))
109fe6060f1SDimitry Andric     return false;
110fe6060f1SDimitry Andric   if (version >= GCOV::V800)
1115ffd83dbSDimitry Andric     buf.getWord(); // hasUnexecutedBlocks
1125ffd83dbSDimitry Andric 
1135ffd83dbSDimitry Andric   uint32_t tag, length;
114e8d8bef9SDimitry Andric   GCOVFunction *fn = nullptr;
1155ffd83dbSDimitry Andric   while ((tag = buf.getWord())) {
1165ffd83dbSDimitry Andric     if (!buf.readInt(length))
1170b57cec5SDimitry Andric       return false;
118fe6060f1SDimitry Andric     uint32_t pos = buf.cursor.tell();
1195ffd83dbSDimitry Andric     if (tag == GCOV_TAG_FUNCTION) {
120e8d8bef9SDimitry Andric       functions.push_back(std::make_unique<GCOVFunction>(*this));
121e8d8bef9SDimitry Andric       fn = functions.back().get();
1225ffd83dbSDimitry Andric       fn->ident = buf.getWord();
1235ffd83dbSDimitry Andric       fn->linenoChecksum = buf.getWord();
124fe6060f1SDimitry Andric       if (version >= GCOV::V407)
1255ffd83dbSDimitry Andric         fn->cfgChecksum = buf.getWord();
1265ffd83dbSDimitry Andric       buf.readString(fn->Name);
1275ffd83dbSDimitry Andric       StringRef filename;
128fe6060f1SDimitry Andric       if (version < GCOV::V800) {
129fe6060f1SDimitry Andric         if (!buf.readString(filename))
130fe6060f1SDimitry Andric           return false;
1315ffd83dbSDimitry Andric         fn->startLine = buf.getWord();
1325ffd83dbSDimitry Andric       } else {
1335ffd83dbSDimitry Andric         fn->artificial = buf.getWord();
134fe6060f1SDimitry Andric         if (!buf.readString(filename))
135fe6060f1SDimitry Andric           return false;
1365ffd83dbSDimitry Andric         fn->startLine = buf.getWord();
1375ffd83dbSDimitry Andric         fn->startColumn = buf.getWord();
1385ffd83dbSDimitry Andric         fn->endLine = buf.getWord();
139fe6060f1SDimitry Andric         if (version >= GCOV::V900)
1405ffd83dbSDimitry Andric           fn->endColumn = buf.getWord();
1415ffd83dbSDimitry Andric       }
1425ffd83dbSDimitry Andric       auto r = filenameToIdx.try_emplace(filename, filenameToIdx.size());
1435ffd83dbSDimitry Andric       if (r.second)
1445ffd83dbSDimitry Andric         filenames.emplace_back(filename);
1455ffd83dbSDimitry Andric       fn->srcIdx = r.first->second;
146fe6060f1SDimitry Andric       identToFunction[fn->ident] = fn;
1475ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_BLOCKS && fn) {
148fe6060f1SDimitry Andric       if (version < GCOV::V800) {
1495ffd83dbSDimitry Andric         for (uint32_t i = 0; i != length; ++i) {
1505ffd83dbSDimitry Andric           buf.getWord(); // Ignored block flags
151e8d8bef9SDimitry Andric           fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
1525ffd83dbSDimitry Andric         }
1535ffd83dbSDimitry Andric       } else {
1545ffd83dbSDimitry Andric         uint32_t num = buf.getWord();
1555ffd83dbSDimitry Andric         for (uint32_t i = 0; i != num; ++i)
156e8d8bef9SDimitry Andric           fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
1575ffd83dbSDimitry Andric       }
1585ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_ARCS && fn) {
1595ffd83dbSDimitry Andric       uint32_t srcNo = buf.getWord();
160e8d8bef9SDimitry Andric       if (srcNo >= fn->blocks.size()) {
1615ffd83dbSDimitry Andric         errs() << "unexpected block number: " << srcNo << " (in "
162e8d8bef9SDimitry Andric                << fn->blocks.size() << ")\n";
1635ffd83dbSDimitry Andric         return false;
1645ffd83dbSDimitry Andric       }
165e8d8bef9SDimitry Andric       GCOVBlock *src = fn->blocks[srcNo].get();
166fe6060f1SDimitry Andric       const uint32_t e =
167fe6060f1SDimitry Andric           version >= GCOV::V1200 ? (length / 4 - 1) / 2 : (length - 1) / 2;
168fe6060f1SDimitry Andric       for (uint32_t i = 0; i != e; ++i) {
1695ffd83dbSDimitry Andric         uint32_t dstNo = buf.getWord(), flags = buf.getWord();
170e8d8bef9SDimitry Andric         GCOVBlock *dst = fn->blocks[dstNo].get();
171e8d8bef9SDimitry Andric         auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
1725ffd83dbSDimitry Andric         src->addDstEdge(arc.get());
1735ffd83dbSDimitry Andric         dst->addSrcEdge(arc.get());
174e8d8bef9SDimitry Andric         if (arc->onTree())
1755ffd83dbSDimitry Andric           fn->treeArcs.push_back(std::move(arc));
1765ffd83dbSDimitry Andric         else
1775ffd83dbSDimitry Andric           fn->arcs.push_back(std::move(arc));
1785ffd83dbSDimitry Andric       }
1795ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_LINES && fn) {
1805ffd83dbSDimitry Andric       uint32_t srcNo = buf.getWord();
181e8d8bef9SDimitry Andric       if (srcNo >= fn->blocks.size()) {
1825ffd83dbSDimitry Andric         errs() << "unexpected block number: " << srcNo << " (in "
183e8d8bef9SDimitry Andric                << fn->blocks.size() << ")\n";
1845ffd83dbSDimitry Andric         return false;
1855ffd83dbSDimitry Andric       }
186e8d8bef9SDimitry Andric       GCOVBlock &Block = *fn->blocks[srcNo];
1875ffd83dbSDimitry Andric       for (;;) {
1885ffd83dbSDimitry Andric         uint32_t line = buf.getWord();
1895ffd83dbSDimitry Andric         if (line)
1905ffd83dbSDimitry Andric           Block.addLine(line);
1915ffd83dbSDimitry Andric         else {
192fe6060f1SDimitry Andric           StringRef filename;
193fe6060f1SDimitry Andric           buf.readString(filename);
1945ffd83dbSDimitry Andric           if (filename.empty())
1950b57cec5SDimitry Andric             break;
1965ffd83dbSDimitry Andric           // TODO Unhandled
1975ffd83dbSDimitry Andric         }
1985ffd83dbSDimitry Andric       }
1995ffd83dbSDimitry Andric     }
200fe6060f1SDimitry Andric     pos += version >= GCOV::V1200 ? length : 4 * length;
201fe6060f1SDimitry Andric     if (pos < buf.cursor.tell())
202fe6060f1SDimitry Andric       return false;
203fe6060f1SDimitry Andric     buf.de.skip(buf.cursor, pos - buf.cursor.tell());
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   GCNOInitialized = true;
2070b57cec5SDimitry Andric   return true;
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric /// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
2110b57cec5SDimitry Andric /// called after readGCNO().
2125ffd83dbSDimitry Andric bool GCOVFile::readGCDA(GCOVBuffer &buf) {
2130b57cec5SDimitry Andric   assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
2145ffd83dbSDimitry Andric   if (!buf.readGCDAFormat())
2150b57cec5SDimitry Andric     return false;
2160b57cec5SDimitry Andric   GCOV::GCOVVersion GCDAVersion;
2175ffd83dbSDimitry Andric   if (!buf.readGCOVVersion(GCDAVersion))
2180b57cec5SDimitry Andric     return false;
219fe6060f1SDimitry Andric   if (version != GCDAVersion) {
2200b57cec5SDimitry Andric     errs() << "GCOV versions do not match.\n";
2210b57cec5SDimitry Andric     return false;
2220b57cec5SDimitry Andric   }
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   uint32_t GCDAChecksum;
2255ffd83dbSDimitry Andric   if (!buf.readInt(GCDAChecksum))
2260b57cec5SDimitry Andric     return false;
227fe6060f1SDimitry Andric   if (checksum != GCDAChecksum) {
228fe6060f1SDimitry Andric     errs() << "file checksums do not match: " << checksum
229fe6060f1SDimitry Andric            << " != " << GCDAChecksum << "\n";
2300b57cec5SDimitry Andric     return false;
2310b57cec5SDimitry Andric   }
2325ffd83dbSDimitry Andric   uint32_t dummy, tag, length;
2335ffd83dbSDimitry Andric   uint32_t ident;
2345ffd83dbSDimitry Andric   GCOVFunction *fn = nullptr;
2355ffd83dbSDimitry Andric   while ((tag = buf.getWord())) {
2365ffd83dbSDimitry Andric     if (!buf.readInt(length))
2370b57cec5SDimitry Andric       return false;
2385ffd83dbSDimitry Andric     uint32_t pos = buf.cursor.tell();
2395ffd83dbSDimitry Andric     if (tag == GCOV_TAG_OBJECT_SUMMARY) {
240fe6060f1SDimitry Andric       buf.readInt(runCount);
2415ffd83dbSDimitry Andric       buf.readInt(dummy);
2425ffd83dbSDimitry Andric       // clang<11 uses a fake 4.2 format which sets length to 9.
2435ffd83dbSDimitry Andric       if (length == 9)
244fe6060f1SDimitry Andric         buf.readInt(runCount);
2455ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
2465ffd83dbSDimitry Andric       // clang<11 uses a fake 4.2 format which sets length to 0.
2475ffd83dbSDimitry Andric       if (length > 0) {
2485ffd83dbSDimitry Andric         buf.readInt(dummy);
2495ffd83dbSDimitry Andric         buf.readInt(dummy);
250fe6060f1SDimitry Andric         buf.readInt(runCount);
2510b57cec5SDimitry Andric       }
252fe6060f1SDimitry Andric       ++programCount;
2535ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_FUNCTION) {
2545ffd83dbSDimitry Andric       if (length == 0) // Placeholder
2555ffd83dbSDimitry Andric         continue;
2565ffd83dbSDimitry Andric       // As of GCC 10, GCOV_TAG_FUNCTION_LENGTH has never been larger than 3.
2575ffd83dbSDimitry Andric       // However, clang<11 uses a fake 4.2 format which may set length larger
2585ffd83dbSDimitry Andric       // than 3.
2595ffd83dbSDimitry Andric       if (length < 2 || !buf.readInt(ident))
2605ffd83dbSDimitry Andric         return false;
261fe6060f1SDimitry Andric       auto It = identToFunction.find(ident);
2625ffd83dbSDimitry Andric       uint32_t linenoChecksum, cfgChecksum = 0;
2635ffd83dbSDimitry Andric       buf.readInt(linenoChecksum);
264fe6060f1SDimitry Andric       if (version >= GCOV::V407)
2655ffd83dbSDimitry Andric         buf.readInt(cfgChecksum);
266fe6060f1SDimitry Andric       if (It != identToFunction.end()) {
2675ffd83dbSDimitry Andric         fn = It->second;
2685ffd83dbSDimitry Andric         if (linenoChecksum != fn->linenoChecksum ||
2695ffd83dbSDimitry Andric             cfgChecksum != fn->cfgChecksum) {
2705ffd83dbSDimitry Andric           errs() << fn->Name
2715ffd83dbSDimitry Andric                  << format(": checksum mismatch, (%u, %u) != (%u, %u)\n",
2725ffd83dbSDimitry Andric                            linenoChecksum, cfgChecksum, fn->linenoChecksum,
2735ffd83dbSDimitry Andric                            fn->cfgChecksum);
2745ffd83dbSDimitry Andric           return false;
2755ffd83dbSDimitry Andric         }
2765ffd83dbSDimitry Andric       }
2775ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_COUNTER_ARCS && fn) {
278fe6060f1SDimitry Andric       uint32_t expected = 2 * fn->arcs.size();
279fe6060f1SDimitry Andric       if (version >= GCOV::V1200)
280fe6060f1SDimitry Andric         expected *= 4;
281fe6060f1SDimitry Andric       if (length != expected) {
2825ffd83dbSDimitry Andric         errs() << fn->Name
2835ffd83dbSDimitry Andric                << format(
2845ffd83dbSDimitry Andric                       ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
285fe6060f1SDimitry Andric                       length, expected);
2865ffd83dbSDimitry Andric         return false;
2875ffd83dbSDimitry Andric       }
2885ffd83dbSDimitry Andric       for (std::unique_ptr<GCOVArc> &arc : fn->arcs) {
289e8d8bef9SDimitry Andric         if (!buf.readInt64(arc->count))
2905ffd83dbSDimitry Andric           return false;
291e8d8bef9SDimitry Andric         arc->src.count += arc->count;
292e8d8bef9SDimitry Andric       }
293e8d8bef9SDimitry Andric 
294e8d8bef9SDimitry Andric       if (fn->blocks.size() >= 2) {
295e8d8bef9SDimitry Andric         GCOVBlock &src = *fn->blocks[0];
296e8d8bef9SDimitry Andric         GCOVBlock &sink =
297fe6060f1SDimitry Andric             version < GCOV::V408 ? *fn->blocks.back() : *fn->blocks[1];
298e8d8bef9SDimitry Andric         auto arc = std::make_unique<GCOVArc>(sink, src, GCOV_ARC_ON_TREE);
299e8d8bef9SDimitry Andric         sink.addDstEdge(arc.get());
300e8d8bef9SDimitry Andric         src.addSrcEdge(arc.get());
301e8d8bef9SDimitry Andric         fn->treeArcs.push_back(std::move(arc));
302e8d8bef9SDimitry Andric 
303e8d8bef9SDimitry Andric         for (GCOVBlock &block : fn->blocksRange())
304e8d8bef9SDimitry Andric           fn->propagateCounts(block, nullptr);
305e8d8bef9SDimitry Andric         for (size_t i = fn->treeArcs.size() - 1; i; --i)
306e8d8bef9SDimitry Andric           fn->treeArcs[i - 1]->src.count += fn->treeArcs[i - 1]->count;
3075ffd83dbSDimitry Andric       }
3085ffd83dbSDimitry Andric     }
309fe6060f1SDimitry Andric     pos += version >= GCOV::V1200 ? length : 4 * length;
3105ffd83dbSDimitry Andric     if (pos < buf.cursor.tell())
3115ffd83dbSDimitry Andric       return false;
3125ffd83dbSDimitry Andric     buf.de.skip(buf.cursor, pos - buf.cursor.tell());
3130b57cec5SDimitry Andric   }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   return true;
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric void GCOVFile::print(raw_ostream &OS) const {
3195ffd83dbSDimitry Andric   for (const GCOVFunction &f : *this)
3205ffd83dbSDimitry Andric     f.print(OS);
3210b57cec5SDimitry Andric }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3240b57cec5SDimitry Andric /// dump - Dump GCOVFile content to dbgs() for debugging purposes.
3250b57cec5SDimitry Andric LLVM_DUMP_METHOD void GCOVFile::dump() const { print(dbgs()); }
3260b57cec5SDimitry Andric #endif
3270b57cec5SDimitry Andric 
328e8d8bef9SDimitry Andric bool GCOVArc::onTree() const { return flags & GCOV_ARC_ON_TREE; }
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3310b57cec5SDimitry Andric // GCOVFunction implementation.
3320b57cec5SDimitry Andric 
333e8d8bef9SDimitry Andric StringRef GCOVFunction::getName(bool demangle) const {
334e8d8bef9SDimitry Andric   if (!demangle)
335e8d8bef9SDimitry Andric     return Name;
336e8d8bef9SDimitry Andric   if (demangled.empty()) {
337e8d8bef9SDimitry Andric     do {
338e8d8bef9SDimitry Andric       if (Name.startswith("_Z")) {
339e8d8bef9SDimitry Andric         int status = 0;
340e8d8bef9SDimitry Andric         // Name is guaranteed to be NUL-terminated.
341e8d8bef9SDimitry Andric         char *res = itaniumDemangle(Name.data(), nullptr, nullptr, &status);
342e8d8bef9SDimitry Andric         if (status == 0) {
343e8d8bef9SDimitry Andric           demangled = res;
344e8d8bef9SDimitry Andric           free(res);
345e8d8bef9SDimitry Andric           break;
346e8d8bef9SDimitry Andric         }
347e8d8bef9SDimitry Andric       }
348e8d8bef9SDimitry Andric       demangled = Name;
349e8d8bef9SDimitry Andric     } while (0);
350e8d8bef9SDimitry Andric   }
351e8d8bef9SDimitry Andric   return demangled;
352e8d8bef9SDimitry Andric }
3535ffd83dbSDimitry Andric StringRef GCOVFunction::getFilename() const { return file.filenames[srcIdx]; }
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric /// getEntryCount - Get the number of times the function was called by
3560b57cec5SDimitry Andric /// retrieving the entry block's count.
3570b57cec5SDimitry Andric uint64_t GCOVFunction::getEntryCount() const {
358e8d8bef9SDimitry Andric   return blocks.front()->getCount();
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric 
361e8d8bef9SDimitry Andric GCOVBlock &GCOVFunction::getExitBlock() const {
362e8d8bef9SDimitry Andric   return file.getVersion() < GCOV::V408 ? *blocks.back() : *blocks[1];
363e8d8bef9SDimitry Andric }
364e8d8bef9SDimitry Andric 
365e8d8bef9SDimitry Andric // For each basic block, the sum of incoming edge counts equals the sum of
366e8d8bef9SDimitry Andric // outgoing edge counts by Kirchoff's circuit law. If the unmeasured arcs form a
367e8d8bef9SDimitry Andric // spanning tree, the count for each unmeasured arc (GCOV_ARC_ON_TREE) can be
368e8d8bef9SDimitry Andric // uniquely identified.
369e8d8bef9SDimitry Andric uint64_t GCOVFunction::propagateCounts(const GCOVBlock &v, GCOVArc *pred) {
370e8d8bef9SDimitry Andric   // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed; otherwise
371e8d8bef9SDimitry Andric   // this prevents infinite recursion.
372e8d8bef9SDimitry Andric   if (!visited.insert(&v).second)
373e8d8bef9SDimitry Andric     return 0;
374e8d8bef9SDimitry Andric 
375e8d8bef9SDimitry Andric   uint64_t excess = 0;
376e8d8bef9SDimitry Andric   for (GCOVArc *e : v.srcs())
377e8d8bef9SDimitry Andric     if (e != pred)
378e8d8bef9SDimitry Andric       excess += e->onTree() ? propagateCounts(e->src, e) : e->count;
379e8d8bef9SDimitry Andric   for (GCOVArc *e : v.dsts())
380e8d8bef9SDimitry Andric     if (e != pred)
381e8d8bef9SDimitry Andric       excess -= e->onTree() ? propagateCounts(e->dst, e) : e->count;
382e8d8bef9SDimitry Andric   if (int64_t(excess) < 0)
383e8d8bef9SDimitry Andric     excess = -excess;
384e8d8bef9SDimitry Andric   if (pred)
385e8d8bef9SDimitry Andric     pred->count = excess;
386e8d8bef9SDimitry Andric   return excess;
3870b57cec5SDimitry Andric }
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric void GCOVFunction::print(raw_ostream &OS) const {
3905ffd83dbSDimitry Andric   OS << "===== " << Name << " (" << ident << ") @ " << getFilename() << ":"
3915ffd83dbSDimitry Andric      << startLine << "\n";
392e8d8bef9SDimitry Andric   for (const auto &Block : blocks)
3930b57cec5SDimitry Andric     Block->print(OS);
3940b57cec5SDimitry Andric }
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3970b57cec5SDimitry Andric /// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
3980b57cec5SDimitry Andric LLVM_DUMP_METHOD void GCOVFunction::dump() const { print(dbgs()); }
3990b57cec5SDimitry Andric #endif
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric /// collectLineCounts - Collect line counts. This must be used after
4020b57cec5SDimitry Andric /// reading .gcno and .gcda files.
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4050b57cec5SDimitry Andric // GCOVBlock implementation.
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric void GCOVBlock::print(raw_ostream &OS) const {
408e8d8bef9SDimitry Andric   OS << "Block : " << number << " Counter : " << count << "\n";
4095ffd83dbSDimitry Andric   if (!pred.empty()) {
4100b57cec5SDimitry Andric     OS << "\tSource Edges : ";
4115ffd83dbSDimitry Andric     for (const GCOVArc *Edge : pred)
412e8d8bef9SDimitry Andric       OS << Edge->src.number << " (" << Edge->count << "), ";
4130b57cec5SDimitry Andric     OS << "\n";
4140b57cec5SDimitry Andric   }
4155ffd83dbSDimitry Andric   if (!succ.empty()) {
4160b57cec5SDimitry Andric     OS << "\tDestination Edges : ";
417e8d8bef9SDimitry Andric     for (const GCOVArc *Edge : succ) {
418e8d8bef9SDimitry Andric       if (Edge->flags & GCOV_ARC_ON_TREE)
419e8d8bef9SDimitry Andric         OS << '*';
420e8d8bef9SDimitry Andric       OS << Edge->dst.number << " (" << Edge->count << "), ";
421e8d8bef9SDimitry Andric     }
4220b57cec5SDimitry Andric     OS << "\n";
4230b57cec5SDimitry Andric   }
424e8d8bef9SDimitry Andric   if (!lines.empty()) {
4250b57cec5SDimitry Andric     OS << "\tLines : ";
426e8d8bef9SDimitry Andric     for (uint32_t N : lines)
4270b57cec5SDimitry Andric       OS << (N) << ",";
4280b57cec5SDimitry Andric     OS << "\n";
4290b57cec5SDimitry Andric   }
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4330b57cec5SDimitry Andric /// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
4340b57cec5SDimitry Andric LLVM_DUMP_METHOD void GCOVBlock::dump() const { print(dbgs()); }
4350b57cec5SDimitry Andric #endif
4360b57cec5SDimitry Andric 
437e8d8bef9SDimitry Andric uint64_t
438e8d8bef9SDimitry Andric GCOVBlock::augmentOneCycle(GCOVBlock *src,
439e8d8bef9SDimitry Andric                            std::vector<std::pair<GCOVBlock *, size_t>> &stack) {
440e8d8bef9SDimitry Andric   GCOVBlock *u;
441e8d8bef9SDimitry Andric   size_t i;
442e8d8bef9SDimitry Andric   stack.clear();
443e8d8bef9SDimitry Andric   stack.emplace_back(src, 0);
444e8d8bef9SDimitry Andric   src->incoming = (GCOVArc *)1; // Mark u available for cycle detection
445e8d8bef9SDimitry Andric   for (;;) {
446e8d8bef9SDimitry Andric     std::tie(u, i) = stack.back();
447e8d8bef9SDimitry Andric     if (i == u->succ.size()) {
448e8d8bef9SDimitry Andric       u->traversable = false;
449e8d8bef9SDimitry Andric       stack.pop_back();
450e8d8bef9SDimitry Andric       if (stack.empty())
451e8d8bef9SDimitry Andric         break;
4520b57cec5SDimitry Andric       continue;
4530b57cec5SDimitry Andric     }
454e8d8bef9SDimitry Andric     ++stack.back().second;
455e8d8bef9SDimitry Andric     GCOVArc *succ = u->succ[i];
456e8d8bef9SDimitry Andric     // Ignore saturated arcs (cycleCount has been reduced to 0) and visited
457e8d8bef9SDimitry Andric     // blocks. Ignore self arcs to guard against bad input (.gcno has no
458e8d8bef9SDimitry Andric     // self arcs).
459e8d8bef9SDimitry Andric     if (succ->cycleCount == 0 || !succ->dst.traversable || &succ->dst == u)
460e8d8bef9SDimitry Andric       continue;
461e8d8bef9SDimitry Andric     if (succ->dst.incoming == nullptr) {
462e8d8bef9SDimitry Andric       succ->dst.incoming = succ;
463e8d8bef9SDimitry Andric       stack.emplace_back(&succ->dst, 0);
4640b57cec5SDimitry Andric       continue;
4650b57cec5SDimitry Andric     }
466e8d8bef9SDimitry Andric     uint64_t minCount = succ->cycleCount;
467e8d8bef9SDimitry Andric     for (GCOVBlock *v = u;;) {
468e8d8bef9SDimitry Andric       minCount = std::min(minCount, v->incoming->cycleCount);
469e8d8bef9SDimitry Andric       v = &v->incoming->src;
470e8d8bef9SDimitry Andric       if (v == &succ->dst)
471e8d8bef9SDimitry Andric         break;
4720b57cec5SDimitry Andric     }
473e8d8bef9SDimitry Andric     succ->cycleCount -= minCount;
474e8d8bef9SDimitry Andric     for (GCOVBlock *v = u;;) {
475e8d8bef9SDimitry Andric       v->incoming->cycleCount -= minCount;
476e8d8bef9SDimitry Andric       v = &v->incoming->src;
477e8d8bef9SDimitry Andric       if (v == &succ->dst)
478e8d8bef9SDimitry Andric         break;
4790b57cec5SDimitry Andric     }
480e8d8bef9SDimitry Andric     return minCount;
481e8d8bef9SDimitry Andric   }
482e8d8bef9SDimitry Andric   return 0;
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric 
485e8d8bef9SDimitry Andric // Get the total execution count of loops among blocks on the same line.
486e8d8bef9SDimitry Andric // Assuming a reducible flow graph, the count is the sum of back edge counts.
487e8d8bef9SDimitry Andric // Identifying loops is complex, so we simply find cycles and perform cycle
488e8d8bef9SDimitry Andric // cancelling iteratively.
489e8d8bef9SDimitry Andric uint64_t GCOVBlock::getCyclesCount(const BlockVector &blocks) {
490e8d8bef9SDimitry Andric   std::vector<std::pair<GCOVBlock *, size_t>> stack;
491e8d8bef9SDimitry Andric   uint64_t count = 0, d;
492e8d8bef9SDimitry Andric   for (;;) {
493e8d8bef9SDimitry Andric     // Make blocks on the line traversable and try finding a cycle.
494e8d8bef9SDimitry Andric     for (auto b : blocks) {
495e8d8bef9SDimitry Andric       const_cast<GCOVBlock *>(b)->traversable = true;
496e8d8bef9SDimitry Andric       const_cast<GCOVBlock *>(b)->incoming = nullptr;
4970b57cec5SDimitry Andric     }
498e8d8bef9SDimitry Andric     d = 0;
499e8d8bef9SDimitry Andric     for (auto block : blocks) {
500e8d8bef9SDimitry Andric       auto *b = const_cast<GCOVBlock *>(block);
501e8d8bef9SDimitry Andric       if (b->traversable && (d = augmentOneCycle(b, stack)) > 0)
502e8d8bef9SDimitry Andric         break;
5030b57cec5SDimitry Andric     }
504e8d8bef9SDimitry Andric     if (d == 0)
505e8d8bef9SDimitry Andric       break;
506e8d8bef9SDimitry Andric     count += d;
5070b57cec5SDimitry Andric   }
508e8d8bef9SDimitry Andric   // If there is no more loop, all traversable bits should have been cleared.
509e8d8bef9SDimitry Andric   // This property is needed by subsequent calls.
510e8d8bef9SDimitry Andric   for (auto b : blocks) {
511e8d8bef9SDimitry Andric     assert(!b->traversable);
512e8d8bef9SDimitry Andric     (void)b;
5130b57cec5SDimitry Andric   }
514e8d8bef9SDimitry Andric   return count;
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5180b57cec5SDimitry Andric // FileInfo implementation.
5190b57cec5SDimitry Andric 
520e8d8bef9SDimitry Andric // Format dividend/divisor as a percentage. Return 1 if the result is greater
521e8d8bef9SDimitry Andric // than 0% and less than 1%.
522e8d8bef9SDimitry Andric static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor) {
523e8d8bef9SDimitry Andric   if (!dividend || !divisor)
5240b57cec5SDimitry Andric     return 0;
525e8d8bef9SDimitry Andric   dividend *= 100;
526e8d8bef9SDimitry Andric   return dividend < divisor ? 1 : dividend / divisor;
5270b57cec5SDimitry Andric }
5280b57cec5SDimitry Andric 
5290b57cec5SDimitry Andric // This custom division function mimics gcov's branch ouputs:
5300b57cec5SDimitry Andric //   - Round to closest whole number
5310b57cec5SDimitry Andric //   - Only output 0% or 100% if it's exactly that value
5320b57cec5SDimitry Andric static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
5330b57cec5SDimitry Andric   if (!Numerator)
5340b57cec5SDimitry Andric     return 0;
5350b57cec5SDimitry Andric   if (Numerator == Divisor)
5360b57cec5SDimitry Andric     return 100;
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric   uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
5390b57cec5SDimitry Andric   if (Res == 0)
5400b57cec5SDimitry Andric     return 1;
5410b57cec5SDimitry Andric   if (Res == 100)
5420b57cec5SDimitry Andric     return 99;
5430b57cec5SDimitry Andric   return Res;
5440b57cec5SDimitry Andric }
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric namespace {
5470b57cec5SDimitry Andric struct formatBranchInfo {
5480b57cec5SDimitry Andric   formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
5490b57cec5SDimitry Andric       : Options(Options), Count(Count), Total(Total) {}
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric   void print(raw_ostream &OS) const {
5520b57cec5SDimitry Andric     if (!Total)
5530b57cec5SDimitry Andric       OS << "never executed";
5540b57cec5SDimitry Andric     else if (Options.BranchCount)
5550b57cec5SDimitry Andric       OS << "taken " << Count;
5560b57cec5SDimitry Andric     else
5570b57cec5SDimitry Andric       OS << "taken " << branchDiv(Count, Total) << "%";
5580b57cec5SDimitry Andric   }
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   const GCOV::Options &Options;
5610b57cec5SDimitry Andric   uint64_t Count;
5620b57cec5SDimitry Andric   uint64_t Total;
5630b57cec5SDimitry Andric };
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
5660b57cec5SDimitry Andric   FBI.print(OS);
5670b57cec5SDimitry Andric   return OS;
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric class LineConsumer {
5710b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> Buffer;
5720b57cec5SDimitry Andric   StringRef Remaining;
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric public:
5755ffd83dbSDimitry Andric   LineConsumer() = default;
5760b57cec5SDimitry Andric   LineConsumer(StringRef Filename) {
577e8d8bef9SDimitry Andric     // Open source files without requiring a NUL terminator. The concurrent
578e8d8bef9SDimitry Andric     // modification may nullify the NUL terminator condition.
5790b57cec5SDimitry Andric     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
580fe6060f1SDimitry Andric         MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/false,
581e8d8bef9SDimitry Andric                                      /*RequiresNullTerminator=*/false);
5820b57cec5SDimitry Andric     if (std::error_code EC = BufferOrErr.getError()) {
5830b57cec5SDimitry Andric       errs() << Filename << ": " << EC.message() << "\n";
5840b57cec5SDimitry Andric       Remaining = "";
5850b57cec5SDimitry Andric     } else {
5860b57cec5SDimitry Andric       Buffer = std::move(BufferOrErr.get());
5870b57cec5SDimitry Andric       Remaining = Buffer->getBuffer();
5880b57cec5SDimitry Andric     }
5890b57cec5SDimitry Andric   }
5900b57cec5SDimitry Andric   bool empty() { return Remaining.empty(); }
5910b57cec5SDimitry Andric   void printNext(raw_ostream &OS, uint32_t LineNum) {
5920b57cec5SDimitry Andric     StringRef Line;
5930b57cec5SDimitry Andric     if (empty())
5940b57cec5SDimitry Andric       Line = "/*EOF*/";
5950b57cec5SDimitry Andric     else
5960b57cec5SDimitry Andric       std::tie(Line, Remaining) = Remaining.split("\n");
5970b57cec5SDimitry Andric     OS << format("%5u:", LineNum) << Line << "\n";
5980b57cec5SDimitry Andric   }
5990b57cec5SDimitry Andric };
6000b57cec5SDimitry Andric } // end anonymous namespace
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric /// Convert a path to a gcov filename. If PreservePaths is true, this
6030b57cec5SDimitry Andric /// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
6040b57cec5SDimitry Andric static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
6050b57cec5SDimitry Andric   if (!PreservePaths)
6060b57cec5SDimitry Andric     return sys::path::filename(Filename).str();
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric   // This behaviour is defined by gcov in terms of text replacements, so it's
6090b57cec5SDimitry Andric   // not likely to do anything useful on filesystems with different textual
6100b57cec5SDimitry Andric   // conventions.
6110b57cec5SDimitry Andric   llvm::SmallString<256> Result("");
6120b57cec5SDimitry Andric   StringRef::iterator I, S, E;
6130b57cec5SDimitry Andric   for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
6140b57cec5SDimitry Andric     if (*I != '/')
6150b57cec5SDimitry Andric       continue;
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric     if (I - S == 1 && *S == '.') {
6180b57cec5SDimitry Andric       // ".", the current directory, is skipped.
6190b57cec5SDimitry Andric     } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
6200b57cec5SDimitry Andric       // "..", the parent directory, is replaced with "^".
6210b57cec5SDimitry Andric       Result.append("^#");
6220b57cec5SDimitry Andric     } else {
6230b57cec5SDimitry Andric       if (S < I)
6240b57cec5SDimitry Andric         // Leave other components intact,
6250b57cec5SDimitry Andric         Result.append(S, I);
6260b57cec5SDimitry Andric       // And separate with "#".
6270b57cec5SDimitry Andric       Result.push_back('#');
6280b57cec5SDimitry Andric     }
6290b57cec5SDimitry Andric     S = I + 1;
6300b57cec5SDimitry Andric   }
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric   if (S < I)
6330b57cec5SDimitry Andric     Result.append(S, I);
6345ffd83dbSDimitry Andric   return std::string(Result.str());
6350b57cec5SDimitry Andric }
6360b57cec5SDimitry Andric 
637e8d8bef9SDimitry Andric std::string Context::getCoveragePath(StringRef filename,
638e8d8bef9SDimitry Andric                                      StringRef mainFilename) const {
639e8d8bef9SDimitry Andric   if (options.NoOutput)
6400b57cec5SDimitry Andric     // This is probably a bug in gcov, but when -n is specified, paths aren't
6410b57cec5SDimitry Andric     // mangled at all, and the -l and -p options are ignored. Here, we do the
6420b57cec5SDimitry Andric     // same.
643e8d8bef9SDimitry Andric     return std::string(filename);
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric   std::string CoveragePath;
646e8d8bef9SDimitry Andric   if (options.LongFileNames && !filename.equals(mainFilename))
6470b57cec5SDimitry Andric     CoveragePath =
648e8d8bef9SDimitry Andric         mangleCoveragePath(mainFilename, options.PreservePaths) + "##";
649e8d8bef9SDimitry Andric   CoveragePath += mangleCoveragePath(filename, options.PreservePaths);
650e8d8bef9SDimitry Andric   if (options.HashFilenames) {
6510b57cec5SDimitry Andric     MD5 Hasher;
6520b57cec5SDimitry Andric     MD5::MD5Result Result;
653e8d8bef9SDimitry Andric     Hasher.update(filename.str());
6540b57cec5SDimitry Andric     Hasher.final(Result);
6555ffd83dbSDimitry Andric     CoveragePath += "##" + std::string(Result.digest());
6560b57cec5SDimitry Andric   }
6570b57cec5SDimitry Andric   CoveragePath += ".gcov";
6580b57cec5SDimitry Andric   return CoveragePath;
6590b57cec5SDimitry Andric }
6600b57cec5SDimitry Andric 
661e8d8bef9SDimitry Andric void Context::collectFunction(GCOVFunction &f, Summary &summary) {
662e8d8bef9SDimitry Andric   SourceInfo &si = sources[f.srcIdx];
663e8d8bef9SDimitry Andric   if (f.startLine >= si.startLineToFunctions.size())
664e8d8bef9SDimitry Andric     si.startLineToFunctions.resize(f.startLine + 1);
665e8d8bef9SDimitry Andric   si.startLineToFunctions[f.startLine].push_back(&f);
666e8d8bef9SDimitry Andric   for (const GCOVBlock &b : f.blocksRange()) {
667e8d8bef9SDimitry Andric     if (b.lines.empty())
6680b57cec5SDimitry Andric       continue;
669e8d8bef9SDimitry Andric     uint32_t maxLineNum = *std::max_element(b.lines.begin(), b.lines.end());
670e8d8bef9SDimitry Andric     if (maxLineNum >= si.lines.size())
671e8d8bef9SDimitry Andric       si.lines.resize(maxLineNum + 1);
672e8d8bef9SDimitry Andric     for (uint32_t lineNum : b.lines) {
673e8d8bef9SDimitry Andric       LineInfo &line = si.lines[lineNum];
674e8d8bef9SDimitry Andric       if (!line.exists)
675e8d8bef9SDimitry Andric         ++summary.lines;
676e8d8bef9SDimitry Andric       if (line.count == 0 && b.count)
677e8d8bef9SDimitry Andric         ++summary.linesExec;
678e8d8bef9SDimitry Andric       line.exists = true;
679e8d8bef9SDimitry Andric       line.count += b.count;
680e8d8bef9SDimitry Andric       line.blocks.push_back(&b);
681e8d8bef9SDimitry Andric     }
682e8d8bef9SDimitry Andric   }
683e8d8bef9SDimitry Andric }
684e8d8bef9SDimitry Andric 
685e8d8bef9SDimitry Andric void Context::collectSourceLine(SourceInfo &si, Summary *summary,
686e8d8bef9SDimitry Andric                                 LineInfo &line, size_t lineNum) const {
687e8d8bef9SDimitry Andric   uint64_t count = 0;
688e8d8bef9SDimitry Andric   for (const GCOVBlock *b : line.blocks) {
689e8d8bef9SDimitry Andric     if (b->number == 0) {
690e8d8bef9SDimitry Andric       // For nonstandard control flows, arcs into the exit block may be
691e8d8bef9SDimitry Andric       // duplicately counted (fork) or not be counted (abnormal exit), and thus
692e8d8bef9SDimitry Andric       // the (exit,entry) counter may be inaccurate. Count the entry block with
693e8d8bef9SDimitry Andric       // the outgoing arcs.
694e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->succ)
695e8d8bef9SDimitry Andric         count += arc->count;
696e8d8bef9SDimitry Andric     } else {
697e8d8bef9SDimitry Andric       // Add counts from predecessors that are not on the same line.
698e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->pred)
699e8d8bef9SDimitry Andric         if (!llvm::is_contained(line.blocks, &arc->src))
700e8d8bef9SDimitry Andric           count += arc->count;
701e8d8bef9SDimitry Andric     }
702e8d8bef9SDimitry Andric     for (GCOVArc *arc : b->succ)
703e8d8bef9SDimitry Andric       arc->cycleCount = arc->count;
704e8d8bef9SDimitry Andric   }
705e8d8bef9SDimitry Andric 
706e8d8bef9SDimitry Andric   count += GCOVBlock::getCyclesCount(line.blocks);
707e8d8bef9SDimitry Andric   line.count = count;
708e8d8bef9SDimitry Andric   if (line.exists) {
709e8d8bef9SDimitry Andric     ++summary->lines;
710e8d8bef9SDimitry Andric     if (line.count != 0)
711e8d8bef9SDimitry Andric       ++summary->linesExec;
712e8d8bef9SDimitry Andric   }
713e8d8bef9SDimitry Andric 
714e8d8bef9SDimitry Andric   if (options.BranchInfo)
715e8d8bef9SDimitry Andric     for (const GCOVBlock *b : line.blocks) {
716e8d8bef9SDimitry Andric       if (b->getLastLine() != lineNum)
717e8d8bef9SDimitry Andric         continue;
718e8d8bef9SDimitry Andric       int branches = 0, execBranches = 0, takenBranches = 0;
719e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->succ) {
720e8d8bef9SDimitry Andric         ++branches;
721e8d8bef9SDimitry Andric         if (count != 0)
722e8d8bef9SDimitry Andric           ++execBranches;
723e8d8bef9SDimitry Andric         if (arc->count != 0)
724e8d8bef9SDimitry Andric           ++takenBranches;
725e8d8bef9SDimitry Andric       }
726e8d8bef9SDimitry Andric       if (branches > 1) {
727e8d8bef9SDimitry Andric         summary->branches += branches;
728e8d8bef9SDimitry Andric         summary->branchesExec += execBranches;
729e8d8bef9SDimitry Andric         summary->branchesTaken += takenBranches;
730e8d8bef9SDimitry Andric       }
731e8d8bef9SDimitry Andric     }
732e8d8bef9SDimitry Andric }
733e8d8bef9SDimitry Andric 
734e8d8bef9SDimitry Andric void Context::collectSource(SourceInfo &si, Summary &summary) const {
735e8d8bef9SDimitry Andric   size_t lineNum = 0;
736e8d8bef9SDimitry Andric   for (LineInfo &line : si.lines) {
737e8d8bef9SDimitry Andric     collectSourceLine(si, &summary, line, lineNum);
738e8d8bef9SDimitry Andric     ++lineNum;
739e8d8bef9SDimitry Andric   }
740e8d8bef9SDimitry Andric }
741e8d8bef9SDimitry Andric 
742e8d8bef9SDimitry Andric void Context::annotateSource(SourceInfo &si, const GCOVFile &file,
743e8d8bef9SDimitry Andric                              StringRef gcno, StringRef gcda,
744e8d8bef9SDimitry Andric                              raw_ostream &os) const {
745e8d8bef9SDimitry Andric   auto source =
746e8d8bef9SDimitry Andric       options.Intermediate ? LineConsumer() : LineConsumer(si.filename);
747e8d8bef9SDimitry Andric 
748e8d8bef9SDimitry Andric   os << "        -:    0:Source:" << si.displayName << '\n';
749e8d8bef9SDimitry Andric   os << "        -:    0:Graph:" << gcno << '\n';
750e8d8bef9SDimitry Andric   os << "        -:    0:Data:" << gcda << '\n';
751fe6060f1SDimitry Andric   os << "        -:    0:Runs:" << file.runCount << '\n';
752fe6060f1SDimitry Andric   if (file.version < GCOV::V900)
753fe6060f1SDimitry Andric     os << "        -:    0:Programs:" << file.programCount << '\n';
754e8d8bef9SDimitry Andric 
755e8d8bef9SDimitry Andric   for (size_t lineNum = 1; !source.empty(); ++lineNum) {
756e8d8bef9SDimitry Andric     if (lineNum >= si.lines.size()) {
757e8d8bef9SDimitry Andric       os << "        -:";
758e8d8bef9SDimitry Andric       source.printNext(os, lineNum);
759e8d8bef9SDimitry Andric       continue;
760e8d8bef9SDimitry Andric     }
761e8d8bef9SDimitry Andric 
762e8d8bef9SDimitry Andric     const LineInfo &line = si.lines[lineNum];
763e8d8bef9SDimitry Andric     if (options.BranchInfo && lineNum < si.startLineToFunctions.size())
764e8d8bef9SDimitry Andric       for (const auto *f : si.startLineToFunctions[lineNum])
765e8d8bef9SDimitry Andric         printFunctionDetails(*f, os);
766e8d8bef9SDimitry Andric     if (!line.exists)
767e8d8bef9SDimitry Andric       os << "        -:";
768e8d8bef9SDimitry Andric     else if (line.count == 0)
769e8d8bef9SDimitry Andric       os << "    #####:";
770e8d8bef9SDimitry Andric     else
771e8d8bef9SDimitry Andric       os << format("%9" PRIu64 ":", line.count);
772e8d8bef9SDimitry Andric     source.printNext(os, lineNum);
773e8d8bef9SDimitry Andric 
774e8d8bef9SDimitry Andric     uint32_t blockIdx = 0, edgeIdx = 0;
775e8d8bef9SDimitry Andric     for (const GCOVBlock *b : line.blocks) {
776e8d8bef9SDimitry Andric       if (b->getLastLine() != lineNum)
777e8d8bef9SDimitry Andric         continue;
778e8d8bef9SDimitry Andric       if (options.AllBlocks) {
779e8d8bef9SDimitry Andric         if (b->getCount() == 0)
780e8d8bef9SDimitry Andric           os << "    $$$$$:";
781e8d8bef9SDimitry Andric         else
782e8d8bef9SDimitry Andric           os << format("%9" PRIu64 ":", b->count);
783e8d8bef9SDimitry Andric         os << format("%5u-block %2u\n", lineNum, blockIdx++);
784e8d8bef9SDimitry Andric       }
785e8d8bef9SDimitry Andric       if (options.BranchInfo) {
786e8d8bef9SDimitry Andric         size_t NumEdges = b->succ.size();
7870b57cec5SDimitry Andric         if (NumEdges > 1)
788e8d8bef9SDimitry Andric           printBranchInfo(*b, edgeIdx, os);
789e8d8bef9SDimitry Andric         else if (options.UncondBranch && NumEdges == 1) {
790e8d8bef9SDimitry Andric           uint64_t count = b->succ[0]->count;
791e8d8bef9SDimitry Andric           os << format("unconditional %2u ", edgeIdx++)
792e8d8bef9SDimitry Andric              << formatBranchInfo(options, count, count) << '\n';
7930b57cec5SDimitry Andric         }
7940b57cec5SDimitry Andric       }
7950b57cec5SDimitry Andric     }
7960b57cec5SDimitry Andric   }
7970b57cec5SDimitry Andric }
7980b57cec5SDimitry Andric 
799e8d8bef9SDimitry Andric void Context::printSourceToIntermediate(const SourceInfo &si,
800e8d8bef9SDimitry Andric                                         raw_ostream &os) const {
801e8d8bef9SDimitry Andric   os << "file:" << si.filename << '\n';
802e8d8bef9SDimitry Andric   for (const auto &fs : si.startLineToFunctions)
803e8d8bef9SDimitry Andric     for (const GCOVFunction *f : fs)
8045ffd83dbSDimitry Andric       os << "function:" << f->startLine << ',' << f->getEntryCount() << ','
805e8d8bef9SDimitry Andric          << f->getName(options.Demangle) << '\n';
806e8d8bef9SDimitry Andric   for (size_t lineNum = 1, size = si.lines.size(); lineNum < size; ++lineNum) {
807e8d8bef9SDimitry Andric     const LineInfo &line = si.lines[lineNum];
808e8d8bef9SDimitry Andric     if (line.blocks.empty())
8095ffd83dbSDimitry Andric       continue;
8105ffd83dbSDimitry Andric     // GCC 8 (r254259) added third third field for Ada:
8115ffd83dbSDimitry Andric     // lcount:<line>,<count>,<has_unexecuted_blocks>
8125ffd83dbSDimitry Andric     // We don't need the third field.
813e8d8bef9SDimitry Andric     os << "lcount:" << lineNum << ',' << line.count << '\n';
8145ffd83dbSDimitry Andric 
815e8d8bef9SDimitry Andric     if (!options.BranchInfo)
8165ffd83dbSDimitry Andric       continue;
817e8d8bef9SDimitry Andric     for (const GCOVBlock *b : line.blocks) {
818e8d8bef9SDimitry Andric       if (b->succ.size() < 2 || b->getLastLine() != lineNum)
8195ffd83dbSDimitry Andric         continue;
820e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->succ) {
821e8d8bef9SDimitry Andric         const char *type =
822e8d8bef9SDimitry Andric             b->getCount() ? arc->count ? "taken" : "nottaken" : "notexec";
823e8d8bef9SDimitry Andric         os << "branch:" << lineNum << ',' << type << '\n';
8245ffd83dbSDimitry Andric       }
8255ffd83dbSDimitry Andric     }
8265ffd83dbSDimitry Andric   }
8275ffd83dbSDimitry Andric }
8285ffd83dbSDimitry Andric 
829e8d8bef9SDimitry Andric void Context::print(StringRef filename, StringRef gcno, StringRef gcda,
830e8d8bef9SDimitry Andric                     GCOVFile &file) {
831e8d8bef9SDimitry Andric   for (StringRef filename : file.filenames) {
832e8d8bef9SDimitry Andric     sources.emplace_back(filename);
833e8d8bef9SDimitry Andric     SourceInfo &si = sources.back();
834e8d8bef9SDimitry Andric     si.displayName = si.filename;
835e8d8bef9SDimitry Andric     if (!options.SourcePrefix.empty() &&
836e8d8bef9SDimitry Andric         sys::path::replace_path_prefix(si.displayName, options.SourcePrefix,
837e8d8bef9SDimitry Andric                                        "") &&
838e8d8bef9SDimitry Andric         !si.displayName.empty()) {
839e8d8bef9SDimitry Andric       // TODO replace_path_prefix may strip the prefix even if the remaining
840e8d8bef9SDimitry Andric       // part does not start with a separator.
841e8d8bef9SDimitry Andric       if (sys::path::is_separator(si.displayName[0]))
842e8d8bef9SDimitry Andric         si.displayName.erase(si.displayName.begin());
8430b57cec5SDimitry Andric       else
844e8d8bef9SDimitry Andric         si.displayName = si.filename;
845e8d8bef9SDimitry Andric     }
846e8d8bef9SDimitry Andric     if (options.RelativeOnly && sys::path::is_absolute(si.displayName))
847e8d8bef9SDimitry Andric       si.ignored = true;
848e8d8bef9SDimitry Andric   }
849e8d8bef9SDimitry Andric 
850e8d8bef9SDimitry Andric   raw_ostream &os = llvm::outs();
851e8d8bef9SDimitry Andric   for (GCOVFunction &f : make_pointee_range(file.functions)) {
852e8d8bef9SDimitry Andric     Summary summary(f.getName(options.Demangle));
853e8d8bef9SDimitry Andric     collectFunction(f, summary);
854e8d8bef9SDimitry Andric     if (options.FuncCoverage && !options.UseStdout) {
855e8d8bef9SDimitry Andric       os << "Function '" << summary.Name << "'\n";
856e8d8bef9SDimitry Andric       printSummary(summary, os);
857e8d8bef9SDimitry Andric       os << '\n';
858e8d8bef9SDimitry Andric     }
859e8d8bef9SDimitry Andric   }
860e8d8bef9SDimitry Andric 
861e8d8bef9SDimitry Andric   for (SourceInfo &si : sources) {
862e8d8bef9SDimitry Andric     if (si.ignored)
863e8d8bef9SDimitry Andric       continue;
864e8d8bef9SDimitry Andric     Summary summary(si.displayName);
865e8d8bef9SDimitry Andric     collectSource(si, summary);
866e8d8bef9SDimitry Andric 
867e8d8bef9SDimitry Andric     // Print file summary unless -t is specified.
868e8d8bef9SDimitry Andric     std::string gcovName = getCoveragePath(si.filename, filename);
869e8d8bef9SDimitry Andric     if (!options.UseStdout) {
870e8d8bef9SDimitry Andric       os << "File '" << summary.Name << "'\n";
871e8d8bef9SDimitry Andric       printSummary(summary, os);
872e8d8bef9SDimitry Andric       if (!options.NoOutput && !options.Intermediate)
873e8d8bef9SDimitry Andric         os << "Creating '" << gcovName << "'\n";
874e8d8bef9SDimitry Andric       os << '\n';
875e8d8bef9SDimitry Andric     }
876e8d8bef9SDimitry Andric 
877e8d8bef9SDimitry Andric     if (options.NoOutput || options.Intermediate)
878e8d8bef9SDimitry Andric       continue;
879e8d8bef9SDimitry Andric     Optional<raw_fd_ostream> os;
880e8d8bef9SDimitry Andric     if (!options.UseStdout) {
881e8d8bef9SDimitry Andric       std::error_code ec;
882fe6060f1SDimitry Andric       os.emplace(gcovName, ec, sys::fs::OF_TextWithCRLF);
883e8d8bef9SDimitry Andric       if (ec) {
884e8d8bef9SDimitry Andric         errs() << ec.message() << '\n';
885e8d8bef9SDimitry Andric         continue;
886e8d8bef9SDimitry Andric       }
887e8d8bef9SDimitry Andric     }
888e8d8bef9SDimitry Andric     annotateSource(si, file, gcno, gcda,
889e8d8bef9SDimitry Andric                    options.UseStdout ? llvm::outs() : *os);
890e8d8bef9SDimitry Andric   }
891e8d8bef9SDimitry Andric 
892e8d8bef9SDimitry Andric   if (options.Intermediate && !options.NoOutput) {
893e8d8bef9SDimitry Andric     // gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0
894e8d8bef9SDimitry Andric     // (PR GCC/82702). We create just one file.
895e8d8bef9SDimitry Andric     std::string outputPath(sys::path::filename(filename));
896e8d8bef9SDimitry Andric     std::error_code ec;
897fe6060f1SDimitry Andric     raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_TextWithCRLF);
898e8d8bef9SDimitry Andric     if (ec) {
899e8d8bef9SDimitry Andric       errs() << ec.message() << '\n';
900e8d8bef9SDimitry Andric       return;
901e8d8bef9SDimitry Andric     }
902e8d8bef9SDimitry Andric 
903e8d8bef9SDimitry Andric     for (const SourceInfo &si : sources)
904e8d8bef9SDimitry Andric       printSourceToIntermediate(si, os);
905e8d8bef9SDimitry Andric   }
906e8d8bef9SDimitry Andric }
907e8d8bef9SDimitry Andric 
908e8d8bef9SDimitry Andric void Context::printFunctionDetails(const GCOVFunction &f,
909e8d8bef9SDimitry Andric                                    raw_ostream &os) const {
910e8d8bef9SDimitry Andric   const uint64_t entryCount = f.getEntryCount();
911e8d8bef9SDimitry Andric   uint32_t blocksExec = 0;
912e8d8bef9SDimitry Andric   const GCOVBlock &exitBlock = f.getExitBlock();
913e8d8bef9SDimitry Andric   uint64_t exitCount = 0;
914e8d8bef9SDimitry Andric   for (const GCOVArc *arc : exitBlock.pred)
915e8d8bef9SDimitry Andric     exitCount += arc->count;
916e8d8bef9SDimitry Andric   for (const GCOVBlock &b : f.blocksRange())
917e8d8bef9SDimitry Andric     if (b.number != 0 && &b != &exitBlock && b.getCount())
918e8d8bef9SDimitry Andric       ++blocksExec;
919e8d8bef9SDimitry Andric 
920e8d8bef9SDimitry Andric   os << "function " << f.getName(options.Demangle) << " called " << entryCount
921e8d8bef9SDimitry Andric      << " returned " << formatPercentage(exitCount, entryCount)
922e8d8bef9SDimitry Andric      << "% blocks executed "
923e8d8bef9SDimitry Andric      << formatPercentage(blocksExec, f.blocks.size() - 2) << "%\n";
9240b57cec5SDimitry Andric }
9250b57cec5SDimitry Andric 
9260b57cec5SDimitry Andric /// printBranchInfo - Print conditional branch probabilities.
927e8d8bef9SDimitry Andric void Context::printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
928e8d8bef9SDimitry Andric                               raw_ostream &os) const {
929e8d8bef9SDimitry Andric   uint64_t total = 0;
930e8d8bef9SDimitry Andric   for (const GCOVArc *arc : Block.dsts())
931e8d8bef9SDimitry Andric     total += arc->count;
932e8d8bef9SDimitry Andric   for (const GCOVArc *arc : Block.dsts())
933e8d8bef9SDimitry Andric     os << format("branch %2u ", edgeIdx++)
934e8d8bef9SDimitry Andric        << formatBranchInfo(options, arc->count, total) << '\n';
9350b57cec5SDimitry Andric }
9360b57cec5SDimitry Andric 
937e8d8bef9SDimitry Andric void Context::printSummary(const Summary &summary, raw_ostream &os) const {
938e8d8bef9SDimitry Andric   os << format("Lines executed:%.2f%% of %" PRIu64 "\n",
939e8d8bef9SDimitry Andric                double(summary.linesExec) * 100 / summary.lines, summary.lines);
940e8d8bef9SDimitry Andric   if (options.BranchInfo) {
941e8d8bef9SDimitry Andric     if (summary.branches == 0) {
942e8d8bef9SDimitry Andric       os << "No branches\n";
9430b57cec5SDimitry Andric     } else {
944e8d8bef9SDimitry Andric       os << format("Branches executed:%.2f%% of %" PRIu64 "\n",
945e8d8bef9SDimitry Andric                    double(summary.branchesExec) * 100 / summary.branches,
946e8d8bef9SDimitry Andric                    summary.branches);
947e8d8bef9SDimitry Andric       os << format("Taken at least once:%.2f%% of %" PRIu64 "\n",
948e8d8bef9SDimitry Andric                    double(summary.branchesTaken) * 100 / summary.branches,
949e8d8bef9SDimitry Andric                    summary.branches);
9500b57cec5SDimitry Andric     }
951e8d8bef9SDimitry Andric     os << "No calls\n";
9520b57cec5SDimitry Andric   }
9530b57cec5SDimitry Andric }
9540b57cec5SDimitry Andric 
955e8d8bef9SDimitry Andric void llvm::gcovOneInput(const GCOV::Options &options, StringRef filename,
956e8d8bef9SDimitry Andric                         StringRef gcno, StringRef gcda, GCOVFile &file) {
957e8d8bef9SDimitry Andric   Context fi(options);
958e8d8bef9SDimitry Andric   fi.print(filename, gcno, gcda, file);
9590b57cec5SDimitry Andric }
960