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