109467b48Spatrick //===- llvm-cxxmap.cpp ----------------------------------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // llvm-cxxmap computes a correspondence between old symbol names and new
1009467b48Spatrick // symbol names based on a symbol equivalence file.
1109467b48Spatrick //
1209467b48Spatrick //===----------------------------------------------------------------------===//
1309467b48Spatrick
1409467b48Spatrick #include "llvm/ADT/DenseMap.h"
15*73471bf0Spatrick #include "llvm/ADT/DenseSet.h"
1609467b48Spatrick #include "llvm/ADT/StringRef.h"
1709467b48Spatrick #include "llvm/Support/CommandLine.h"
18*73471bf0Spatrick #include "llvm/Support/FileSystem.h"
1909467b48Spatrick #include "llvm/Support/InitLLVM.h"
2009467b48Spatrick #include "llvm/Support/LineIterator.h"
2109467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
2209467b48Spatrick #include "llvm/Support/SymbolRemappingReader.h"
2309467b48Spatrick #include "llvm/Support/WithColor.h"
2409467b48Spatrick #include "llvm/Support/raw_ostream.h"
2509467b48Spatrick
2609467b48Spatrick using namespace llvm;
2709467b48Spatrick
28*73471bf0Spatrick cl::OptionCategory CXXMapCategory("CXX Map Options");
29*73471bf0Spatrick
3009467b48Spatrick cl::opt<std::string> OldSymbolFile(cl::Positional, cl::Required,
31*73471bf0Spatrick cl::desc("<symbol-file>"),
32*73471bf0Spatrick cl::cat(CXXMapCategory));
3309467b48Spatrick cl::opt<std::string> NewSymbolFile(cl::Positional, cl::Required,
34*73471bf0Spatrick cl::desc("<symbol-file>"),
35*73471bf0Spatrick cl::cat(CXXMapCategory));
3609467b48Spatrick cl::opt<std::string> RemappingFile("remapping-file", cl::Required,
37*73471bf0Spatrick cl::desc("Remapping file"),
38*73471bf0Spatrick cl::cat(CXXMapCategory));
39*73471bf0Spatrick cl::alias RemappingFileA("r", cl::aliasopt(RemappingFile),
40*73471bf0Spatrick cl::cat(CXXMapCategory));
4109467b48Spatrick cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
42*73471bf0Spatrick cl::init("-"), cl::desc("Output file"),
43*73471bf0Spatrick cl::cat(CXXMapCategory));
44*73471bf0Spatrick cl::alias OutputFilenameA("o", cl::aliasopt(OutputFilename),
45*73471bf0Spatrick cl::cat(CXXMapCategory));
4609467b48Spatrick
4709467b48Spatrick cl::opt<bool> WarnAmbiguous(
4809467b48Spatrick "Wambiguous",
49*73471bf0Spatrick cl::desc("Warn on equivalent symbols in the output symbol list"),
50*73471bf0Spatrick cl::cat(CXXMapCategory));
5109467b48Spatrick cl::opt<bool> WarnIncomplete(
5209467b48Spatrick "Wincomplete",
53*73471bf0Spatrick cl::desc("Warn on input symbols missing from output symbol list"),
54*73471bf0Spatrick cl::cat(CXXMapCategory));
5509467b48Spatrick
warn(Twine Message,Twine Whence="",std::string Hint="")5609467b48Spatrick static void warn(Twine Message, Twine Whence = "",
5709467b48Spatrick std::string Hint = "") {
5809467b48Spatrick WithColor::warning();
5909467b48Spatrick std::string WhenceStr = Whence.str();
6009467b48Spatrick if (!WhenceStr.empty())
6109467b48Spatrick errs() << WhenceStr << ": ";
6209467b48Spatrick errs() << Message << "\n";
6309467b48Spatrick if (!Hint.empty())
6409467b48Spatrick WithColor::note() << Hint << "\n";
6509467b48Spatrick }
6609467b48Spatrick
exitWithError(Twine Message,Twine Whence="",std::string Hint="")6709467b48Spatrick static void exitWithError(Twine Message, Twine Whence = "",
6809467b48Spatrick std::string Hint = "") {
6909467b48Spatrick WithColor::error();
7009467b48Spatrick std::string WhenceStr = Whence.str();
7109467b48Spatrick if (!WhenceStr.empty())
7209467b48Spatrick errs() << WhenceStr << ": ";
7309467b48Spatrick errs() << Message << "\n";
7409467b48Spatrick if (!Hint.empty())
7509467b48Spatrick WithColor::note() << Hint << "\n";
7609467b48Spatrick ::exit(1);
7709467b48Spatrick }
7809467b48Spatrick
exitWithError(Error E,StringRef Whence="")7909467b48Spatrick static void exitWithError(Error E, StringRef Whence = "") {
8009467b48Spatrick exitWithError(toString(std::move(E)), Whence);
8109467b48Spatrick }
8209467b48Spatrick
exitWithErrorCode(std::error_code EC,StringRef Whence="")8309467b48Spatrick static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {
8409467b48Spatrick exitWithError(EC.message(), Whence);
8509467b48Spatrick }
8609467b48Spatrick
remapSymbols(MemoryBuffer & OldSymbolFile,MemoryBuffer & NewSymbolFile,MemoryBuffer & RemappingFile,raw_ostream & Out)8709467b48Spatrick static void remapSymbols(MemoryBuffer &OldSymbolFile,
8809467b48Spatrick MemoryBuffer &NewSymbolFile,
8909467b48Spatrick MemoryBuffer &RemappingFile,
9009467b48Spatrick raw_ostream &Out) {
9109467b48Spatrick // Load the remapping file and prepare to canonicalize symbols.
9209467b48Spatrick SymbolRemappingReader Reader;
9309467b48Spatrick if (Error E = Reader.read(RemappingFile))
9409467b48Spatrick exitWithError(std::move(E));
9509467b48Spatrick
9609467b48Spatrick // Canonicalize the new symbols.
9709467b48Spatrick DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
9809467b48Spatrick DenseSet<StringRef> UnparseableSymbols;
9909467b48Spatrick for (line_iterator LineIt(NewSymbolFile, /*SkipBlanks=*/true, '#');
10009467b48Spatrick !LineIt.is_at_eof(); ++LineIt) {
10109467b48Spatrick StringRef Symbol = *LineIt;
10209467b48Spatrick
10309467b48Spatrick auto K = Reader.insert(Symbol);
10409467b48Spatrick if (!K) {
10509467b48Spatrick UnparseableSymbols.insert(Symbol);
10609467b48Spatrick continue;
10709467b48Spatrick }
10809467b48Spatrick
10909467b48Spatrick auto ItAndIsNew = MappedNames.insert({K, Symbol});
11009467b48Spatrick if (WarnAmbiguous && !ItAndIsNew.second &&
11109467b48Spatrick ItAndIsNew.first->second != Symbol) {
11209467b48Spatrick warn("symbol " + Symbol + " is equivalent to earlier symbol " +
11309467b48Spatrick ItAndIsNew.first->second,
11409467b48Spatrick NewSymbolFile.getBufferIdentifier() + ":" +
11509467b48Spatrick Twine(LineIt.line_number()),
11609467b48Spatrick "later symbol will not be the target of any remappings");
11709467b48Spatrick }
11809467b48Spatrick }
11909467b48Spatrick
12009467b48Spatrick // Figure out which new symbol each old symbol is equivalent to.
12109467b48Spatrick for (line_iterator LineIt(OldSymbolFile, /*SkipBlanks=*/true, '#');
12209467b48Spatrick !LineIt.is_at_eof(); ++LineIt) {
12309467b48Spatrick StringRef Symbol = *LineIt;
12409467b48Spatrick
12509467b48Spatrick auto K = Reader.lookup(Symbol);
12609467b48Spatrick StringRef NewSymbol = MappedNames.lookup(K);
12709467b48Spatrick
12809467b48Spatrick if (NewSymbol.empty()) {
12909467b48Spatrick if (WarnIncomplete && !UnparseableSymbols.count(Symbol)) {
13009467b48Spatrick warn("no new symbol matches old symbol " + Symbol,
13109467b48Spatrick OldSymbolFile.getBufferIdentifier() + ":" +
13209467b48Spatrick Twine(LineIt.line_number()));
13309467b48Spatrick }
13409467b48Spatrick continue;
13509467b48Spatrick }
13609467b48Spatrick
13709467b48Spatrick Out << Symbol << " " << NewSymbol << "\n";
13809467b48Spatrick }
13909467b48Spatrick }
14009467b48Spatrick
main(int argc,const char * argv[])14109467b48Spatrick int main(int argc, const char *argv[]) {
14209467b48Spatrick InitLLVM X(argc, argv);
14309467b48Spatrick
144*73471bf0Spatrick cl::HideUnrelatedOptions({&CXXMapCategory, &getColorCategory()});
14509467b48Spatrick cl::ParseCommandLineOptions(argc, argv, "LLVM C++ mangled name remapper\n");
14609467b48Spatrick
14709467b48Spatrick auto OldSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(OldSymbolFile);
14809467b48Spatrick if (!OldSymbolBufOrError)
14909467b48Spatrick exitWithErrorCode(OldSymbolBufOrError.getError(), OldSymbolFile);
15009467b48Spatrick
15109467b48Spatrick auto NewSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(NewSymbolFile);
15209467b48Spatrick if (!NewSymbolBufOrError)
15309467b48Spatrick exitWithErrorCode(NewSymbolBufOrError.getError(), NewSymbolFile);
15409467b48Spatrick
15509467b48Spatrick auto RemappingBufOrError = MemoryBuffer::getFileOrSTDIN(RemappingFile);
15609467b48Spatrick if (!RemappingBufOrError)
15709467b48Spatrick exitWithErrorCode(RemappingBufOrError.getError(), RemappingFile);
15809467b48Spatrick
15909467b48Spatrick std::error_code EC;
160*73471bf0Spatrick raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
16109467b48Spatrick if (EC)
16209467b48Spatrick exitWithErrorCode(EC, OutputFilename);
16309467b48Spatrick
16409467b48Spatrick remapSymbols(*OldSymbolBufOrError.get(), *NewSymbolBufOrError.get(),
16509467b48Spatrick *RemappingBufOrError.get(), OS);
16609467b48Spatrick }
167