From 3164fcfd273b37931e30a631f525d52ac2897fc0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 13 Sep 2018 20:22:02 +0000 Subject: Add flag to llvm-profdata to allow symbols in profile data to be remapped, and add a tool to generate symbol remapping files. Summary: The new tool llvm-cxxmap builds a symbol mapping table from a file containing a description of partial equivalences to apply to mangled names and files containing old and new symbol tables. Reviewers: davidxl Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D51470 llvm-svn: 342168 --- llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp | 155 +++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp (limited to 'llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp') diff --git a/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp b/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp new file mode 100644 index 00000000000..39028cc8672 --- /dev/null +++ b/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp @@ -0,0 +1,155 @@ +//===- llvm-cxxmap.cpp ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// llvm-cxxmap computes a correspondence between old symbol names and new +// symbol names based on a symbol equivalence file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SymbolRemappingReader.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +cl::opt OldSymbolFile(cl::Positional, cl::Required, + cl::desc("")); +cl::opt NewSymbolFile(cl::Positional, cl::Required, + cl::desc("")); +cl::opt RemappingFile("remapping-file", cl::Required, + cl::desc("Remapping file")); +cl::alias RemappingFileA("r", cl::aliasopt(RemappingFile)); +cl::opt OutputFilename("output", cl::value_desc("output"), + cl::init("-"), cl::desc("Output file")); +cl::alias OutputFilenameA("o", cl::aliasopt(OutputFilename)); + +cl::opt WarnAmbiguous( + "Wambiguous", + cl::desc("Warn on equivalent symbols in the output symbol list")); +cl::opt WarnIncomplete( + "Wincomplete", + cl::desc("Warn on input symbols missing from output symbol list")); + +static void warn(Twine Message, Twine Whence = "", + std::string Hint = "") { + WithColor::warning(); + std::string WhenceStr = Whence.str(); + if (!WhenceStr.empty()) + errs() << WhenceStr << ": "; + errs() << Message << "\n"; + if (!Hint.empty()) + WithColor::note() << Hint << "\n"; +} + +static void exitWithError(Twine Message, Twine Whence = "", + std::string Hint = "") { + WithColor::error(); + std::string WhenceStr = Whence.str(); + if (!WhenceStr.empty()) + errs() << WhenceStr << ": "; + errs() << Message << "\n"; + if (!Hint.empty()) + WithColor::note() << Hint << "\n"; + ::exit(1); +} + +static void exitWithError(Error E, StringRef Whence = "") { + exitWithError(toString(std::move(E)), Whence); +} + +static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") { + exitWithError(EC.message(), Whence); +} + +static void remapSymbols(MemoryBuffer &OldSymbolFile, + MemoryBuffer &NewSymbolFile, + MemoryBuffer &RemappingFile, + raw_ostream &Out) { + // Load the remapping file and prepare to canonicalize symbols. + SymbolRemappingReader Reader; + if (Error E = Reader.read(RemappingFile)) + exitWithError(std::move(E)); + + // Canonicalize the new symbols. + DenseMap MappedNames; + DenseSet UnparseableSymbols; + for (line_iterator LineIt(NewSymbolFile, /*SkipBlanks=*/true, '#'); + !LineIt.is_at_eof(); ++LineIt) { + StringRef Symbol = *LineIt; + + auto K = Reader.insert(Symbol); + if (!K) { + UnparseableSymbols.insert(Symbol); + continue; + } + + auto ItAndIsNew = MappedNames.insert({K, Symbol}); + if (WarnAmbiguous && !ItAndIsNew.second && + ItAndIsNew.first->second != Symbol) { + warn("symbol " + Symbol + " is equivalent to earlier symbol " + + ItAndIsNew.first->second, + NewSymbolFile.getBufferIdentifier() + ":" + + Twine(LineIt.line_number()), + "later symbol will not be the target of any remappings"); + } + } + + // Figure out which new symbol each old symbol is equivalent to. + for (line_iterator LineIt(OldSymbolFile, /*SkipBlanks=*/true, '#'); + !LineIt.is_at_eof(); ++LineIt) { + StringRef Symbol = *LineIt; + + auto K = Reader.lookup(Symbol); + StringRef NewSymbol = MappedNames.lookup(K); + + if (NewSymbol.empty()) { + if (WarnIncomplete && !UnparseableSymbols.count(Symbol)) { + warn("no new symbol matches old symbol " + Symbol, + OldSymbolFile.getBufferIdentifier() + ":" + + Twine(LineIt.line_number())); + } + continue; + } + + Out << Symbol << " " << NewSymbol << "\n"; + } +} + +int main(int argc, const char *argv[]) { + InitLLVM X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv, "LLVM C++ mangled name remapper\n"); + + auto OldSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(OldSymbolFile); + if (!OldSymbolBufOrError) + exitWithErrorCode(OldSymbolBufOrError.getError(), OldSymbolFile); + + auto NewSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(NewSymbolFile); + if (!NewSymbolBufOrError) + exitWithErrorCode(NewSymbolBufOrError.getError(), NewSymbolFile); + + auto RemappingBufOrError = MemoryBuffer::getFileOrSTDIN(RemappingFile); + if (!RemappingBufOrError) + exitWithErrorCode(RemappingBufOrError.getError(), RemappingFile); + + std::error_code EC; + raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); + if (EC) + exitWithErrorCode(EC, OutputFilename); + + remapSymbols(*OldSymbolBufOrError.get(), *NewSymbolBufOrError.get(), + *RemappingBufOrError.get(), OS); +} -- cgit v1.2.3