mirror of
https://github.com/RPCS3/llvm.git
synced 2025-03-05 00:59:19 +00:00
[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:
parent
a5ec41d9a9
commit
13ca1ccb76
@ -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
|
||||
|
4
test/tools/llvm-cov/demangle.test
Normal file
4
test/tools/llvm-cov/demangle.test
Normal 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:
|
@ -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;
|
||||
|
@ -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(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user