10b57cec5SDimitry Andric //===- gcov.cpp - GCOV compatible 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 // llvm-cov is a command line tools to analyze and report coverage information. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/ProfileData/GCOV.h" 140b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 150b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 160b57cec5SDimitry Andric #include "llvm/Support/Errc.h" 170b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 180b57cec5SDimitry Andric #include "llvm/Support/Path.h" 190b57cec5SDimitry Andric #include <system_error> 200b57cec5SDimitry Andric using namespace llvm; 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric static void reportCoverage(StringRef SourceFile, StringRef ObjectDir, 230b57cec5SDimitry Andric const std::string &InputGCNO, 240b57cec5SDimitry Andric const std::string &InputGCDA, bool DumpGCOV, 250b57cec5SDimitry Andric const GCOV::Options &Options) { 260b57cec5SDimitry Andric SmallString<128> CoverageFileStem(ObjectDir); 270b57cec5SDimitry Andric if (CoverageFileStem.empty()) { 280b57cec5SDimitry Andric // If no directory was specified with -o, look next to the source file. 290b57cec5SDimitry Andric CoverageFileStem = sys::path::parent_path(SourceFile); 300b57cec5SDimitry Andric sys::path::append(CoverageFileStem, sys::path::stem(SourceFile)); 310b57cec5SDimitry Andric } else if (sys::fs::is_directory(ObjectDir)) 320b57cec5SDimitry Andric // A directory name was given. Use it and the source file name. 330b57cec5SDimitry Andric sys::path::append(CoverageFileStem, sys::path::stem(SourceFile)); 340b57cec5SDimitry Andric else 350b57cec5SDimitry Andric // A file was given. Ignore the source file and look next to this file. 360b57cec5SDimitry Andric sys::path::replace_extension(CoverageFileStem, ""); 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric std::string GCNO = InputGCNO.empty() 390b57cec5SDimitry Andric ? std::string(CoverageFileStem.str()) + ".gcno" 400b57cec5SDimitry Andric : InputGCNO; 410b57cec5SDimitry Andric std::string GCDA = InputGCDA.empty() 420b57cec5SDimitry Andric ? std::string(CoverageFileStem.str()) + ".gcda" 430b57cec5SDimitry Andric : InputGCDA; 440b57cec5SDimitry Andric GCOVFile GF; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> GCNO_Buff = 470b57cec5SDimitry Andric MemoryBuffer::getFileOrSTDIN(GCNO); 480b57cec5SDimitry Andric if (std::error_code EC = GCNO_Buff.getError()) { 490b57cec5SDimitry Andric errs() << GCNO << ": " << EC.message() << "\n"; 500b57cec5SDimitry Andric return; 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric GCOVBuffer GCNO_GB(GCNO_Buff.get().get()); 530b57cec5SDimitry Andric if (!GF.readGCNO(GCNO_GB)) { 540b57cec5SDimitry Andric errs() << "Invalid .gcno File!\n"; 550b57cec5SDimitry Andric return; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> GCDA_Buff = 590b57cec5SDimitry Andric MemoryBuffer::getFileOrSTDIN(GCDA); 600b57cec5SDimitry Andric if (std::error_code EC = GCDA_Buff.getError()) { 610b57cec5SDimitry Andric if (EC != errc::no_such_file_or_directory) { 620b57cec5SDimitry Andric errs() << GCDA << ": " << EC.message() << "\n"; 630b57cec5SDimitry Andric return; 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric // Clear the filename to make it clear we didn't read anything. 660b57cec5SDimitry Andric GCDA = "-"; 670b57cec5SDimitry Andric } else { 68*5ffd83dbSDimitry Andric GCOVBuffer gcda_buf(GCDA_Buff.get().get()); 69*5ffd83dbSDimitry Andric if (!gcda_buf.readGCDAFormat()) 70*5ffd83dbSDimitry Andric errs() << GCDA << ":not a gcov data file\n"; 71*5ffd83dbSDimitry Andric else if (!GF.readGCDA(gcda_buf)) 720b57cec5SDimitry Andric errs() << "Invalid .gcda File!\n"; 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric if (DumpGCOV) 760b57cec5SDimitry Andric GF.print(errs()); 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric FileInfo FI(Options); 790b57cec5SDimitry Andric GF.collectLineCounts(FI); 80*5ffd83dbSDimitry Andric FI.print(llvm::outs(), SourceFile, GCNO, GCDA, GF); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric int gcovMain(int argc, const char *argv[]) { 840b57cec5SDimitry Andric cl::list<std::string> SourceFiles(cl::Positional, cl::OneOrMore, 850b57cec5SDimitry Andric cl::desc("SOURCEFILE")); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric cl::opt<bool> AllBlocks("a", cl::Grouping, cl::init(false), 880b57cec5SDimitry Andric cl::desc("Display all basic blocks")); 890b57cec5SDimitry Andric cl::alias AllBlocksA("all-blocks", cl::aliasopt(AllBlocks)); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric cl::opt<bool> BranchProb("b", cl::Grouping, cl::init(false), 920b57cec5SDimitry Andric cl::desc("Display branch probabilities")); 930b57cec5SDimitry Andric cl::alias BranchProbA("branch-probabilities", cl::aliasopt(BranchProb)); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric cl::opt<bool> BranchCount("c", cl::Grouping, cl::init(false), 960b57cec5SDimitry Andric cl::desc("Display branch counts instead " 970b57cec5SDimitry Andric "of percentages (requires -b)")); 980b57cec5SDimitry Andric cl::alias BranchCountA("branch-counts", cl::aliasopt(BranchCount)); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric cl::opt<bool> LongNames("l", cl::Grouping, cl::init(false), 1010b57cec5SDimitry Andric cl::desc("Prefix filenames with the main file")); 1020b57cec5SDimitry Andric cl::alias LongNamesA("long-file-names", cl::aliasopt(LongNames)); 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric cl::opt<bool> FuncSummary("f", cl::Grouping, cl::init(false), 1050b57cec5SDimitry Andric cl::desc("Show coverage for each function")); 1060b57cec5SDimitry Andric cl::alias FuncSummaryA("function-summaries", cl::aliasopt(FuncSummary)); 1070b57cec5SDimitry Andric 108*5ffd83dbSDimitry Andric // Supported by gcov 4.9~8. gcov 9 (GCC r265587) removed --intermediate-format 109*5ffd83dbSDimitry Andric // and -i was changed to mean --json-format. We consider this format still 110*5ffd83dbSDimitry Andric // useful and support -i. 111*5ffd83dbSDimitry Andric cl::opt<bool> Intermediate( 112*5ffd83dbSDimitry Andric "intermediate-format", cl::init(false), 113*5ffd83dbSDimitry Andric cl::desc("Output .gcov in intermediate text format")); 114*5ffd83dbSDimitry Andric cl::alias IntermediateA("i", cl::desc("Alias for --intermediate-format"), 115*5ffd83dbSDimitry Andric cl::Grouping, cl::NotHidden, 116*5ffd83dbSDimitry Andric cl::aliasopt(Intermediate)); 117*5ffd83dbSDimitry Andric 1180b57cec5SDimitry Andric cl::opt<bool> NoOutput("n", cl::Grouping, cl::init(false), 1190b57cec5SDimitry Andric cl::desc("Do not output any .gcov files")); 1200b57cec5SDimitry Andric cl::alias NoOutputA("no-output", cl::aliasopt(NoOutput)); 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric cl::opt<std::string> ObjectDir( 1230b57cec5SDimitry Andric "o", cl::value_desc("DIR|FILE"), cl::init(""), 1240b57cec5SDimitry Andric cl::desc("Find objects in DIR or based on FILE's path")); 1250b57cec5SDimitry Andric cl::alias ObjectDirA("object-directory", cl::aliasopt(ObjectDir)); 1260b57cec5SDimitry Andric cl::alias ObjectDirB("object-file", cl::aliasopt(ObjectDir)); 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric cl::opt<bool> PreservePaths("p", cl::Grouping, cl::init(false), 1290b57cec5SDimitry Andric cl::desc("Preserve path components")); 1300b57cec5SDimitry Andric cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths)); 1310b57cec5SDimitry Andric 132*5ffd83dbSDimitry Andric cl::opt<bool> UseStdout("t", cl::Grouping, cl::init(false), 133*5ffd83dbSDimitry Andric cl::desc("Print to stdout")); 134*5ffd83dbSDimitry Andric cl::alias UseStdoutA("stdout", cl::aliasopt(UseStdout)); 135*5ffd83dbSDimitry Andric 1360b57cec5SDimitry Andric cl::opt<bool> UncondBranch("u", cl::Grouping, cl::init(false), 1370b57cec5SDimitry Andric cl::desc("Display unconditional branch info " 1380b57cec5SDimitry Andric "(requires -b)")); 1390b57cec5SDimitry Andric cl::alias UncondBranchA("unconditional-branches", cl::aliasopt(UncondBranch)); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric cl::opt<bool> HashFilenames("x", cl::Grouping, cl::init(false), 1420b57cec5SDimitry Andric cl::desc("Hash long pathnames")); 1430b57cec5SDimitry Andric cl::alias HashFilenamesA("hash-filenames", cl::aliasopt(HashFilenames)); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric cl::OptionCategory DebugCat("Internal and debugging options"); 1470b57cec5SDimitry Andric cl::opt<bool> DumpGCOV("dump", cl::init(false), cl::cat(DebugCat), 1480b57cec5SDimitry Andric cl::desc("Dump the gcov file to stderr")); 1490b57cec5SDimitry Andric cl::opt<std::string> InputGCNO("gcno", cl::cat(DebugCat), cl::init(""), 1500b57cec5SDimitry Andric cl::desc("Override inferred gcno file")); 1510b57cec5SDimitry Andric cl::opt<std::string> InputGCDA("gcda", cl::cat(DebugCat), cl::init(""), 1520b57cec5SDimitry Andric cl::desc("Override inferred gcda file")); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric GCOV::Options Options(AllBlocks, BranchProb, BranchCount, FuncSummary, 157*5ffd83dbSDimitry Andric PreservePaths, UncondBranch, Intermediate, LongNames, 158*5ffd83dbSDimitry Andric NoOutput, UseStdout, HashFilenames); 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric for (const auto &SourceFile : SourceFiles) 1610b57cec5SDimitry Andric reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV, 1620b57cec5SDimitry Andric Options); 1630b57cec5SDimitry Andric return 0; 1640b57cec5SDimitry Andric } 165