Coverage Report

Created: 2017-09-21 03:39

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