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