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       warning("Source file doesn't exist, proceeded by ignoring it.", 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; F.increment(EC)) {
215 
216       if (EC) {
217         warning(EC.message(), F->path());
218         continue;
219       }
220 
221       if (llvm::sys::fs::is_regular_file(F->path()))
222         addCollectedPath(F->path());
223     }
224   }
225 }
226 
227 ErrorOr<const MemoryBuffer &>
228 CodeCoverageTool::getSourceFile(StringRef SourceFile) {
229   // If we've remapped filenames, look up the real location for this file.
230   std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
231   if (!RemappedFilenames.empty()) {
232     auto Loc = RemappedFilenames.find(SourceFile);
233     if (Loc != RemappedFilenames.end())
234       SourceFile = Loc->second;
235   }
236   for (const auto &Files : LoadedSourceFiles)
237     if (sys::fs::equivalent(SourceFile, Files.first))
238       return *Files.second;
239   auto Buffer = MemoryBuffer::getFile(SourceFile);
240   if (auto EC = Buffer.getError()) {
241     error(EC.message(), SourceFile);
242     return EC;
243   }
244   LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
245   return *LoadedSourceFiles.back().second;
246 }
247 
248 void CodeCoverageTool::attachExpansionSubViews(
249     SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions,
250     const CoverageMapping &Coverage) {
251   if (!ViewOpts.ShowExpandedRegions)
252     return;
253   for (const auto &Expansion : Expansions) {
254     auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
255     if (ExpansionCoverage.empty())
256       continue;
257     auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
258     if (!SourceBuffer)
259       continue;
260 
261     auto SubViewExpansions = ExpansionCoverage.getExpansions();
262     auto SubView =
263         SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
264                                    ViewOpts, std::move(ExpansionCoverage));
265     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
266     View.addExpansion(Expansion.Region, std::move(SubView));
267   }
268 }
269 
270 std::unique_ptr<SourceCoverageView>
271 CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
272                                      const CoverageMapping &Coverage) {
273   auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
274   if (FunctionCoverage.empty())
275     return nullptr;
276   auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
277   if (!SourceBuffer)
278     return nullptr;
279 
280   auto Expansions = FunctionCoverage.getExpansions();
281   auto View = SourceCoverageView::create(DC.demangle(Function.Name),
282                                          SourceBuffer.get(), ViewOpts,
283                                          std::move(FunctionCoverage));
284   attachExpansionSubViews(*View, Expansions, Coverage);
285 
286   return View;
287 }
288 
289 std::unique_ptr<SourceCoverageView>
290 CodeCoverageTool::createSourceFileView(StringRef SourceFile,
291                                        const CoverageMapping &Coverage) {
292   auto SourceBuffer = getSourceFile(SourceFile);
293   if (!SourceBuffer)
294     return nullptr;
295   auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
296   if (FileCoverage.empty())
297     return nullptr;
298 
299   auto Expansions = FileCoverage.getExpansions();
300   auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
301                                          ViewOpts, std::move(FileCoverage));
302   attachExpansionSubViews(*View, Expansions, Coverage);
303   if (!ViewOpts.ShowFunctionInstantiations)
304     return View;
305 
306   for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
307     // Skip functions which have a single instantiation.
308     if (Group.size() < 2)
309       continue;
310 
311     for (const FunctionRecord *Function : Group.getInstantiations()) {
312       std::unique_ptr<SourceCoverageView> SubView{nullptr};
313 
314       StringRef Funcname = DC.demangle(Function->Name);
315 
316       if (Function->ExecutionCount > 0) {
317         auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
318         auto SubViewExpansions = SubViewCoverage.getExpansions();
319         SubView = SourceCoverageView::create(
320             Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
321         attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
322       }
323 
324       unsigned FileID = Function->CountedRegions.front().FileID;
325       unsigned Line = 0;
326       for (const auto &CR : Function->CountedRegions)
327         if (CR.FileID == FileID)
328           Line = std::max(CR.LineEnd, Line);
329       View->addInstantiation(Funcname, Line, std::move(SubView));
330     }
331   }
332   return View;
333 }
334 
335 static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
336   sys::fs::file_status Status;
337   if (sys::fs::status(LHS, Status))
338     return false;
339   auto LHSTime = Status.getLastModificationTime();
340   if (sys::fs::status(RHS, Status))
341     return false;
342   auto RHSTime = Status.getLastModificationTime();
343   return LHSTime > RHSTime;
344 }
345 
346 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
347   for (StringRef ObjectFilename : ObjectFilenames)
348     if (modifiedTimeGT(ObjectFilename, PGOFilename))
349       warning("profile data may be out of date - object is newer",
350               ObjectFilename);
351   auto CoverageOrErr =
352       CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches);
353   if (Error E = CoverageOrErr.takeError()) {
354     error("Failed to load coverage: " + toString(std::move(E)),
355           join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
356     return nullptr;
357   }
358   auto Coverage = std::move(CoverageOrErr.get());
359   unsigned Mismatched = Coverage->getMismatchedCount();
360   if (Mismatched) {
361     warning(Twine(Mismatched) + " functions have mismatched data");
362 
363     if (ViewOpts.Debug) {
364       for (const auto &HashMismatch : Coverage->getHashMismatches())
365         errs() << "hash-mismatch: "
366                << "No profile record found for '" << HashMismatch.first << "'"
367                << " with hash = 0x" << Twine::utohexstr(HashMismatch.second)
368                << '\n';
369 
370       for (const auto &CounterMismatch : Coverage->getCounterMismatches())
371         errs() << "counter-mismatch: "
372                << "Coverage mapping for " << CounterMismatch.first
373                << " only has " << CounterMismatch.second
374                << " valid counter expressions\n";
375     }
376   }
377 
378   remapPathNames(*Coverage);
379 
380   if (!SourceFiles.empty())
381     removeUnmappedInputs(*Coverage);
382 
383   demangleSymbols(*Coverage);
384 
385   return Coverage;
386 }
387 
388 void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
389   if (!PathRemapping)
390     return;
391 
392   // Convert remapping paths to native paths with trailing seperators.
393   auto nativeWithTrailing = [](StringRef Path) -> std::string {
394     if (Path.empty())
395       return "";
396     SmallString<128> NativePath;
397     sys::path::native(Path, NativePath);
398     if (!sys::path::is_separator(NativePath.back()))
399       NativePath += sys::path::get_separator();
400     return NativePath.c_str();
401   };
402   std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
403   std::string RemapTo = nativeWithTrailing(PathRemapping->second);
404 
405   // Create a mapping from coverage data file paths to local paths.
406   for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
407     SmallString<128> NativeFilename;
408     sys::path::native(Filename, NativeFilename);
409     if (NativeFilename.startswith(RemapFrom)) {
410       RemappedFilenames[Filename] =
411           RemapTo + NativeFilename.substr(RemapFrom.size()).str();
412     }
413   }
414 
415   // Convert input files from local paths to coverage data file paths.
416   StringMap<std::string> InvRemappedFilenames;
417   for (const auto &RemappedFilename : RemappedFilenames)
418     InvRemappedFilenames[RemappedFilename.getValue()] = 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<const char *> ArgsV;
480   for (const std::string &Arg : ViewOpts.DemanglerOpts)
481     ArgsV.push_back(Arg.c_str());
482   ArgsV.push_back(nullptr);
483   Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
484   std::string ErrMsg;
485   int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
486                                /*env=*/nullptr, Redirects, /*secondsToWait=*/0,
487                                /*memoryLimit=*/0, &ErrMsg);
488   if (RC) {
489     error(ErrMsg, ViewOpts.DemanglerOpts[0]);
490     return;
491   }
492 
493   // Parse the demangler's output.
494   auto BufOrError = MemoryBuffer::getFile(OutputPath);
495   if (!BufOrError) {
496     error(OutputPath, BufOrError.getError().message());
497     return;
498   }
499 
500   std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError);
501 
502   SmallVector<StringRef, 8> Symbols;
503   StringRef DemanglerData = DemanglerBuf->getBuffer();
504   DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
505                       /*KeepEmpty=*/false);
506   if (Symbols.size() != NumSymbols) {
507     error("Demangler did not provide expected number of symbols");
508     return;
509   }
510 
511   // Cache the demangled names.
512   unsigned I = 0;
513   for (const auto &Function : Coverage.getCoveredFunctions())
514     // On Windows, lines in the demangler's output file end with "\r\n".
515     // Splitting by '\n' keeps '\r's, so cut them now.
516     DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
517 }
518 
519 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
520                                            CoverageMapping *Coverage,
521                                            CoveragePrinter *Printer,
522                                            bool ShowFilenames) {
523   auto View = createSourceFileView(SourceFile, *Coverage);
524   if (!View) {
525     warning("The file '" + SourceFile + "' isn't covered.");
526     return;
527   }
528 
529   auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
530   if (Error E = OSOrErr.takeError()) {
531     error("Could not create view file!", toString(std::move(E)));
532     return;
533   }
534   auto OS = std::move(OSOrErr.get());
535 
536   View->print(*OS.get(), /*Wholefile=*/true,
537               /*ShowSourceName=*/ShowFilenames,
538               /*ShowTitle=*/ViewOpts.hasOutputDirectory());
539   Printer->closeViewFile(std::move(OS));
540 }
541 
542 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
543   cl::opt<std::string> CovFilename(
544       cl::Positional, cl::desc("Covered executable or object file."));
545 
546   cl::list<std::string> CovFilenames(
547       "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore,
548       cl::CommaSeparated);
549 
550   cl::list<std::string> InputSourceFiles(
551       cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
552 
553   cl::opt<bool> DebugDumpCollectedPaths(
554       "dump-collected-paths", cl::Optional, cl::Hidden,
555       cl::desc("Show the collected paths to source files"));
556 
557   cl::opt<std::string, true> PGOFilename(
558       "instr-profile", cl::Required, cl::location(this->PGOFilename),
559       cl::desc(
560           "File with the profile data obtained after an instrumented run"));
561 
562   cl::list<std::string> Arches(
563       "arch", cl::desc("architectures of the coverage mapping binaries"));
564 
565   cl::opt<bool> DebugDump("dump", cl::Optional,
566                           cl::desc("Show internal debug dump"));
567 
568   cl::opt<CoverageViewOptions::OutputFormat> Format(
569       "format", cl::desc("Output format for line-based coverage reports"),
570       cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
571                             "Text output"),
572                  clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
573                             "HTML output")),
574       cl::init(CoverageViewOptions::OutputFormat::Text));
575 
576   cl::opt<std::string> PathRemap(
577       "path-equivalence", cl::Optional,
578       cl::desc("<from>,<to> Map coverage data paths to local source file "
579                "paths"));
580 
581   cl::OptionCategory FilteringCategory("Function filtering options");
582 
583   cl::list<std::string> NameFilters(
584       "name", cl::Optional,
585       cl::desc("Show code coverage only for functions with the given name"),
586       cl::ZeroOrMore, cl::cat(FilteringCategory));
587 
588   cl::list<std::string> NameFilterFiles(
589       "name-whitelist", cl::Optional,
590       cl::desc("Show code coverage only for functions listed in the given "
591                "file"),
592       cl::ZeroOrMore, cl::cat(FilteringCategory));
593 
594   cl::list<std::string> NameRegexFilters(
595       "name-regex", cl::Optional,
596       cl::desc("Show code coverage only for functions that match the given "
597                "regular expression"),
598       cl::ZeroOrMore, cl::cat(FilteringCategory));
599 
600   cl::opt<double> RegionCoverageLtFilter(
601       "region-coverage-lt", cl::Optional,
602       cl::desc("Show code coverage only for functions with region coverage "
603                "less than the given threshold"),
604       cl::cat(FilteringCategory));
605 
606   cl::opt<double> RegionCoverageGtFilter(
607       "region-coverage-gt", cl::Optional,
608       cl::desc("Show code coverage only for functions with region coverage "
609                "greater than the given threshold"),
610       cl::cat(FilteringCategory));
611 
612   cl::opt<double> LineCoverageLtFilter(
613       "line-coverage-lt", cl::Optional,
614       cl::desc("Show code coverage only for functions with line coverage less "
615                "than the given threshold"),
616       cl::cat(FilteringCategory));
617 
618   cl::opt<double> LineCoverageGtFilter(
619       "line-coverage-gt", cl::Optional,
620       cl::desc("Show code coverage only for functions with line coverage "
621                "greater than the given threshold"),
622       cl::cat(FilteringCategory));
623 
624   cl::opt<cl::boolOrDefault> UseColor(
625       "use-color", cl::desc("Emit colored output (default=autodetect)"),
626       cl::init(cl::BOU_UNSET));
627 
628   cl::list<std::string> DemanglerOpts(
629       "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
630 
631   cl::opt<bool> RegionSummary(
632       "show-region-summary", cl::Optional,
633       cl::desc("Show region statistics in summary table"),
634       cl::init(true));
635 
636   cl::opt<bool> InstantiationSummary(
637       "show-instantiation-summary", cl::Optional,
638       cl::desc("Show instantiation statistics in summary table"));
639 
640   cl::opt<bool> SummaryOnly(
641       "summary-only", cl::Optional,
642       cl::desc("Export only summary information for each source file"));
643 
644   cl::opt<unsigned> NumThreads(
645       "num-threads", cl::init(0),
646       cl::desc("Number of merge threads to use (default: autodetect)"));
647   cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
648                         cl::aliasopt(NumThreads));
649 
650   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
651     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
652     ViewOpts.Debug = DebugDump;
653 
654     if (!CovFilename.empty())
655       ObjectFilenames.emplace_back(CovFilename);
656     for (const std::string &Filename : CovFilenames)
657       ObjectFilenames.emplace_back(Filename);
658     if (ObjectFilenames.empty()) {
659       errs() << "No filenames specified!\n";
660       ::exit(1);
661     }
662 
663     ViewOpts.Format = Format;
664     switch (ViewOpts.Format) {
665     case CoverageViewOptions::OutputFormat::Text:
666       ViewOpts.Colors = UseColor == cl::BOU_UNSET
667                             ? sys::Process::StandardOutHasColors()
668                             : UseColor == cl::BOU_TRUE;
669       break;
670     case CoverageViewOptions::OutputFormat::HTML:
671       if (UseColor == cl::BOU_FALSE)
672         errs() << "Color output cannot be disabled when generating html.\n";
673       ViewOpts.Colors = true;
674       break;
675     }
676 
677     // If path-equivalence was given and is a comma seperated pair then set
678     // PathRemapping.
679     auto EquivPair = StringRef(PathRemap).split(',');
680     if (!(EquivPair.first.empty() && EquivPair.second.empty()))
681       PathRemapping = EquivPair;
682 
683     // If a demangler is supplied, check if it exists and register it.
684     if (DemanglerOpts.size()) {
685       auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
686       if (!DemanglerPathOrErr) {
687         error("Could not find the demangler!",
688               DemanglerPathOrErr.getError().message());
689         return 1;
690       }
691       DemanglerOpts[0] = *DemanglerPathOrErr;
692       ViewOpts.DemanglerOpts.swap(DemanglerOpts);
693     }
694 
695     // Read in -name-whitelist files.
696     if (!NameFilterFiles.empty()) {
697       std::string SpecialCaseListErr;
698       NameWhitelist =
699           SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr);
700       if (!NameWhitelist)
701         error(SpecialCaseListErr);
702     }
703 
704     // Create the function filters
705     if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) {
706       auto NameFilterer = llvm::make_unique<CoverageFilters>();
707       for (const auto &Name : NameFilters)
708         NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
709       if (NameWhitelist)
710         NameFilterer->push_back(
711             llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));
712       for (const auto &Regex : NameRegexFilters)
713         NameFilterer->push_back(
714             llvm::make_unique<NameRegexCoverageFilter>(Regex));
715       Filters.push_back(std::move(NameFilterer));
716     }
717     if (RegionCoverageLtFilter.getNumOccurrences() ||
718         RegionCoverageGtFilter.getNumOccurrences() ||
719         LineCoverageLtFilter.getNumOccurrences() ||
720         LineCoverageGtFilter.getNumOccurrences()) {
721       auto StatFilterer = llvm::make_unique<CoverageFilters>();
722       if (RegionCoverageLtFilter.getNumOccurrences())
723         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
724             RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
725       if (RegionCoverageGtFilter.getNumOccurrences())
726         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
727             RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
728       if (LineCoverageLtFilter.getNumOccurrences())
729         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
730             LineCoverageFilter::LessThan, LineCoverageLtFilter));
731       if (LineCoverageGtFilter.getNumOccurrences())
732         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
733             RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
734       Filters.push_back(std::move(StatFilterer));
735     }
736 
737     if (!Arches.empty()) {
738       for (const std::string &Arch : Arches) {
739         if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
740           error("Unknown architecture: " + Arch);
741           return 1;
742         }
743         CoverageArches.emplace_back(Arch);
744       }
745       if (CoverageArches.size() != ObjectFilenames.size()) {
746         error("Number of architectures doesn't match the number of objects");
747         return 1;
748       }
749     }
750 
751     for (const std::string &File : InputSourceFiles)
752       collectPaths(File);
753 
754     if (DebugDumpCollectedPaths) {
755       for (const std::string &SF : SourceFiles)
756         outs() << SF << '\n';
757       ::exit(0);
758     }
759 
760     ViewOpts.ShowRegionSummary = RegionSummary;
761     ViewOpts.ShowInstantiationSummary = InstantiationSummary;
762     ViewOpts.ExportSummaryOnly = SummaryOnly;
763     ViewOpts.NumThreads = NumThreads;
764 
765     return 0;
766   };
767 
768   switch (Cmd) {
769   case Show:
770     return doShow(argc, argv, commandLineParser);
771   case Report:
772     return doReport(argc, argv, commandLineParser);
773   case Export:
774     return doExport(argc, argv, commandLineParser);
775   }
776   return 0;
777 }
778 
779 int CodeCoverageTool::doShow(int argc, const char **argv,
780                              CommandLineParserType commandLineParser) {
781 
782   cl::OptionCategory ViewCategory("Viewing options");
783 
784   cl::opt<bool> ShowLineExecutionCounts(
785       "show-line-counts", cl::Optional,
786       cl::desc("Show the execution counts for each line"), cl::init(true),
787       cl::cat(ViewCategory));
788 
789   cl::opt<bool> ShowRegions(
790       "show-regions", cl::Optional,
791       cl::desc("Show the execution counts for each region"),
792       cl::cat(ViewCategory));
793 
794   cl::opt<bool> ShowBestLineRegionsCounts(
795       "show-line-counts-or-regions", cl::Optional,
796       cl::desc("Show the execution counts for each line, or the execution "
797                "counts for each region on lines that have multiple regions"),
798       cl::cat(ViewCategory));
799 
800   cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
801                                cl::desc("Show expanded source regions"),
802                                cl::cat(ViewCategory));
803 
804   cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
805                                    cl::desc("Show function instantiations"),
806                                    cl::init(true), cl::cat(ViewCategory));
807 
808   cl::opt<std::string> ShowOutputDirectory(
809       "output-dir", cl::init(""),
810       cl::desc("Directory in which coverage information is written out"));
811   cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
812                                  cl::aliasopt(ShowOutputDirectory));
813 
814   cl::opt<uint32_t> TabSize(
815       "tab-size", cl::init(2),
816       cl::desc(
817           "Set tab expansion size for html coverage reports (default = 2)"));
818 
819   cl::opt<std::string> ProjectTitle(
820       "project-title", cl::Optional,
821       cl::desc("Set project title for the coverage report"));
822 
823   auto Err = commandLineParser(argc, argv);
824   if (Err)
825     return Err;
826 
827   ViewOpts.ShowLineNumbers = true;
828   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
829                            !ShowRegions || ShowBestLineRegionsCounts;
830   ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
831   ViewOpts.ShowExpandedRegions = ShowExpansions;
832   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
833   ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
834   ViewOpts.TabSize = TabSize;
835   ViewOpts.ProjectTitle = ProjectTitle;
836 
837   if (ViewOpts.hasOutputDirectory()) {
838     if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
839       error("Could not create output directory!", E.message());
840       return 1;
841     }
842   }
843 
844   sys::fs::file_status Status;
845   if (sys::fs::status(PGOFilename, Status)) {
846     error("profdata file error: can not get the file status. \n");
847     return 1;
848   }
849 
850   auto ModifiedTime = Status.getLastModificationTime();
851   std::string ModifiedTimeStr = to_string(ModifiedTime);
852   size_t found = ModifiedTimeStr.rfind(':');
853   ViewOpts.CreatedTimeStr = (found != std::string::npos)
854                                 ? "Created: " + ModifiedTimeStr.substr(0, found)
855                                 : "Created: " + ModifiedTimeStr;
856 
857   auto Coverage = load();
858   if (!Coverage)
859     return 1;
860 
861   auto Printer = CoveragePrinter::create(ViewOpts);
862 
863   if (SourceFiles.empty())
864     // Get the source files from the function coverage mapping.
865     for (StringRef Filename : Coverage->getUniqueSourceFiles())
866       SourceFiles.push_back(Filename);
867 
868   // Create an index out of the source files.
869   if (ViewOpts.hasOutputDirectory()) {
870     if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
871       error("Could not create index file!", toString(std::move(E)));
872       return 1;
873     }
874   }
875 
876   if (!Filters.empty()) {
877     // Build the map of filenames to functions.
878     std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
879         FilenameFunctionMap;
880     for (const auto &SourceFile : SourceFiles)
881       for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
882         if (Filters.matches(*Coverage.get(), Function))
883           FilenameFunctionMap[SourceFile].push_back(&Function);
884 
885     // Only print filter matching functions for each file.
886     for (const auto &FileFunc : FilenameFunctionMap) {
887       StringRef File = FileFunc.first;
888       const auto &Functions = FileFunc.second;
889 
890       auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
891       if (Error E = OSOrErr.takeError()) {
892         error("Could not create view file!", toString(std::move(E)));
893         return 1;
894       }
895       auto OS = std::move(OSOrErr.get());
896 
897       bool ShowTitle = ViewOpts.hasOutputDirectory();
898       for (const auto *Function : Functions) {
899         auto FunctionView = createFunctionView(*Function, *Coverage);
900         if (!FunctionView) {
901           warning("Could not read coverage for '" + Function->Name + "'.");
902           continue;
903         }
904         FunctionView->print(*OS.get(), /*WholeFile=*/false,
905                             /*ShowSourceName=*/true, ShowTitle);
906         ShowTitle = false;
907       }
908 
909       Printer->closeViewFile(std::move(OS));
910     }
911     return 0;
912   }
913 
914   // Show files
915   bool ShowFilenames =
916       (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
917       (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
918 
919   auto NumThreads = ViewOpts.NumThreads;
920 
921   // If NumThreads is not specified, auto-detect a good default.
922   if (NumThreads == 0)
923     NumThreads =
924         std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
925                               unsigned(SourceFiles.size())));
926 
927   if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) {
928     for (const std::string &SourceFile : SourceFiles)
929       writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
930                           ShowFilenames);
931   } else {
932     // In -output-dir mode, it's safe to use multiple threads to print files.
933     ThreadPool Pool(NumThreads);
934     for (const std::string &SourceFile : SourceFiles)
935       Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
936                  Coverage.get(), Printer.get(), ShowFilenames);
937     Pool.wait();
938   }
939 
940   return 0;
941 }
942 
943 int CodeCoverageTool::doReport(int argc, const char **argv,
944                                CommandLineParserType commandLineParser) {
945   cl::opt<bool> ShowFunctionSummaries(
946       "show-functions", cl::Optional, cl::init(false),
947       cl::desc("Show coverage summaries for each function"));
948 
949   auto Err = commandLineParser(argc, argv);
950   if (Err)
951     return Err;
952 
953   if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
954     error("HTML output for summary reports is not yet supported.");
955     return 1;
956   }
957 
958   auto Coverage = load();
959   if (!Coverage)
960     return 1;
961 
962   CoverageReport Report(ViewOpts, *Coverage.get());
963   if (!ShowFunctionSummaries) {
964     if (SourceFiles.empty())
965       Report.renderFileReports(llvm::outs());
966     else
967       Report.renderFileReports(llvm::outs(), SourceFiles);
968   } else {
969     if (SourceFiles.empty()) {
970       error("Source files must be specified when -show-functions=true is "
971             "specified");
972       return 1;
973     }
974 
975     Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
976   }
977   return 0;
978 }
979 
980 int CodeCoverageTool::doExport(int argc, const char **argv,
981                                CommandLineParserType commandLineParser) {
982 
983   auto Err = commandLineParser(argc, argv);
984   if (Err)
985     return Err;
986 
987   if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
988     error("Coverage data can only be exported as textual JSON.");
989     return 1;
990   }
991 
992   auto Coverage = load();
993   if (!Coverage) {
994     error("Could not load coverage information");
995     return 1;
996   }
997 
998   auto Exporter = CoverageExporterJson(*Coverage.get(), ViewOpts, outs());
999 
1000   if (SourceFiles.empty())
1001     Exporter.renderRoot();
1002   else
1003     Exporter.renderRoot(SourceFiles);
1004 
1005   return 0;
1006 }
1007 
1008 int showMain(int argc, const char *argv[]) {
1009   CodeCoverageTool Tool;
1010   return Tool.run(CodeCoverageTool::Show, argc, argv);
1011 }
1012 
1013 int reportMain(int argc, const char *argv[]) {
1014   CodeCoverageTool Tool;
1015   return Tool.run(CodeCoverageTool::Report, argc, argv);
1016 }
1017 
1018 int exportMain(int argc, const char *argv[]) {
1019   CodeCoverageTool Tool;
1020   return Tool.run(CodeCoverageTool::Export, argc, argv);
1021 }
1022