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