xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-cxxmap/llvm-cxxmap.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- llvm-cxxmap.cpp ----------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // llvm-cxxmap computes a correspondence between old symbol names and new
100b57cec5SDimitry Andric // symbol names based on a symbol equivalence file.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
15fe6060f1SDimitry Andric #include "llvm/ADT/DenseSet.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
1706c3fb27SDimitry Andric #include "llvm/ProfileData/SymbolRemappingReader.h"
180b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
19fe6060f1SDimitry Andric #include "llvm/Support/FileSystem.h"
200b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
210b57cec5SDimitry Andric #include "llvm/Support/LineIterator.h"
220b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
230b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
28fe6060f1SDimitry Andric cl::OptionCategory CXXMapCategory("CXX Map Options");
29fe6060f1SDimitry Andric 
300b57cec5SDimitry Andric cl::opt<std::string> OldSymbolFile(cl::Positional, cl::Required,
31fe6060f1SDimitry Andric                                    cl::desc("<symbol-file>"),
32fe6060f1SDimitry Andric                                    cl::cat(CXXMapCategory));
330b57cec5SDimitry Andric cl::opt<std::string> NewSymbolFile(cl::Positional, cl::Required,
34fe6060f1SDimitry Andric                                    cl::desc("<symbol-file>"),
35fe6060f1SDimitry Andric                                    cl::cat(CXXMapCategory));
360b57cec5SDimitry Andric cl::opt<std::string> RemappingFile("remapping-file", cl::Required,
37fe6060f1SDimitry Andric                                    cl::desc("Remapping file"),
38fe6060f1SDimitry Andric                                    cl::cat(CXXMapCategory));
39fe6060f1SDimitry Andric cl::alias RemappingFileA("r", cl::aliasopt(RemappingFile),
40fe6060f1SDimitry Andric                          cl::cat(CXXMapCategory));
410b57cec5SDimitry Andric cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
42fe6060f1SDimitry Andric                                     cl::init("-"), cl::desc("Output file"),
43fe6060f1SDimitry Andric                                     cl::cat(CXXMapCategory));
44fe6060f1SDimitry Andric cl::alias OutputFilenameA("o", cl::aliasopt(OutputFilename),
45fe6060f1SDimitry Andric                           cl::cat(CXXMapCategory));
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric cl::opt<bool> WarnAmbiguous(
480b57cec5SDimitry Andric     "Wambiguous",
49fe6060f1SDimitry Andric     cl::desc("Warn on equivalent symbols in the output symbol list"),
50fe6060f1SDimitry Andric     cl::cat(CXXMapCategory));
510b57cec5SDimitry Andric cl::opt<bool> WarnIncomplete(
520b57cec5SDimitry Andric     "Wincomplete",
53fe6060f1SDimitry Andric     cl::desc("Warn on input symbols missing from output symbol list"),
54fe6060f1SDimitry Andric     cl::cat(CXXMapCategory));
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric static void warn(Twine Message, Twine Whence = "",
570b57cec5SDimitry Andric                  std::string Hint = "") {
580b57cec5SDimitry Andric   WithColor::warning();
590b57cec5SDimitry Andric   std::string WhenceStr = Whence.str();
600b57cec5SDimitry Andric   if (!WhenceStr.empty())
610b57cec5SDimitry Andric     errs() << WhenceStr << ": ";
620b57cec5SDimitry Andric   errs() << Message << "\n";
630b57cec5SDimitry Andric   if (!Hint.empty())
640b57cec5SDimitry Andric     WithColor::note() << Hint << "\n";
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric static void exitWithError(Twine Message, Twine Whence = "",
680b57cec5SDimitry Andric                           std::string Hint = "") {
690b57cec5SDimitry Andric   WithColor::error();
700b57cec5SDimitry Andric   std::string WhenceStr = Whence.str();
710b57cec5SDimitry Andric   if (!WhenceStr.empty())
720b57cec5SDimitry Andric     errs() << WhenceStr << ": ";
730b57cec5SDimitry Andric   errs() << Message << "\n";
740b57cec5SDimitry Andric   if (!Hint.empty())
750b57cec5SDimitry Andric     WithColor::note() << Hint << "\n";
760b57cec5SDimitry Andric   ::exit(1);
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric static void exitWithError(Error E, StringRef Whence = "") {
800b57cec5SDimitry Andric   exitWithError(toString(std::move(E)), Whence);
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {
840b57cec5SDimitry Andric   exitWithError(EC.message(), Whence);
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric static void remapSymbols(MemoryBuffer &OldSymbolFile,
880b57cec5SDimitry Andric                          MemoryBuffer &NewSymbolFile,
890b57cec5SDimitry Andric                          MemoryBuffer &RemappingFile,
900b57cec5SDimitry Andric                          raw_ostream &Out) {
910b57cec5SDimitry Andric   // Load the remapping file and prepare to canonicalize symbols.
920b57cec5SDimitry Andric   SymbolRemappingReader Reader;
930b57cec5SDimitry Andric   if (Error E = Reader.read(RemappingFile))
940b57cec5SDimitry Andric     exitWithError(std::move(E));
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   // Canonicalize the new symbols.
970b57cec5SDimitry Andric   DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames;
980b57cec5SDimitry Andric   DenseSet<StringRef> UnparseableSymbols;
990b57cec5SDimitry Andric   for (line_iterator LineIt(NewSymbolFile, /*SkipBlanks=*/true, '#');
1000b57cec5SDimitry Andric        !LineIt.is_at_eof(); ++LineIt) {
1010b57cec5SDimitry Andric     StringRef Symbol = *LineIt;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric     auto K = Reader.insert(Symbol);
1040b57cec5SDimitry Andric     if (!K) {
1050b57cec5SDimitry Andric       UnparseableSymbols.insert(Symbol);
1060b57cec5SDimitry Andric       continue;
1070b57cec5SDimitry Andric     }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric     auto ItAndIsNew = MappedNames.insert({K, Symbol});
1100b57cec5SDimitry Andric     if (WarnAmbiguous && !ItAndIsNew.second &&
1110b57cec5SDimitry Andric         ItAndIsNew.first->second != Symbol) {
1120b57cec5SDimitry Andric       warn("symbol " + Symbol + " is equivalent to earlier symbol " +
1130b57cec5SDimitry Andric                ItAndIsNew.first->second,
1140b57cec5SDimitry Andric            NewSymbolFile.getBufferIdentifier() + ":" +
1150b57cec5SDimitry Andric                Twine(LineIt.line_number()),
1160b57cec5SDimitry Andric            "later symbol will not be the target of any remappings");
1170b57cec5SDimitry Andric     }
1180b57cec5SDimitry Andric   }
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   // Figure out which new symbol each old symbol is equivalent to.
1210b57cec5SDimitry Andric   for (line_iterator LineIt(OldSymbolFile, /*SkipBlanks=*/true, '#');
1220b57cec5SDimitry Andric        !LineIt.is_at_eof(); ++LineIt) {
1230b57cec5SDimitry Andric     StringRef Symbol = *LineIt;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric     auto K = Reader.lookup(Symbol);
1260b57cec5SDimitry Andric     StringRef NewSymbol = MappedNames.lookup(K);
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     if (NewSymbol.empty()) {
1290b57cec5SDimitry Andric       if (WarnIncomplete && !UnparseableSymbols.count(Symbol)) {
1300b57cec5SDimitry Andric         warn("no new symbol matches old symbol " + Symbol,
1310b57cec5SDimitry Andric              OldSymbolFile.getBufferIdentifier() + ":" +
1320b57cec5SDimitry Andric                  Twine(LineIt.line_number()));
1330b57cec5SDimitry Andric       }
1340b57cec5SDimitry Andric       continue;
1350b57cec5SDimitry Andric     }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric     Out << Symbol << " " << NewSymbol << "\n";
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric int main(int argc, const char *argv[]) {
1420b57cec5SDimitry Andric   InitLLVM X(argc, argv);
1430b57cec5SDimitry Andric 
144fe6060f1SDimitry Andric   cl::HideUnrelatedOptions({&CXXMapCategory, &getColorCategory()});
1450b57cec5SDimitry Andric   cl::ParseCommandLineOptions(argc, argv, "LLVM C++ mangled name remapper\n");
1460b57cec5SDimitry Andric 
147*0fca6ea1SDimitry Andric   auto OldSymbolBufOrError =
148*0fca6ea1SDimitry Andric       MemoryBuffer::getFileOrSTDIN(OldSymbolFile, /*IsText=*/true);
1490b57cec5SDimitry Andric   if (!OldSymbolBufOrError)
1500b57cec5SDimitry Andric     exitWithErrorCode(OldSymbolBufOrError.getError(), OldSymbolFile);
1510b57cec5SDimitry Andric 
152*0fca6ea1SDimitry Andric   auto NewSymbolBufOrError =
153*0fca6ea1SDimitry Andric       MemoryBuffer::getFileOrSTDIN(NewSymbolFile, /*IsText=*/true);
1540b57cec5SDimitry Andric   if (!NewSymbolBufOrError)
1550b57cec5SDimitry Andric     exitWithErrorCode(NewSymbolBufOrError.getError(), NewSymbolFile);
1560b57cec5SDimitry Andric 
157*0fca6ea1SDimitry Andric   auto RemappingBufOrError =
158*0fca6ea1SDimitry Andric       MemoryBuffer::getFileOrSTDIN(RemappingFile, /*IsText=*/true);
1590b57cec5SDimitry Andric   if (!RemappingBufOrError)
1600b57cec5SDimitry Andric     exitWithErrorCode(RemappingBufOrError.getError(), RemappingFile);
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   std::error_code EC;
163fe6060f1SDimitry Andric   raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
1640b57cec5SDimitry Andric   if (EC)
1650b57cec5SDimitry Andric     exitWithErrorCode(EC, OutputFilename);
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric   remapSymbols(*OldSymbolBufOrError.get(), *NewSymbolBufOrError.get(),
1680b57cec5SDimitry Andric                *RemappingBufOrError.get(), OS);
1690b57cec5SDimitry Andric }
170