[llvm] r275640 - [llvm-cov] Optionally use a symbol demangler when preparing reports

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 15 15:44:57 PDT 2016


Author: vedantk
Date: Fri Jul 15 17:44:57 2016
New Revision: 275640

URL: http://llvm.org/viewvc/llvm-project?rev=275640&view=rev
Log:
[llvm-cov] Optionally use a symbol demangler when preparing reports

Add an option to specify a symbol demangler (as well as options to the
demangler). This can be used to make reports more human-readable.

This option is especially useful in -output-dir mode, since it isn't as
easy to manually pipe reports into a demangler in this mode.

Added:
    llvm/trunk/test/tools/llvm-cov/demangle.test
Modified:
    llvm/trunk/docs/CommandGuide/llvm-cov.rst
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
    llvm/trunk/tools/llvm-cov/CoverageViewOptions.h

Modified: llvm/trunk/docs/CommandGuide/llvm-cov.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-cov.rst?rev=275640&r1=275639&r2=275640&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/llvm-cov.rst (original)
+++ llvm/trunk/docs/CommandGuide/llvm-cov.rst Fri Jul 15 17:44:57 2016
@@ -248,6 +248,14 @@ OPTIONS
  PATH/functions.EXTENSION. When used in file view mode, a report for each file
  is written to PATH/REL_PATH_TO_FILE.EXTENSION.
 
+.. option:: -Xdemangler=<TOOL>|<TOOL-OPTION>
+
+ Specify a symbol demangler. This can be used to make reports more
+ human-readable. This option can be specified multiple times to supply
+ arguments to the demangler (e.g `-Xdemangler c++filt -Xdemangler -n` for C++).
+ The demangler is expected to read a newline-separated list of symbols from
+ stdin and write a newline-separated list of the same length to stdout.
+
 .. option:: -line-coverage-gt=<N>
 
  Show code coverage only for functions with line coverage greater than the

Added: llvm/trunk/test/tools/llvm-cov/demangle.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/demangle.test?rev=275640&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-cov/demangle.test (added)
+++ llvm/trunk/test/tools/llvm-cov/demangle.test Fri Jul 15 17:44:57 2016
@@ -0,0 +1,4 @@
+// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -Xdemangler sed -Xdemangler 's/_/X/g' -filename-equivalence %S/showTemplateInstantiations.cpp | FileCheck %s
+
+// CHECK: XZ4funcIbEiTX:
+// CHECK: XZ4funcIiEiTX:

Modified: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=275640&r1=275639&r2=275640&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Fri Jul 15 17:44:57 2016
@@ -26,9 +26,12 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
 #include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/ToolOutputFile.h"
 #include <functional>
 #include <system_error>
 
@@ -81,6 +84,12 @@ public:
   /// \brief Load the coverage mapping data. Return nullptr if an error occured.
   std::unique_ptr<CoverageMapping> load();
 
+  /// \brief If a demangler is available, demangle all symbol names.
+  void demangleSymbols(const CoverageMapping &Coverage);
+
+  /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
+  StringRef getSymbolForHumans(StringRef Sym) const;
+
   int run(Command Cmd, int argc, const char **argv);
 
   typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
@@ -101,6 +110,9 @@ public:
   std::string CoverageArch;
 
 private:
+  /// A cache for demangled symbol names.
+  StringMap<std::string> DemangledNames;
+
   /// File paths (absolute, or otherwise) to input source files.
   std::vector<std::string> CollectedPaths;
 
