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/ThreadPool.h"
37 #include "llvm/Support/Threading.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   cl::opt<unsigned> NumThreads(
641       "num-threads", cl::init(0),
642       cl::desc("Number of merge threads to use (default: autodetect)"));
643   cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
644                         cl::aliasopt(NumThreads));
645 
646   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
647     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
648     ViewOpts.Debug = DebugDump;
649 
650     if (!CovFilename.empty())
651       ObjectFilenames.emplace_back(CovFilename);
652     for (const std::string &Filename : CovFilenames)
653       ObjectFilenames.emplace_back(Filename);
654     if (ObjectFilenames.empty()) {
655       errs() << "No filenames specified!\n";
656       ::exit(1);
657     }
658 
659     ViewOpts.Format = Format;
660     switch (ViewOpts.Format) {
661     case CoverageViewOptions::OutputFormat::Text:
662       ViewOpts.Colors = UseColor == cl::BOU_UNSET
663                             ? sys::Process::StandardOutHasColors()
664                             : UseColor == cl::BOU_TRUE;
665       break;
666     case CoverageViewOptions::OutputFormat::HTML:
667       if (UseColor == cl::BOU_FALSE)
668         errs() << "Color output cannot be disabled when generating html.\n";
669       ViewOpts.Colors = true;
670       break;
671     }
672 
673     // If path-equivalence was given and is a comma seperated pair then set
674     // PathRemapping.
675     auto EquivPair = StringRef(PathRemap).split(',');
676     if (!(EquivPair.first.empty() && EquivPair.second.empty()))
677       PathRemapping = EquivPair;
678 
679     // If a demangler is supplied, check if it exists and register it.
680     if (DemanglerOpts.size()) {
681       auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
682       if (!DemanglerPathOrErr) {
683         error("Could not find the demangler!",
684               DemanglerPathOrErr.getError().message());
685         return 1;
686       }
687       DemanglerOpts[0] = *DemanglerPathOrErr;
688       ViewOpts.DemanglerOpts.swap(DemanglerOpts);
689     }
690 
691     // Read in -name-whitelist files.
692     if (!NameFilterFiles.empty()) {
693       std::string SpecialCaseListErr;
694       NameWhitelist =
695           SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr);
696       if (!NameWhitelist)
697         error(SpecialCaseListErr);
698     }
699 
700     // Create the function filters
701     if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) {
702       auto NameFilterer = llvm::make_unique<CoverageFilters>();
703       for (const auto &Name : NameFilters)
704         NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
705       if (NameWhitelist)
706         NameFilterer->push_back(
707             llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));
708       for (const auto &Regex : NameRegexFilters)
709         NameFilterer->push_back(
710             llvm::make_unique<NameRegexCoverageFilter>(Regex));
711       Filters.push_back(std::move(NameFilterer));
712     }
713     if (RegionCoverageLtFilter.getNumOccurrences() ||
714         RegionCoverageGtFilter.getNumOccurrences() ||
715         LineCoverageLtFilter.getNumOccurrences() ||
716         LineCoverageGtFilter.getNumOccurrences()) {
717       auto StatFilterer = llvm::make_unique<CoverageFilters>();
718       if (RegionCoverageLtFilter.getNumOccurrences())
719         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
720             RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
721       if (RegionCoverageGtFilter.getNumOccurrences())
722         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
723             RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
724       if (LineCoverageLtFilter.getNumOccurrences())
725         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
726             LineCoverageFilter::LessThan, LineCoverageLtFilter));
727       if (LineCoverageGtFilter.getNumOccurrences())
728         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
729             RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
730       Filters.push_back(std::move(StatFilterer));
731     }
732 
733     if (!Arches.empty()) {
734       for (const std::string &Arch : Arches) {
735         if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
736           error("Unknown architecture: " + Arch);
737           return 1;
738         }
739         CoverageArches.emplace_back(Arch);
740       }
741       if (CoverageArches.size() != ObjectFilenames.size()) {
742         error("Number of architectures doesn't match the number of objects");
743         return 1;
744       }
745     }
746 
747     for (const std::string &File : InputSourceFiles)
748       collectPaths(File);
749 
750     if (DebugDumpCollectedPaths) {
751       for (const std::string &SF : SourceFiles)
752         outs() << SF << '\n';
753       ::exit(0);
754     }
755 
756     ViewOpts.ShowRegionSummary = RegionSummary;
757     ViewOpts.ShowInstantiationSummary = InstantiationSummary;
758     ViewOpts.ExportSummaryOnly = SummaryOnly;
759     ViewOpts.NumThreads = NumThreads;
760 
761     return 0;
762   };
763 
764   switch (Cmd) {
765   case Show:
766     return doShow(argc, argv, commandLineParser);
767   case Report:
768     return doReport(argc, argv, commandLineParser);
769   case Export:
770     return doExport(argc, argv, commandLineParser);
771   }
772   return 0;
773 }
774 
775 int CodeCoverageTool::doShow(int argc, const char **argv,
776                              CommandLineParserType commandLineParser) {
777 
778   cl::OptionCategory ViewCategory("Viewing options");
779 
780   cl::opt<bool> ShowLineExecutionCounts(
781       "show-line-counts", cl::Optional,
782       cl::desc("Show the execution counts for each line"), cl::init(true),
783       cl::cat(ViewCategory));
784 
785   cl::opt<bool> ShowRegions(
786       "show-regions", cl::Optional,
787       cl::desc("Show the execution counts for each region"),
788       cl::cat(ViewCategory));
789 
790   cl::opt<bool> ShowBestLineRegionsCounts(
791       "show-line-counts-or-regions", cl::Optional,
792       cl::desc("Show the execution counts for each line, or the execution "
793                "counts for each region on lines that have multiple regions"),
794       cl::cat(ViewCategory));
795 
796   cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
797                                cl::desc("Show expanded source regions"),
798                                cl::cat(ViewCategory));
799 
800   cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
801                                    cl::desc("Show function instantiations"),
802                                    cl::init(true), cl::cat(ViewCategory));
803 
804   cl::opt<std::string> ShowOutputDirectory(
805       "output-dir", cl::init(""),
806       cl::desc("Directory in which coverage information is written out"));
807   cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
808                                  cl::aliasopt(ShowOutputDirectory));
809 
810   cl::opt<uint32_t> TabSize(
811       "tab-size", cl::init(2),
812       cl::desc(
813           "Set tab expansion size for html coverage reports (default = 2)"));
814 
815   cl::opt<std::string> ProjectTitle(
816       "project-title", cl::Optional,
817       cl::desc("Set project title for the coverage report"));
818 
819   auto Err = commandLineParser(argc, argv);
820   if (Err)
821     return Err;
822 
823   ViewOpts.ShowLineNumbers = true;
824   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
825                            !ShowRegions || ShowBestLineRegionsCounts;
826   ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
827   ViewOpts.ShowExpandedRegions = ShowExpansions;
828   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
829   ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
830   ViewOpts.TabSize = TabSize;
831   ViewOpts.ProjectTitle = ProjectTitle;
832 
833   if (ViewOpts.hasOutputDirectory()) {
834     if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
835       error("Could not create output directory!", E.message());
836       return 1;
837     }
838   }
839 
840   sys::fs::file_status Status;
841   if (sys::fs::status(PGOFilename, Status)) {
842     error("profdata file error: can not get the file status. \n");
843     return 1;
844   }
845 
846   auto ModifiedTime = Status.getLastModificationTime();
847   std::string ModifiedTimeStr = to_string(ModifiedTime);
848   size_t found = ModifiedTimeStr.rfind(':');
849   ViewOpts.CreatedTimeStr = (found != std::string::npos)
850                                 ? "Created: " + ModifiedTimeStr.substr(0, found)
851                                 : "Created: " + ModifiedTimeStr;
852 
853   auto Coverage = load();
854   if (!Coverage)
855     return 1;
856 
857   auto Printer = CoveragePrinter::create(ViewOpts);
858 
859   if (SourceFiles.empty())
860     // Get the source files from the function coverage mapping.
861     for (StringRef Filename : Coverage->getUniqueSourceFiles())
862       SourceFiles.push_back(Filename);
863 
864   // Create an index out of the source files.
865   if (ViewOpts.hasOutputDirectory()) {
866     if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
867       error("Could not create index file!", toString(std::move(E)));
868       return 1;
869     }
870   }
871 
872   if (!Filters.empty()) {
873     // Build the map of filenames to functions.
874     std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
875         FilenameFunctionMap;
876     for (const auto &SourceFile : SourceFiles)
877       for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
878         if (Filters.matches(*Coverage.get(), Function))
879           FilenameFunctionMap[SourceFile].push_back(&Function);
880 
881     // Only print filter matching functions for each file.
882     for (const auto &FileFunc : FilenameFunctionMap) {
883       StringRef File = FileFunc.first;
884       const auto &Functions = FileFunc.second;
885 
886       auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
887       if (Error E = OSOrErr.takeError()) {
888         error("Could not create view file!", toString(std::move(E)));
889         return 1;
890       }
891       auto OS = std::move(OSOrErr.get());
892 
893       bool ShowTitle = ViewOpts.hasOutputDirectory();
894       for (const auto *Function : Functions) {
895         auto FunctionView = createFunctionView(*Function, *Coverage);
896         if (!FunctionView) {
897           warning("Could not read coverage for '" + Function->Name + "'.");
898           continue;
899         }
900         FunctionView->print(*OS.get(), /*WholeFile=*/false,
901                             /*ShowSourceName=*/true, ShowTitle);
902         ShowTitle = false;
903       }
904 
905       Printer->closeViewFile(std::move(OS));
906     }
907     return 0;
908   }
909 
910   // Show files
911   bool ShowFilenames =
912       (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
913       (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
914 
915   auto NumThreads = ViewOpts.NumThreads;
916 
917   // If NumThreads is not specified, auto-detect a good default.
918   if (NumThreads == 0)
919     NumThreads =
920         std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
921                               unsigned(SourceFiles.size())));
922 
923   if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) {
924     for (const std::string &SourceFile : SourceFiles)
925       writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
926                           ShowFilenames);
927   } else {
928     // In -output-dir mode, it's safe to use multiple threads to print files.
929     ThreadPool Pool(NumThreads);
930     for (const std::string &SourceFile : SourceFiles)
931       Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
932                  Coverage.get(), Printer.get(), ShowFilenames);
933     Pool.wait();
934   }
935 
936   return 0;
937 }
938 
939 int CodeCoverageTool::doReport(int argc, const char **argv,
940                                CommandLineParserType commandLineParser) {
941   cl::opt<bool> ShowFunctionSummaries(
942       "show-functions", cl::Optional, cl::init(false),
943       cl::desc("Show coverage summaries for each function"));
944 
945   auto Err = commandLineParser(argc, argv);
946   if (Err)
947     return Err;
948 
949   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
950     error("HTML output for summary reports is not yet supported.");
951     return 1;
952   }
953 
954   auto Coverage = load();
955   if (!Coverage)
956     return 1;
957 
958   CoverageReport Report(ViewOpts, *Coverage.get());
959   if (!ShowFunctionSummaries) {
960     if (SourceFiles.empty())
961       Report.renderFileReports(llvm::outs());
962     else
963       Report.renderFileReports(llvm::outs(), SourceFiles);
964   } else {
965     if (SourceFiles.empty()) {
966       error("Source files must be specified when -show-functions=true is "
967             "specified");
968       return 1;
969     }
970 
971     Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
972   }
973   return 0;
974 }
975 
976 int CodeCoverageTool::doExport(int argc, const char **argv,
977                                CommandLineParserType commandLineParser) {
978 
979   auto Err = commandLineParser(argc, argv);
980   if (Err)
981     return Err;
982 
983   if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
984     error("Coverage data can only be exported as textual JSON.");
985     return 1;
986   }
987 
988   auto Coverage = load();
989   if (!Coverage) {
990     error("Could not load coverage information");
991     return 1;
992   }
993 
994   auto Exporter = CoverageExporterJson(*Coverage.get(), ViewOpts, outs());
995 
996   if (SourceFiles.empty())
997     Exporter.renderRoot();
998   else
999     Exporter.renderRoot(SourceFiles);
1000 
1001   return 0;
1002 }
1003 
1004 int showMain(int argc, const char *argv[]) {
1005   CodeCoverageTool Tool;
1006   return Tool.run(CodeCoverageTool::Show, argc, argv);
1007 }
1008 
1009 int reportMain(int argc, const char *argv[]) {
1010   CodeCoverageTool Tool;
1011   return Tool.run(CodeCoverageTool::Report, argc, argv);
1012 }
1013 
1014 int exportMain(int argc, const char *argv[]) {
1015   CodeCoverageTool Tool;
1016   return Tool.run(CodeCoverageTool::Export, argc, argv);
1017 }
1018