1 //===- llvm-cxxmap.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // llvm-cxxmap computes a correspondence between old symbol names and new 10 // symbol names based on a symbol equivalence file. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/DenseMap.h" 15 #include "llvm/ADT/DenseSet.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/Support/CommandLine.h" 18 #include "llvm/Support/FileSystem.h" 19 #include "llvm/Support/InitLLVM.h" 20 #include "llvm/Support/LineIterator.h" 21 #include "llvm/Support/MemoryBuffer.h" 22 #include "llvm/Support/SymbolRemappingReader.h" 23 #include "llvm/Support/WithColor.h" 24 #include "llvm/Support/raw_ostream.h" 25 26 using namespace llvm; 27 28 cl::opt<std::string> OldSymbolFile(cl::Positional, cl::Required, 29 cl::desc("<symbol-file>")); 30 cl::opt<std::string> NewSymbolFile(cl::Positional, cl::Required, 31 cl::desc("<symbol-file>")); 32 cl::opt<std::string> RemappingFile("remapping-file", cl::Required, 33 cl::desc("Remapping file")); 34 cl::alias RemappingFileA("r", cl::aliasopt(RemappingFile)); 35 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), 36 cl::init("-"), cl::desc("Output file")); 37 cl::alias OutputFilenameA("o", cl::aliasopt(OutputFilename)); 38 39 cl::opt<bool> WarnAmbiguous( 40 "Wambiguous", 41 cl::desc("Warn on equivalent symbols in the output symbol list")); 42 cl::opt<bool> WarnIncomplete( 43 "Wincomplete", 44 cl::desc("Warn on input symbols missing from output symbol list")); 45 46 static void warn(Twine Message, Twine Whence = "", 47 std::string Hint = "") { 48 WithColor::warning(); 49 std::string WhenceStr = Whence.str(); 50 if (!WhenceStr.empty()) 51 errs() << WhenceStr << ": "; 52 errs() << Message << "\n"; 53 if (!Hint.empty()) 54 WithColor::note() << Hint << "\n"; 55 } 56 57 static void exitWithError(Twine Message, Twine Whence = "", 58 std::string Hint = "") { 59 WithColor::error(); 60 std::string WhenceStr = Whence.str(); 61 if (!WhenceStr.empty()) 62 errs() << WhenceStr << ": "; 63 errs() << Message << "\n"; 64 if (!Hint.empty()) 65 WithColor::note() << Hint << "\n"; 66 ::exit(1); 67 } 68 69 static void exitWithError(Error E, StringRef Whence = "") { 70 exitWithError(toString(std::move(E)), Whence); 71 } 72 73 static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") { 74 exitWithError(EC.message(), Whence); 75 } 76 77 static void remapSymbols(MemoryBuffer &OldSymbolFile, 78 MemoryBuffer &NewSymbolFile, 79 MemoryBuffer &RemappingFile, 80 raw_ostream &Out) { 81 // Load the remapping file and prepare to canonicalize symbols. 82 SymbolRemappingReader Reader; 83 if (Error E = Reader.read(RemappingFile)) 84 exitWithError(std::move(E)); 85 86 // Canonicalize the new symbols. 87 DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames; 88 DenseSet<StringRef> UnparseableSymbols; 89 for (line_iterator LineIt(NewSymbolFile, /*SkipBlanks=*/true, '#'); 90 !LineIt.is_at_eof(); ++LineIt) { 91 StringRef Symbol = *LineIt; 92 93 auto K = Reader.insert(Symbol); 94 if (!K) { 95 UnparseableSymbols.insert(Symbol); 96 continue; 97 } 98 99 auto ItAndIsNew = MappedNames.insert({K, Symbol}); 100 if (WarnAmbiguous && !ItAndIsNew.second && 101 ItAndIsNew.first->second != Symbol) { 102 warn("symbol " + Symbol + " is equivalent to earlier symbol " + 103 ItAndIsNew.first->second, 104 NewSymbolFile.getBufferIdentifier() + ":" + 105 Twine(LineIt.line_number()), 106 "later symbol will not be the target of any remappings"); 107 } 108 } 109 110 // Figure out which new symbol each old symbol is equivalent to. 111 for (line_iterator LineIt(OldSymbolFile, /*SkipBlanks=*/true, '#'); 112 !LineIt.is_at_eof(); ++LineIt) { 113 StringRef Symbol = *LineIt; 114 115 auto K = Reader.lookup(Symbol); 116 StringRef NewSymbol = MappedNames.lookup(K); 117 118 if (NewSymbol.empty()) { 119 if (WarnIncomplete && !UnparseableSymbols.count(Symbol)) { 120 warn("no new symbol matches old symbol " + Symbol, 121 OldSymbolFile.getBufferIdentifier() + ":" + 122 Twine(LineIt.line_number())); 123 } 124 continue; 125 } 126 127 Out << Symbol << " " << NewSymbol << "\n"; 128 } 129 } 130 131 int main(int argc, const char *argv[]) { 132 InitLLVM X(argc, argv); 133 134 cl::ParseCommandLineOptions(argc, argv, "LLVM C++ mangled name remapper\n"); 135 136 auto OldSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(OldSymbolFile); 137 if (!OldSymbolBufOrError) 138 exitWithErrorCode(OldSymbolBufOrError.getError(), OldSymbolFile); 139 140 auto NewSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(NewSymbolFile); 141 if (!NewSymbolBufOrError) 142 exitWithErrorCode(NewSymbolBufOrError.getError(), NewSymbolFile); 143 144 auto RemappingBufOrError = MemoryBuffer::getFileOrSTDIN(RemappingFile); 145 if (!RemappingBufOrError) 146 exitWithErrorCode(RemappingBufOrError.getError(), RemappingFile); 147 148 std::error_code EC; 149 raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF); 150 if (EC) 151 exitWithErrorCode(EC, OutputFilename); 152 153 remapSymbols(*OldSymbolBufOrError.get(), *NewSymbolBufOrError.get(), 154 *RemappingBufOrError.get(), OS); 155 } 156