@@ -205,8 +217,9 @@ CodeCoverageTool::createFunctionView(con
     return nullptr;
 
   auto Expansions = FunctionCoverage.getExpansions();
-  auto View = SourceCoverageView::create(Function.Name, SourceBuffer.get(),
-                                         ViewOpts, std::move(FunctionCoverage));
+  auto View = SourceCoverageView::create(getSymbolForHumans(Function.Name),
+                                         SourceBuffer.get(), ViewOpts,
+                                         std::move(FunctionCoverage));
   attachExpansionSubViews(*View, Expansions, Coverage);
 
   return View;
@@ -230,9 +243,9 @@ CodeCoverageTool::createSourceFileView(S
   for (const auto *Function : Coverage.getInstantiations(SourceFile)) {
     auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
     auto SubViewExpansions = SubViewCoverage.getExpansions();
-    auto SubView =
-        SourceCoverageView::create(Function->Name, SourceBuffer.get(), ViewOpts,
-                                   std::move(SubViewCoverage));
+    auto SubView = SourceCoverageView::create(
+        getSymbolForHumans(Function->Name), SourceBuffer.get(), ViewOpts,
+        std::move(SubViewCoverage));
     attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
 
     if (SubView) {
@@ -289,9 +302,91 @@ std::unique_ptr<CoverageMapping> CodeCov
     }
   }
 
+  demangleSymbols(*Coverage);
+
   return Coverage;
 }
 
+void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
+  if (!ViewOpts.hasDemangler())
+    return;
+
+  // Pass function names to the demangler in a temporary file.
+  int InputFD;
+  SmallString<256> InputPath;
+  std::error_code EC =
+      sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath);
+  if (EC) {
+    error(InputPath, EC.message());
+    return;
+  }
+  tool_output_file InputTOF{InputPath, InputFD};
+
+  unsigned NumSymbols = 0;
+  for (const auto &Function : Coverage.getCoveredFunctions()) {
+    InputTOF.os() << Function.Name << '\n';
+    ++NumSymbols;
+  }
+  InputTOF.os().flush();
+
+  // Use another temporary file to store the demangler's output.
+  int OutputFD;
+  SmallString<256> OutputPath;
+  EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD,
+                                    OutputPath);
+  if (EC) {
+    error(OutputPath, EC.message());
+    return;
+  }
+  tool_output_file OutputTOF{OutputPath, OutputFD};
+
+  // Invoke the demangler.
+  std::vector<const char *> ArgsV;
+  for (const std::string &Arg : ViewOpts.DemanglerOpts)
+    ArgsV.push_back(Arg.c_str());
+  ArgsV.push_back(nullptr);
+  StringRef InputPathRef{InputPath}, OutputPathRef{OutputPath}, StderrRef;
+  const StringRef *Redirects[] = {&InputPathRef, &OutputPathRef, &StderrRef};
+  std::string ErrMsg;
+  int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
+                               /*env=*/nullptr, Redirects, /*secondsToWait=*/0,
+                               /*memoryLimit=*/0, &ErrMsg);
+  if (RC) {
+    error(ErrMsg, ViewOpts.DemanglerOpts[0]);
+    return;
+  }
+
+  // Parse the demangler's output.
+  auto BufOrError = MemoryBuffer::getFile(OutputPath);
+  if (!BufOrError) {
+    error(OutputPath, BufOrError.getError().message());
+    return;
+  }
+
+  std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError);
+
+  SmallVector<StringRef, 8> Symbols;
+  StringRef DemanglerData = DemanglerBuf->getBuffer();
+  DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
+                      /*KeepEmpty=*/false);
+  if (Symbols.size() != NumSymbols) {
+    error("Demangler did not provide expected number of symbols");
+    return;
+  }
+
+  // Cache the demangled names.
+  unsigned I = 0;
+  for (const auto &Function : Coverage.getCoveredFunctions())
+    DemangledNames[Function.Name] = Symbols[I++];
+}
+
+StringRef CodeCoverageTool::getSymbolForHumans(StringRef Sym) const {
+  const auto DemangledName = DemangledNames.find(Sym);
+  if (DemangledName == DemangledNames.end())
+    return Sym;
+  return DemangledName->getValue();
+}
+
 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
   cl::opt<std::string, true> ObjectFilename(
       cl::Positional, cl::Required, cl::location(this->ObjectFilename),
@@ -366,6 +461,9 @@ int CodeCoverageTool::run(Command Cmd, i
       "use-color", cl::desc("Emit colored output (default=autodetect)"),
       cl::init(cl::BOU_UNSET));
 
+  cl::list<std::string> DemanglerOpts(
+      "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
+
   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
     ViewOpts.Debug = DebugDump;
@@ -385,6 +483,18 @@ int CodeCoverageTool::run(Command Cmd, i
       break;
     }
 
+    // If a demangler is supplied, check if it exists and register it.
+    if (DemanglerOpts.size()) {
+      auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
+      if (!DemanglerPathOrErr) {
+        error("Could not find the demangler!",
+              DemanglerPathOrErr.getError().message());
+        return 1;
+      }
+      DemanglerOpts[0] = *DemanglerPathOrErr;
+      ViewOpts.DemanglerOpts.swap(DemanglerOpts);
+    }
+
     // Create the function filters
     if (!NameFilters.empty() || !NameRegexFilters.empty()) {
       auto NameFilterer = new CoverageFilters;

Modified: llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageViewOptions.h?rev=275640&r1=275639&r2=275640&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageViewOptions.h (original)
+++ llvm/trunk/tools/llvm-cov/CoverageViewOptions.h Fri Jul 15 17:44:57 2016
@@ -11,6 +11,7 @@
 #define LLVM_COV_COVERAGEVIEWOPTIONS_H
 
 #include "RenderingSupport.h"
+#include <vector>
 
 namespace llvm {
 
@@ -32,6 +33,7 @@ struct CoverageViewOptions {
   bool ShowFullFilenames;
   OutputFormat Format;
   std::string ShowOutputDirectory;
+  std::vector<std::string> DemanglerOpts;
 
   /// \brief Change the output's stream color if the colors are enabled.
   ColoredRawOstream colored_ostream(raw_ostream &OS,
@@ -41,6 +43,9 @@ struct CoverageViewOptions {
 
   /// \brief Check if an output directory has been specified.
   bool hasOutputDirectory() const { return !ShowOutputDirectory.empty(); }
+
+  /// \brief Check if a demangler has been specified.
+  bool hasDemangler() const { return !DemanglerOpts.empty(); }
 };
 }
 




More information about the llvm-commits mailing list