[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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275640 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Vedant Kumar 2016-07-15 22:44:57 +00:00
parent a5ec41d9a9
commit 13ca1ccb76
4 changed files with 132 additions and 5 deletions

View File

@ -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

View File

@ -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:

View File

@ -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(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<CoverageMapping> 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<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, int argc, const char **argv) {
"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, 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;

View File

@ -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(); }
};
}