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