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