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