1 //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // The 'CodeCoverageTool' class implements a command line tool to analyze and
11 // report coverage information using the profiling instrumentation and code
12 // coverage mapping.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "CoverageExporterJson.h"
17 #include "CoverageFilters.h"
18 #include "CoverageReport.h"
19 #include "CoverageSummaryInfo.h"
20 #include "CoverageViewOptions.h"
21 #include "RenderingSupport.h"
22 #include "SourceCoverageView.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/ADT/Triple.h"
26 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
27 #include "llvm/ProfileData/InstrProfReader.h"
28 #include "llvm/Support/CommandLine.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Format.h"
31 #include "llvm/Support/MemoryBuffer.h"
32 #include "llvm/Support/Path.h"
33 #include "llvm/Support/Process.h"
34 #include "llvm/Support/Program.h"
35 #include "llvm/Support/ScopedPrinter.h"
36 #include "llvm/Support/Threading.h"
37 #include "llvm/Support/ThreadPool.h"
38 #include "llvm/Support/ToolOutputFile.h"
39 
40 #include <functional>
41 #include <map>
42 #include <system_error>
43 
44 using namespace llvm;
45 using namespace coverage;
46 
47 void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping,
48                               const CoverageViewOptions &Options,
49                               raw_ostream &OS);
50 
51 namespace {
52 /// \brief The implementation of the coverage tool.
53 class CodeCoverageTool {
54 public:
55   enum Command {
56     /// \brief The show command.
57     Show,
58     /// \brief The report command.
59     Report,
60     /// \brief The export command.
61     Export
62   };
63 
64   int run(Command Cmd, int argc, const char **argv);
65 
66 private:
67   /// \brief Print the error message to the error output stream.
68   void error(const Twine &Message, StringRef Whence = "");
69 
70   /// \brief Print the warning message to the error output stream.
71   void warning(const Twine &Message, StringRef Whence = "");
72 
73   /// \brief Convert \p Path into an absolute path and append it to the list
74   /// of collected paths.
75   void addCollectedPath(const std::string &Path);
76 
77   /// \brief If \p Path is a regular file, collect the path. If it's a
78   /// directory, recursively collect all of the paths within the directory.
79   void collectPaths(const std::string &Path);
80 
81   /// \brief Return a memory buffer for the given source file.
82   ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
83 
84   /// \brief Create source views for the expansions of the view.
85   void attachExpansionSubViews(SourceCoverageView &View,
86                                ArrayRef<ExpansionRecord> Expansions,
87                                const CoverageMapping &Coverage);
88 
89   /// \brief Create the source view of a particular function.
90   std::unique_ptr<SourceCoverageView>
91   createFunctionView(const FunctionRecord &Function,
92                      const CoverageMapping &Coverage);
93 
94   /// \brief Create the main source view of a particular source file.
95   std::unique_ptr<SourceCoverageView>
96   createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
97 
98   /// \brief Load the coverage mapping data. Return nullptr if an error occurred.
99   std::unique_ptr<CoverageMapping> load();
100 
101   /// \brief Create a mapping from files in the Coverage data to local copies
102   /// (path-equivalence).
103   void remapPathNames(const CoverageMapping &Coverage);
104 
105   /// \brief Remove input source files which aren't mapped by \p Coverage.
106   void removeUnmappedInputs(const CoverageMapping &Coverage);
107 
108   /// \brief If a demangler is available, demangle all symbol names.
109   void demangleSymbols(const CoverageMapping &Coverage);
110 
111   /// \brief Write out a source file view to the filesystem.
112   void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
113                            CoveragePrinter *Printer, bool ShowFilenames);
114 
115   typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
116 
117   int doShow(int argc, const char **argv,
118              CommandLineParserType commandLineParser);
119 
120   int doReport(int argc, const char **argv,
121                CommandLineParserType commandLineParser);
122 
123   int doExport(int argc, const char **argv,
124                CommandLineParserType commandLineParser);
125 
126   std::vector<StringRef> ObjectFilenames;
127   CoverageViewOptions ViewOpts;
128   CoverageFiltersMatchAll Filters;
129 
130   /// The path to the indexed profile.
131   std::string PGOFilename;
132 
133   /// A list of input source files.
134   std::vector<std::string> SourceFiles;
135 
136   /// In -path-equivalence mode, this maps the absolute paths from the coverage
137   /// mapping data to the input source files.
138   StringMap<std::string> RemappedFilenames;
139 
140   /// The coverage data path to be remapped from, and the source path to be
141   /// remapped to, when using -path-equivalence.
142   Optional<std::pair<std::string, std::string>> PathRemapping;
143 
144   /// The architecture the coverage mapping data targets.
145   std::vector<StringRef> CoverageArches;
146 
147   /// A cache for demangled symbols.
148   DemangleCache DC;
149 
150   /// A lock which guards printing to stderr.
151   std::mutex ErrsLock;
152 
153   /// A container for input source file buffers.
154   std::mutex LoadedSourceFilesLock;
155   std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
156       LoadedSourceFiles;
157 
158   /// Whitelist from -name-whitelist to be used for filtering.
159   std::unique_ptr<SpecialCaseList> NameWhitelist;
160 };
161 }
162 
163 static std::string getErrorString(const Twine &Message, StringRef Whence,
164                                   bool Warning) {
165   std::string Str = (Warning ? "warning" : "error");
166   Str += ": ";
167   if (!Whence.empty())
168     Str += Whence.str() + ": ";
169   Str += Message.str() + "\n";
170   return Str;
171 }
172 
173 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
174   std::unique_lock<std::mutex> Guard{ErrsLock};
175   ViewOpts.colored_ostream(errs(), raw_ostream::RED)
176       << getErrorString(Message, Whence, false);
177 }
178 
179 void CodeCoverageTool::warning(const Twine &Message, StringRef Whence) {
180   std::unique_lock<std::mutex> Guard{ErrsLock};
181   ViewOpts.colored_ostream(errs(), raw_ostream::RED)
182       << getErrorString(Message, Whence, true);
183 }
184 
185 void CodeCoverageTool::addCollectedPath(const std::string &Path) {
186   SmallString<128> EffectivePath(Path);
187   if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) {
188     error(EC.message(), Path);
189     return;
190   }
191   sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
192   SourceFiles.emplace_back(EffectivePath.str());
193 }
194 
195 void CodeCoverageTool::collectPaths(const std::string &Path) {
196   llvm::sys::fs::file_status Status;
197   llvm::sys::fs::status(Path, Status);
198   if (!llvm::sys::fs::exists(Status)) {
199     if (PathRemapping)
200       addCollectedPath(Path);
201     else
202       error("Missing source file", Path);
203     return;
204   }
205 
206   if (llvm::sys::fs::is_regular_file(Status)) {
207     addCollectedPath(Path);
208     return;
209   }
210 
211   if (llvm::sys::fs::is_directory(Status)) {
212     std::error_code EC;
213     for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E;
214          F != E && !EC; F.increment(EC)) {
215       if (llvm::sys::fs::is_regular_file(F->path()))
216         addCollectedPath(F->path());
217     }
218     if (EC)
219       warning(EC.message(), Path);
220   }
221 }
222 
223 ErrorOr<const MemoryBuffer &>
224 CodeCoverageTool::getSourceFile(StringRef SourceFile) {
225   // If we've remapped filenames, look up the real location for this file.
226   std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
227   if (!RemappedFilenames.empty()) {
228     auto Loc = RemappedFilenames.find(SourceFile);
229     if (Loc != RemappedFilenames.end())
230       SourceFile = Loc->second;
231   }
232   for (const auto &Files : LoadedSourceFiles)
233     if (sys::fs::equivalent(SourceFile, Files.first))
234       return *Files.second;
235   auto Buffer = MemoryBuffer::getFile(SourceFile);
236   if (auto EC = Buffer.getError()) {
237     error(EC.message(), SourceFile);
238     return EC;
239   }
240   LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
241   return *LoadedSourceFiles.back().second;
242 }
243 
244 void CodeCoverageTool::attachExpansionSubViews(
245     SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions,
246     const CoverageMapping &Coverage) {
247   if (!ViewOpts.ShowExpandedRegions)
248     return;
249   for (const auto &Expansion : Expansions) {
250     auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
251     if (ExpansionCoverage.empty())
252       continue;
253     auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
254     if (!SourceBuffer)
255       continue;
256 
257     auto SubViewExpansions = ExpansionCoverage.getExpansions();
258     auto SubView =
259         SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
260                                    ViewOpts, std::move(ExpansionCoverage));
261     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
262     View.addExpansion(Expansion.Region, std::move(SubView));
263   }
264 }
265 
266 std::unique_ptr<SourceCoverageView>
267 CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
268                                      const CoverageMapping &Coverage) {
269   auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
270   if (FunctionCoverage.empty())
271     return nullptr;
272   auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
273   if (!SourceBuffer)
274     return nullptr;
275 
276   auto Expansions = FunctionCoverage.getExpansions();
277   auto View = SourceCoverageView::create(DC.demangle(Function.Name),
278                                          SourceBuffer.get(), ViewOpts,
279                                          std::move(FunctionCoverage));
280   attachExpansionSubViews(*View, Expansions, Coverage);
281 
282   return View;
283 }
284 
285 std::unique_ptr<SourceCoverageView>
286 CodeCoverageTool::createSourceFileView(StringRef SourceFile,
287                                        const CoverageMapping &Coverage) {
288   auto SourceBuffer = getSourceFile(SourceFile);
289   if (!SourceBuffer)
290     return nullptr;
291   auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
292   if (FileCoverage.empty())
293     return nullptr;
294 
295   auto Expansions = FileCoverage.getExpansions();
296   auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
297                                          ViewOpts, std::move(FileCoverage));
298   attachExpansionSubViews(*View, Expansions, Coverage);
299   if (!ViewOpts.ShowFunctionInstantiations)
300     return View;
301 
302   for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
303     // Skip functions which have a single instantiation.
304     if (Group.size() < 2)
305       continue;
306 
307     for (const FunctionRecord *Function : Group.getInstantiations()) {
308       std::unique_ptr<SourceCoverageView> SubView{nullptr};
309 
310       StringRef Funcname = DC.demangle(Function->Name);
311 
312       if (Function->ExecutionCount > 0) {
313         auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
314         auto SubViewExpansions = SubViewCoverage.getExpansions();
315         SubView = SourceCoverageView::create(
316             Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
317         attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
318       }
319 
320       unsigned FileID = Function->CountedRegions.front().FileID;
321       unsigned Line = 0;
322       for (const auto &CR : Function->CountedRegions)
323         if (CR.FileID == FileID)
324           Line = std::max(CR.LineEnd, Line);
325       View->addInstantiation(Funcname, Line, std::move(SubView));
326     }
327   }
328   return View;
329 }
330 
331 static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
332   sys::fs::file_status Status;
333   if (sys::fs::status(LHS, Status))
334     return false;
335   auto LHSTime = Status.getLastModificationTime();
336   if (sys::fs::status(RHS, Status))
337     return false;
338   auto RHSTime = Status.getLastModificationTime();
339   return LHSTime > RHSTime;
340 }
341 
342 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
343   for (StringRef ObjectFilename : ObjectFilenames)
344     if (modifiedTimeGT(ObjectFilename, PGOFilename))
345       warning("profile data may be out of date - object is newer",
346               ObjectFilename);
347   auto CoverageOrErr =
348       CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches);
349   if (Error E = CoverageOrErr.takeError()) {
350     error("Failed to load coverage: " + toString(std::move(E)),
351           join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
352     return nullptr;
353   }
354   auto Coverage = std::move(CoverageOrErr.get());
355   unsigned Mismatched = Coverage->getMismatchedCount();
356   if (Mismatched) {
357     warning(Twine(Mismatched) + " functions have mismatched data");
358 
359     if (ViewOpts.Debug) {
360       for (const auto &HashMismatch : Coverage->getHashMismatches())
361         errs() << "hash-mismatch: "
362                << "No profile record found for '" << HashMismatch.first << "'"
363                << " with hash = 0x" << Twine::utohexstr(HashMismatch.second)
364                << '\n';
365 
366       for (const auto &CounterMismatch : Coverage->getCounterMismatches())
367         errs() << "counter-mismatch: "
368                << "Coverage mapping for " << CounterMismatch.first
369                << " only has " << CounterMismatch.second
370                << " valid counter expressions\n";
371     }
372   }
373 
374   remapPathNames(*Coverage);
375 
376   if (!SourceFiles.empty())
377     removeUnmappedInputs(*Coverage);
378 
379   demangleSymbols(*Coverage);
380 
381   return Coverage;
382 }
383 
384 void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
385   if (!PathRemapping)
386     return;
387 
388   // Convert remapping paths to native paths with trailing seperators.
389   auto nativeWithTrailing = [](StringRef Path) -> std::string {
390     if (Path.empty())
391       return "";
392     SmallString<128> NativePath;
393     sys::path::native(Path, NativePath);
394     if (!sys::path::is_separator(NativePath.back()))
395       NativePath += sys::path::get_separator();
396     return NativePath.c_str();
397   };
398   std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
399   std::string RemapTo = nativeWithTrailing(PathRemapping->second);
400 
401   // Create a mapping from coverage data file paths to local paths.
402   for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
403     SmallString<128> NativeFilename;
404     sys::path::native(Filename, NativeFilename);
405     if (NativeFilename.startswith(RemapFrom)) {
406       RemappedFilenames[Filename] =
407           RemapTo + NativeFilename.substr(RemapFrom.size()).str();
408     }
409   }
410 
411   // Convert input files from local paths to coverage data file paths.
412   StringMap<std::string> InvRemappedFilenames;
413   for (const auto &RemappedFilename : RemappedFilenames)
414     InvRemappedFilenames[RemappedFilename.getValue()] = RemappedFilename.getKey();
415 
416   for (std::string &Filename : SourceFiles) {
417     SmallString<128> NativeFilename;
418     sys::path::native(Filename, NativeFilename);
419     auto CovFileName = InvRemappedFilenames.find(NativeFilename);
420     if (CovFileName != InvRemappedFilenames.end())
421       Filename = CovFileName->second;
422   }
423 }
424 
425 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) {
426   std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles();
427 
428   auto UncoveredFilesIt = SourceFiles.end();
429   // The user may have specified source files which aren't in the coverage
430   // mapping. Filter these files away.
431   UncoveredFilesIt = std::remove_if(
432       SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) {
433         return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(),
434                                    SF);
435       });
436 
437   SourceFiles.erase(UncoveredFilesIt, SourceFiles.end());
438 }
439 
440 void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
441   if (!ViewOpts.hasDemangler())
442     return;
443 
444   // Pass function names to the demangler in a temporary file.
445   int InputFD;
446   SmallString<256> InputPath;
447   std::error_code EC =
448       sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath);
449   if (EC) {
450     error(InputPath, EC.message());
451     return;
452   }
453   ToolOutputFile InputTOF{InputPath, InputFD};
454 
455   unsigned NumSymbols = 0;
456   for (const auto &Function : Coverage.getCoveredFunctions()) {
457     InputTOF.os() << Function.Name << '\n';
458     ++NumSymbols;
459   }
460   InputTOF.os().close();
461 
462   // Use another temporary file to store the demangler's output.
463   int OutputFD;
464   SmallString<256> OutputPath;
465   EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD,
466                                     OutputPath);
467   if (EC) {
468     error(OutputPath, EC.message());
469     return;
470   }
471   ToolOutputFile OutputTOF{OutputPath, OutputFD};
472   OutputTOF.os().close();
473 
474   // Invoke the demangler.
475   std::vector<const char *> ArgsV;
476   for (const std::string &Arg : ViewOpts.DemanglerOpts)
477     ArgsV.push_back(Arg.c_str());
478   ArgsV.push_back(nullptr);
479   Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
480   std::string ErrMsg;
481   int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
482                                /*env=*/nullptr, Redirects, /*secondsToWait=*/0,
483                                /*memoryLimit=*/0, &ErrMsg);
484   if (RC) {
485     error(ErrMsg, ViewOpts.DemanglerOpts[0]);
486     return;
487   }
488 
489   // Parse the demangler's output.
490   auto BufOrError = MemoryBuffer::getFile(OutputPath);
491   if (!BufOrError) {
492     error(OutputPath, BufOrError.getError().message());
493     return;
494   }
495 
496   std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError);
497 
498   SmallVector<StringRef, 8> Symbols;
499   StringRef DemanglerData = DemanglerBuf->getBuffer();
500   DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
501                       /*KeepEmpty=*/false);
502   if (Symbols.size() != NumSymbols) {
503     error("Demangler did not provide expected number of symbols");
504     return;
505   }
506 
507   // Cache the demangled names.
508   unsigned I = 0;
509   for (const auto &Function : Coverage.getCoveredFunctions())
510     // On Windows, lines in the demangler's output file end with "\r\n".
511     // Splitting by '\n' keeps '\r's, so cut them now.
512     DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
513 }
514 
515 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
516                                            CoverageMapping *Coverage,
517                                            CoveragePrinter *Printer,
518                                            bool ShowFilenames) {
519   auto View = createSourceFileView(SourceFile, *Coverage);
520   if (!View) {
521     warning("The file '" + SourceFile + "' isn't covered.");
522     return;
523   }
524 
525   auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
526   if (Error E = OSOrErr.takeError()) {
527     error("Could not create view file!", toString(std::move(E)));
528     return;
529   }
530   auto OS = std::move(OSOrErr.get());
531 
532   View->print(*OS.get(), /*Wholefile=*/true,
533               /*ShowSourceName=*/ShowFilenames,
534               /*ShowTitle=*/ViewOpts.hasOutputDirectory());
535   Printer->closeViewFile(std::move(OS));
536 }
537 
538 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
539   cl::opt<std::string> CovFilename(
540       cl::Positional, cl::desc("Covered executable or object file."));
541 
542   cl::list<std::string> CovFilenames(
543       "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore,
544       cl::CommaSeparated);
545 
546   cl::list<std::string> InputSourceFiles(
547       cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
548 
549   cl::opt<bool> DebugDumpCollectedPaths(
550       "dump-collected-paths", cl::Optional, cl::Hidden,
551       cl::desc("Show the collected paths to source files"));
552 
553   cl::opt<std::string, true> PGOFilename(
554       "instr-profile", cl::Required, cl::location(this->PGOFilename),
555       cl::desc(
556           "File with the profile data obtained after an instrumented run"));
557 
558   cl::list<std::string> Arches(
559       "arch", cl::desc("architectures of the coverage mapping binaries"));
560 
561   cl::opt<bool> DebugDump("dump", cl::Optional,
562                           cl::desc("Show internal debug dump"));
563 
564   cl::opt<CoverageViewOptions::OutputFormat> Format(
565       "format", cl::desc("Output format for line-based coverage reports"),
566       cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
567                             "Text output"),
568                  clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
569                             "HTML output")),
570       cl::init(CoverageViewOptions::OutputFormat::Text));
571 
572   cl::opt<std::string> PathRemap(
573       "path-equivalence", cl::Optional,
574       cl::desc("<from>,<to> Map coverage data paths to local source file "
575                "paths"));
576 
577   cl::OptionCategory FilteringCategory("Function filtering options");
578 
579   cl::list<std::string> NameFilters(
580       "name", cl::Optional,
581       cl::desc("Show code coverage only for functions with the given name"),
582       cl::ZeroOrMore, cl::cat(FilteringCategory));
583 
584   cl::list<std::string> NameFilterFiles(
585       "name-whitelist", cl::Optional,
586       cl::desc("Show code coverage only for functions listed in the given "
587                "file"),
588       cl::ZeroOrMore, cl::cat(FilteringCategory));
589 
590   cl::list<std::string> NameRegexFilters(
591       "name-regex", cl::Optional,
592       cl::desc("Show code coverage only for functions that match the given "
593                "regular expression"),
594       cl::ZeroOrMore, cl::cat(FilteringCategory));
595 
596   cl::opt<double> RegionCoverageLtFilter(
597       "region-coverage-lt", cl::Optional,
598       cl::desc("Show code coverage only for functions with region coverage "
599                "less than the given threshold"),
600       cl::cat(FilteringCategory));
601 
602   cl::opt<double> RegionCoverageGtFilter(
603       "region-coverage-gt", cl::Optional,
604       cl::desc("Show code coverage only for functions with region coverage "
605                "greater than the given threshold"),
606       cl::cat(FilteringCategory));
607 
608   cl::opt<double> LineCoverageLtFilter(
609       "line-coverage-lt", cl::Optional,
610       cl::desc("Show code coverage only for functions with line coverage less "
611                "than the given threshold"),
612       cl::cat(FilteringCategory));
613 
614   cl::opt<double> LineCoverageGtFilter(
615       "line-coverage-gt", cl::Optional,
616       cl::desc("Show code coverage only for functions with line coverage "
617                "greater than the given threshold"),
618       cl::cat(FilteringCategory));
619 
620   cl::opt<cl::boolOrDefault> UseColor(
621       "use-color", cl::desc("Emit colored output (default=autodetect)"),
622       cl::init(cl::BOU_UNSET));
623 
624   cl::list<std::string> DemanglerOpts(
625       "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
626 
627   cl::opt<bool> RegionSummary(
628       "show-region-summary", cl::Optional,
629       cl::desc("Show region statistics in summary table"),
630       cl::init(true));
631 
632   cl::opt<bool> InstantiationSummary(
633       "show-instantiation-summary", cl::Optional,
634       cl::desc("Show instantiation statistics in summary table"));
635 
636   cl::opt<bool> SummaryOnly(
637       "summary-only", cl::Optional,
638       cl::desc("Export only summary information for each source file"));
639 
640   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
641     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
642     ViewOpts.Debug = DebugDump;
643 
644     if (!CovFilename.empty())
645       ObjectFilenames.emplace_back(CovFilename);
646     for (const std::string &Filename : CovFilenames)
647       ObjectFilenames.emplace_back(Filename);
648     if (ObjectFilenames.empty()) {
649       errs() << "No filenames specified!\n";
650       ::exit(1);
651     }
652 
653     ViewOpts.Format = Format;
654     switch (ViewOpts.Format) {
655     case CoverageViewOptions::OutputFormat::Text:
656       ViewOpts.Colors = UseColor == cl::BOU_UNSET
657                             ? sys::Process::StandardOutHasColors()
658                             : UseColor == cl::BOU_TRUE;
659       break;
660     case CoverageViewOptions::OutputFormat::HTML:
661       if (UseColor == cl::BOU_FALSE)
662         errs() << "Color output cannot be disabled when generating html.\n";
663       ViewOpts.Colors = true;
664       break;
665     }
666 
667     // If path-equivalence was given and is a comma seperated pair then set
668     // PathRemapping.
669     auto EquivPair = StringRef(PathRemap).split(',');
670     if (!(EquivPair.first.empty() && EquivPair.second.empty()))
671       PathRemapping = EquivPair;
672 
673     // If a demangler is supplied, check if it exists and register it.
674     if (DemanglerOpts.size()) {
675       auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
676       if (!DemanglerPathOrErr) {
677         error("Could not find the demangler!",
678               DemanglerPathOrErr.getError().message());
679         return 1;
680       }
681       DemanglerOpts[0] = *DemanglerPathOrErr;
682       ViewOpts.DemanglerOpts.swap(DemanglerOpts);
683     }
684 
685     // Read in -name-whitelist files.
686     if (!NameFilterFiles.empty()) {
687       std::string SpecialCaseListErr;
688       NameWhitelist =
689           SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr);
690       if (!NameWhitelist)
691         error(SpecialCaseListErr);
692     }
693 
694     // Create the function filters
695     if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) {
696       auto NameFilterer = llvm::make_unique<CoverageFilters>();
697       for (const auto &Name : NameFilters)
698         NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
699       if (NameWhitelist)
700         NameFilterer->push_back(
701             llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));
702       for (const auto &Regex : NameRegexFilters)
703         NameFilterer->push_back(
704             llvm::make_unique<NameRegexCoverageFilter>(Regex));
705       Filters.push_back(std::move(NameFilterer));
706     }
707     if (RegionCoverageLtFilter.getNumOccurrences() ||
708         RegionCoverageGtFilter.getNumOccurrences() ||
709         LineCoverageLtFilter.getNumOccurrences() ||
710         LineCoverageGtFilter.getNumOccurrences()) {
711       auto StatFilterer = llvm::make_unique<CoverageFilters>();
712       if (RegionCoverageLtFilter.getNumOccurrences())
713         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
714             RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
715       if (RegionCoverageGtFilter.getNumOccurrences())
716         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
717             RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
718       if (LineCoverageLtFilter.getNumOccurrences())
719         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
720             LineCoverageFilter::LessThan, LineCoverageLtFilter));
721       if (LineCoverageGtFilter.getNumOccurrences())
722         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
723             RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
724       Filters.push_back(std::move(StatFilterer));
725     }
726 
727     if (!Arches.empty()) {
728       for (const std::string &Arch : Arches) {
729         if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
730           error("Unknown architecture: " + Arch);
731           return 1;
732         }
733         CoverageArches.emplace_back(Arch);
734       }
735       if (CoverageArches.size() != ObjectFilenames.size()) {
736         error("Number of architectures doesn't match the number of objects");
737         return 1;
738       }
739     }
740 
741     for (const std::string &File : InputSourceFiles)
742       collectPaths(File);
743 
744     if (DebugDumpCollectedPaths) {
745       for (const std::string &SF : SourceFiles)
746         outs() << SF << '\n';
747       ::exit(0);
748     }
749 
750     ViewOpts.ShowRegionSummary = RegionSummary;
751     ViewOpts.ShowInstantiationSummary = InstantiationSummary;
752     ViewOpts.ExportSummaryOnly = SummaryOnly;
753 
754     return 0;
755   };
756 
757   switch (Cmd) {
758   case Show:
759     return doShow(argc, argv, commandLineParser);
760   case Report:
761     return doReport(argc, argv, commandLineParser);
762   case Export:
763     return doExport(argc, argv, commandLineParser);
764   }
765   return 0;
766 }
767 
768 int CodeCoverageTool::doShow(int argc, const char **argv,
769                              CommandLineParserType commandLineParser) {
770 
771   cl::OptionCategory ViewCategory("Viewing options");
772 
773   cl::opt<bool> ShowLineExecutionCounts(
774       "show-line-counts", cl::Optional,
775       cl::desc("Show the execution counts for each line"), cl::init(true),
776       cl::cat(ViewCategory));
777 
778   cl::opt<bool> ShowRegions(
779       "show-regions", cl::Optional,
780       cl::desc("Show the execution counts for each region"),
781       cl::cat(ViewCategory));
782 
783   cl::opt<bool> ShowBestLineRegionsCounts(
784       "show-line-counts-or-regions", cl::Optional,
785       cl::desc("Show the execution counts for each line, or the execution "
786                "counts for each region on lines that have multiple regions"),
787       cl::cat(ViewCategory));
788 
789   cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
790                                cl::desc("Show expanded source regions"),
791                                cl::cat(ViewCategory));
792 
793   cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
794                                    cl::desc("Show function instantiations"),
795                                    cl::init(true), cl::cat(ViewCategory));
796 
797   cl::opt<std::string> ShowOutputDirectory(
798       "output-dir", cl::init(""),
799       cl::desc("Directory in which coverage information is written out"));
800   cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
801                                  cl::aliasopt(ShowOutputDirectory));
802 
803   cl::opt<uint32_t> TabSize(
804       "tab-size", cl::init(2),
805       cl::desc(
806           "Set tab expansion size for html coverage reports (default = 2)"));
807 
808   cl::opt<std::string> ProjectTitle(
809       "project-title", cl::Optional,
810       cl::desc("Set project title for the coverage report"));
811 
812   cl::opt<unsigned> NumThreads(
813       "num-threads", cl::init(0),
814       cl::desc("Number of merge threads to use (default: autodetect)"));
815   cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
816                         cl::aliasopt(NumThreads));
817 
818   auto Err = commandLineParser(argc, argv);
819   if (Err)
820     return Err;
821 
822   ViewOpts.ShowLineNumbers = true;
823   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
824                            !ShowRegions || ShowBestLineRegionsCounts;
825   ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
826   ViewOpts.ShowExpandedRegions = ShowExpansions;
827   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
828   ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
829   ViewOpts.TabSize = TabSize;
830   ViewOpts.ProjectTitle = ProjectTitle;
831 
832   if (ViewOpts.hasOutputDirectory()) {
833     if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
834       error("Could not create output directory!", E.message());
835       return 1;
836     }
837   }
838 
839   sys::fs::file_status Status;
840   if (sys::fs::status(PGOFilename, Status)) {
841     error("profdata file error: can not get the file status. \n");
842     return 1;
843   }
844 
845   auto ModifiedTime = Status.getLastModificationTime();
846   std::string ModifiedTimeStr = to_string(ModifiedTime);
847   size_t found = ModifiedTimeStr.rfind(':');
848   ViewOpts.CreatedTimeStr = (found != std::string::npos)
849                                 ? "Created: " + ModifiedTimeStr.substr(0, found)
850                                 : "Created: " + ModifiedTimeStr;
851 
852   auto Coverage = load();
853   if (!Coverage)
854     return 1;
855 
856   auto Printer = CoveragePrinter::create(ViewOpts);
857 
858   if (SourceFiles.empty())
859     // Get the source files from the function coverage mapping.
860     for (StringRef Filename : Coverage->getUniqueSourceFiles())
861       SourceFiles.push_back(Filename);
862 
863   // Create an index out of the source files.
864   if (ViewOpts.hasOutputDirectory()) {
865     if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
866       error("Could not create index file!", toString(std::move(E)));
867       return 1;
868     }
869   }
870 
871   if (!Filters.empty()) {
872     // Build the map of filenames to functions.
873     std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
874         FilenameFunctionMap;
875     for (const auto &SourceFile : SourceFiles)
876       for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
877         if (Filters.matches(*Coverage.get(), Function))
878           FilenameFunctionMap[SourceFile].push_back(&Function);
879 
880     // Only print filter matching functions for each file.
881     for (const auto &FileFunc : FilenameFunctionMap) {
882       StringRef File = FileFunc.first;
883       const auto &Functions = FileFunc.second;
884 
885       auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
886       if (Error E = OSOrErr.takeError()) {
887         error("Could not create view file!", toString(std::move(E)));
888         return 1;
889       }
890       auto OS = std::move(OSOrErr.get());
891 
892       bool ShowTitle = ViewOpts.hasOutputDirectory();
893       for (const auto *Function : Functions) {
894         auto FunctionView = createFunctionView(*Function, *Coverage);
895         if (!FunctionView) {
896           warning("Could not read coverage for '" + Function->Name + "'.");
897           continue;
898         }
899         FunctionView->print(*OS.get(), /*WholeFile=*/false,
900                             /*ShowSourceName=*/true, ShowTitle);
901         ShowTitle = false;
902       }
903 
904       Printer->closeViewFile(std::move(OS));
905     }
906     return 0;
907   }
908 
909   // Show files
910   bool ShowFilenames =
911       (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
912       (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
913 
914   // If NumThreads is not specified, auto-detect a good default.
915   if (NumThreads == 0)
916     NumThreads =
917         std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
918                               unsigned(SourceFiles.size())));
919 
920   if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) {
921     for (const std::string &SourceFile : SourceFiles)
922       writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
923                           ShowFilenames);
924   } else {
925     // In -output-dir mode, it's safe to use multiple threads to print files.
926     ThreadPool Pool(NumThreads);
927     for (const std::string &SourceFile : SourceFiles)
928       Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
929                  Coverage.get(), Printer.get(), ShowFilenames);
930     Pool.wait();
931   }
932 
933   return 0;
934 }
935 
936 int CodeCoverageTool::doReport(int argc, const char **argv,
937                                CommandLineParserType commandLineParser) {
938   cl::opt<bool> ShowFunctionSummaries(
939       "show-functions", cl::Optional, cl::init(false),
940       cl::desc("Show coverage summaries for each function"));
941 
942   auto Err = commandLineParser(argc, argv);
943   if (Err)
944     return Err;
945 
946   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
947     error("HTML output for summary reports is not yet supported.");
948     return 1;
949   }
950 
951   auto Coverage = load();
952   if (!Coverage)
953     return 1;
954 
955   CoverageReport Report(ViewOpts, *Coverage.get());
956   if (!ShowFunctionSummaries) {
957     if (SourceFiles.empty())
958       Report.renderFileReports(llvm::outs());
959     else
960       Report.renderFileReports(llvm::outs(), SourceFiles);
961   } else {
962     if (SourceFiles.empty()) {
963       error("Source files must be specified when -show-functions=true is "
964             "specified");
965       return 1;
966     }
967 
968     Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
969   }
970   return 0;
971 }
972 
973 int CodeCoverageTool::doExport(int argc, const char **argv,
974                                CommandLineParserType commandLineParser) {
975 
976   auto Err = commandLineParser(argc, argv);
977   if (Err)
978     return Err;
979 
980   if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
981     error("Coverage data can only be exported as textual JSON.");
982     return 1;
983   }
984 
985   auto Coverage = load();
986   if (!Coverage) {
987     error("Could not load coverage information");
988     return 1;
989   }
990 
991   auto Exporter = CoverageExporterJson(*Coverage.get(), ViewOpts, outs());
992 
993   if (SourceFiles.empty())
994     Exporter.renderRoot();
995   else
996     Exporter.renderRoot(SourceFiles);
997 
998   return 0;
999 }
1000 
1001 int showMain(int argc, const char *argv[]) {
1002   CodeCoverageTool Tool;
1003   return Tool.run(CodeCoverageTool::Show, argc, argv);
1004 }
1005 
1006 int reportMain(int argc, const char *argv[]) {
1007   CodeCoverageTool Tool;
1008   return Tool.run(CodeCoverageTool::Report, argc, argv);
1009 }
1010 
1011 int exportMain(int argc, const char *argv[]) {
1012   CodeCoverageTool Tool;
1013   return Tool.run(CodeCoverageTool::Export, argc, argv);
1014 }
1015