From: Vedant Kumar Date: Fri, 15 Jul 2016 22:44:57 +0000 (+0000) Subject: [llvm-cov] Optionally use a symbol demangler when preparing reports X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=424f51bb041ab23cfe14548563da7367c3ceaf1d;p=platform%2Fupstream%2Fllvm.git [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. llvm-svn: 275640 --- diff --git a/llvm/docs/CommandGuide/llvm-cov.rst b/llvm/docs/CommandGuide/llvm-cov.rst index cdb36e7..946b125 100644 --- a/llvm/docs/CommandGuide/llvm-cov.rst +++ b/llvm/docs/CommandGuide/llvm-cov.rst @@ -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=| + + 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= Show code coverage only for functions with line coverage greater than the diff --git a/llvm/test/tools/llvm-cov/demangle.test b/llvm/test/tools/llvm-cov/demangle.test new file mode 100644 index 0000000..6f56f25 --- /dev/null +++ b/llvm/test/tools/llvm-cov/demangle.test @@ -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: diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index 59cb708..2ceaa1f 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -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 #include @@ -81,6 +84,12 @@ public: /// \brief Load the coverage mapping data. Return nullptr if an error occured. std::unique_ptr 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 CommandLineParserType; @@ -101,6 +110,9 @@ public: std::string CoverageArch; private: + /// A cache for demangled symbol names. + StringMap DemangledNames; + /// File paths (absolute, or otherwise) to input source files. std::vector CollectedPaths; @@ -205,8 +217,9 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function, 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(StringRef SourceFile, 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 CodeCoverageTool::load() { } } + 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 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 DemanglerBuf = std::move(*BufOrError); + + SmallVector 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 ObjectFilename( cl::Positional, cl::Required, cl::location(this->ObjectFilename), @@ -366,6 +461,9 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { "use-color", cl::desc("Emit colored output (default=autodetect)"), cl::init(cl::BOU_UNSET)); + cl::list DemanglerOpts( + "Xdemangler", cl::desc("|")); + 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, int argc, const char **argv) { 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; diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h index eafc0cf..350c264 100644 --- a/llvm/tools/llvm-cov/CoverageViewOptions.h +++ b/llvm/tools/llvm-cov/CoverageViewOptions.h @@ -11,6 +11,7 @@ #define LLVM_COV_COVERAGEVIEWOPTIONS_H #include "RenderingSupport.h" +#include namespace llvm { @@ -32,6 +33,7 @@ struct CoverageViewOptions { bool ShowFullFilenames; OutputFormat Format; std::string ShowOutputDirectory; + std::vector 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(); } }; }