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