xref: /openbsd-src/gnu/llvm/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp (revision 73471bf04ceb096474c7f0fa83b1b65c70a787a1)
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