gcov.cpp revision 288943
1189251Ssam//===- gcov.cpp - GCOV compatible LLVM coverage tool ----------------------===// 2189251Ssam// 3189251Ssam// The LLVM Compiler Infrastructure 4189251Ssam// 5252726Srpaulo// This file is distributed under the University of Illinois Open Source 6252726Srpaulo// License. See LICENSE.TXT for details. 7189251Ssam// 8189251Ssam//===----------------------------------------------------------------------===// 9189251Ssam// 10189251Ssam// llvm-cov is a command line tools to analyze and report coverage information. 11189251Ssam// 12189251Ssam//===----------------------------------------------------------------------===// 13189251Ssam 14189251Ssam#include "llvm/ADT/SmallString.h" 15189251Ssam#include "llvm/Support/CommandLine.h" 16189251Ssam#include "llvm/Support/Errc.h" 17189251Ssam#include "llvm/Support/FileSystem.h" 18189251Ssam#include "llvm/Support/GCOV.h" 19189251Ssam#include "llvm/Support/ManagedStatic.h" 20189251Ssam#include "llvm/Support/Path.h" 21189251Ssam#include "llvm/Support/PrettyStackTrace.h" 22189251Ssam#include "llvm/Support/Signals.h" 23189251Ssam#include <system_error> 24189251Ssamusing namespace llvm; 25189251Ssam 26189251Ssamstatic void reportCoverage(StringRef SourceFile, StringRef ObjectDir, 27189251Ssam const std::string &InputGCNO, 28189251Ssam const std::string &InputGCDA, bool DumpGCOV, 29189251Ssam const GCOVOptions &Options) { 30189251Ssam SmallString<128> CoverageFileStem(ObjectDir); 31189251Ssam if (CoverageFileStem.empty()) { 32189251Ssam // If no directory was specified with -o, look next to the source file. 33189251Ssam CoverageFileStem = sys::path::parent_path(SourceFile); 34189251Ssam sys::path::append(CoverageFileStem, sys::path::stem(SourceFile)); 35189251Ssam } else if (sys::fs::is_directory(ObjectDir)) 36189251Ssam // A directory name was given. Use it and the source file name. 37189251Ssam sys::path::append(CoverageFileStem, sys::path::stem(SourceFile)); 38189251Ssam else 39189251Ssam // A file was given. Ignore the source file and look next to this file. 40189251Ssam sys::path::replace_extension(CoverageFileStem, ""); 41189251Ssam 42189251Ssam std::string GCNO = InputGCNO.empty() 43189251Ssam ? std::string(CoverageFileStem.str()) + ".gcno" 44189251Ssam : InputGCNO; 45189251Ssam std::string GCDA = InputGCDA.empty() 46189251Ssam ? std::string(CoverageFileStem.str()) + ".gcda" 47189251Ssam : InputGCDA; 48189251Ssam GCOVFile GF; 49189251Ssam 50189251Ssam ErrorOr<std::unique_ptr<MemoryBuffer>> GCNO_Buff = 51189251Ssam MemoryBuffer::getFileOrSTDIN(GCNO); 52189251Ssam if (std::error_code EC = GCNO_Buff.getError()) { 53189251Ssam errs() << GCNO << ": " << EC.message() << "\n"; 54189251Ssam return; 55189251Ssam } 56189251Ssam GCOVBuffer GCNO_GB(GCNO_Buff.get().get()); 57189251Ssam if (!GF.readGCNO(GCNO_GB)) { 58189251Ssam errs() << "Invalid .gcno File!\n"; 59189251Ssam return; 60189251Ssam } 61189251Ssam 62189251Ssam ErrorOr<std::unique_ptr<MemoryBuffer>> GCDA_Buff = 63189251Ssam MemoryBuffer::getFileOrSTDIN(GCDA); 64189251Ssam if (std::error_code EC = GCDA_Buff.getError()) { 65189251Ssam if (EC != errc::no_such_file_or_directory) { 66189251Ssam errs() << GCDA << ": " << EC.message() << "\n"; 67189251Ssam return; 68189251Ssam } 69189251Ssam // Clear the filename to make it clear we didn't read anything. 70189251Ssam GCDA = "-"; 71189251Ssam } else { 72189251Ssam GCOVBuffer GCDA_GB(GCDA_Buff.get().get()); 73189251Ssam if (!GF.readGCDA(GCDA_GB)) { 74189251Ssam errs() << "Invalid .gcda File!\n"; 75189251Ssam return; 76189251Ssam } 77189251Ssam } 78189251Ssam 79189251Ssam if (DumpGCOV) 80189251Ssam GF.dump(); 81189251Ssam 82189251Ssam FileInfo FI(Options); 83189251Ssam GF.collectLineCounts(FI); 84189251Ssam FI.print(llvm::outs(), SourceFile, GCNO, GCDA); 85189251Ssam} 86189251Ssam 87189251Ssamint gcovMain(int argc, const char *argv[]) { 88189251Ssam // Print a stack trace if we signal out. 89189251Ssam sys::PrintStackTraceOnErrorSignal(); 90189251Ssam PrettyStackTraceProgram X(argc, argv); 91189251Ssam llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 92189251Ssam 93189251Ssam cl::list<std::string> SourceFiles(cl::Positional, cl::OneOrMore, 94189251Ssam cl::desc("SOURCEFILE")); 95189251Ssam 96189251Ssam cl::opt<bool> AllBlocks("a", cl::Grouping, cl::init(false), 97189251Ssam cl::desc("Display all basic blocks")); 98189251Ssam cl::alias AllBlocksA("all-blocks", cl::aliasopt(AllBlocks)); 99189251Ssam 100189251Ssam cl::opt<bool> BranchProb("b", cl::Grouping, cl::init(false), 101189251Ssam cl::desc("Display branch probabilities")); 102189251Ssam cl::alias BranchProbA("branch-probabilities", cl::aliasopt(BranchProb)); 103189251Ssam 104189251Ssam cl::opt<bool> BranchCount("c", cl::Grouping, cl::init(false), 105189251Ssam cl::desc("Display branch counts instead " 106189251Ssam "of percentages (requires -b)")); 107189251Ssam cl::alias BranchCountA("branch-counts", cl::aliasopt(BranchCount)); 108189251Ssam 109189251Ssam cl::opt<bool> LongNames("l", cl::Grouping, cl::init(false), 110189251Ssam cl::desc("Prefix filenames with the main file")); 111189251Ssam cl::alias LongNamesA("long-file-names", cl::aliasopt(LongNames)); 112189251Ssam 113189251Ssam cl::opt<bool> FuncSummary("f", cl::Grouping, cl::init(false), 114189251Ssam cl::desc("Show coverage for each function")); 115189251Ssam cl::alias FuncSummaryA("function-summaries", cl::aliasopt(FuncSummary)); 116189251Ssam 117189251Ssam cl::opt<bool> NoOutput("n", cl::Grouping, cl::init(false), 118189251Ssam cl::desc("Do not output any .gcov files")); 119189251Ssam cl::alias NoOutputA("no-output", cl::aliasopt(NoOutput)); 120189251Ssam 121189251Ssam cl::opt<std::string> ObjectDir( 122189251Ssam "o", cl::value_desc("DIR|FILE"), cl::init(""), 123189251Ssam cl::desc("Find objects in DIR or based on FILE's path")); 124189251Ssam cl::alias ObjectDirA("object-directory", cl::aliasopt(ObjectDir)); 125189251Ssam cl::alias ObjectDirB("object-file", cl::aliasopt(ObjectDir)); 126189251Ssam 127189251Ssam cl::opt<bool> PreservePaths("p", cl::Grouping, cl::init(false), 128189251Ssam cl::desc("Preserve path components")); 129189251Ssam cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths)); 130189251Ssam 131189251Ssam cl::opt<bool> UncondBranch("u", cl::Grouping, cl::init(false), 132189251Ssam cl::desc("Display unconditional branch info " 133189251Ssam "(requires -b)")); 134189251Ssam cl::alias UncondBranchA("unconditional-branches", cl::aliasopt(UncondBranch)); 135189251Ssam 136189251Ssam cl::OptionCategory DebugCat("Internal and debugging options"); 137189251Ssam cl::opt<bool> DumpGCOV("dump", cl::init(false), cl::cat(DebugCat), 138189251Ssam cl::desc("Dump the gcov file to stderr")); 139189251Ssam cl::opt<std::string> InputGCNO("gcno", cl::cat(DebugCat), cl::init(""), 140189251Ssam cl::desc("Override inferred gcno file")); 141189251Ssam cl::opt<std::string> InputGCDA("gcda", cl::cat(DebugCat), cl::init(""), 142189251Ssam cl::desc("Override inferred gcda file")); 143189251Ssam 144189251Ssam cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); 145189251Ssam 146189251Ssam GCOVOptions Options(AllBlocks, BranchProb, BranchCount, FuncSummary, 147189251Ssam PreservePaths, UncondBranch, LongNames, NoOutput); 148189251Ssam 149189251Ssam for (const auto &SourceFile : SourceFiles) 150189251Ssam reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV, 151189251Ssam Options); 152189251Ssam return 0; 153189251Ssam} 154189251Ssam