1343171Sdim//===- llvm-cxxmap.cpp ----------------------------------------------------===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim// 9343171Sdim// llvm-cxxmap computes a correspondence between old symbol names and new 10343171Sdim// symbol names based on a symbol equivalence file. 11343171Sdim// 12343171Sdim//===----------------------------------------------------------------------===// 13343171Sdim 14343171Sdim#include "llvm/ADT/DenseSet.h" 15343171Sdim#include "llvm/ADT/DenseMap.h" 16343171Sdim#include "llvm/ADT/StringRef.h" 17343171Sdim#include "llvm/Support/CommandLine.h" 18343171Sdim#include "llvm/Support/InitLLVM.h" 19343171Sdim#include "llvm/Support/LineIterator.h" 20343171Sdim#include "llvm/Support/MemoryBuffer.h" 21343171Sdim#include "llvm/Support/SymbolRemappingReader.h" 22343171Sdim#include "llvm/Support/WithColor.h" 23343171Sdim#include "llvm/Support/raw_ostream.h" 24343171Sdim 25343171Sdimusing namespace llvm; 26343171Sdim 27343171Sdimcl::opt<std::string> OldSymbolFile(cl::Positional, cl::Required, 28343171Sdim cl::desc("<symbol-file>")); 29343171Sdimcl::opt<std::string> NewSymbolFile(cl::Positional, cl::Required, 30343171Sdim cl::desc("<symbol-file>")); 31343171Sdimcl::opt<std::string> RemappingFile("remapping-file", cl::Required, 32343171Sdim cl::desc("Remapping file")); 33343171Sdimcl::alias RemappingFileA("r", cl::aliasopt(RemappingFile)); 34343171Sdimcl::opt<std::string> OutputFilename("output", cl::value_desc("output"), 35343171Sdim cl::init("-"), cl::desc("Output file")); 36343171Sdimcl::alias OutputFilenameA("o", cl::aliasopt(OutputFilename)); 37343171Sdim 38343171Sdimcl::opt<bool> WarnAmbiguous( 39343171Sdim "Wambiguous", 40343171Sdim cl::desc("Warn on equivalent symbols in the output symbol list")); 41343171Sdimcl::opt<bool> WarnIncomplete( 42343171Sdim "Wincomplete", 43343171Sdim cl::desc("Warn on input symbols missing from output symbol list")); 44343171Sdim 45343171Sdimstatic void warn(Twine Message, Twine Whence = "", 46343171Sdim std::string Hint = "") { 47343171Sdim WithColor::warning(); 48343171Sdim std::string WhenceStr = Whence.str(); 49343171Sdim if (!WhenceStr.empty()) 50343171Sdim errs() << WhenceStr << ": "; 51343171Sdim errs() << Message << "\n"; 52343171Sdim if (!Hint.empty()) 53343171Sdim WithColor::note() << Hint << "\n"; 54343171Sdim} 55343171Sdim 56343171Sdimstatic void exitWithError(Twine Message, Twine Whence = "", 57343171Sdim std::string Hint = "") { 58343171Sdim WithColor::error(); 59343171Sdim std::string WhenceStr = Whence.str(); 60343171Sdim if (!WhenceStr.empty()) 61343171Sdim errs() << WhenceStr << ": "; 62343171Sdim errs() << Message << "\n"; 63343171Sdim if (!Hint.empty()) 64343171Sdim WithColor::note() << Hint << "\n"; 65343171Sdim ::exit(1); 66343171Sdim} 67343171Sdim 68343171Sdimstatic void exitWithError(Error E, StringRef Whence = "") { 69343171Sdim exitWithError(toString(std::move(E)), Whence); 70343171Sdim} 71343171Sdim 72343171Sdimstatic void exitWithErrorCode(std::error_code EC, StringRef Whence = "") { 73343171Sdim exitWithError(EC.message(), Whence); 74343171Sdim} 75343171Sdim 76343171Sdimstatic void remapSymbols(MemoryBuffer &OldSymbolFile, 77343171Sdim MemoryBuffer &NewSymbolFile, 78343171Sdim MemoryBuffer &RemappingFile, 79343171Sdim raw_ostream &Out) { 80343171Sdim // Load the remapping file and prepare to canonicalize symbols. 81343171Sdim SymbolRemappingReader Reader; 82343171Sdim if (Error E = Reader.read(RemappingFile)) 83343171Sdim exitWithError(std::move(E)); 84343171Sdim 85343171Sdim // Canonicalize the new symbols. 86343171Sdim DenseMap<SymbolRemappingReader::Key, StringRef> MappedNames; 87343171Sdim DenseSet<StringRef> UnparseableSymbols; 88343171Sdim for (line_iterator LineIt(NewSymbolFile, /*SkipBlanks=*/true, '#'); 89343171Sdim !LineIt.is_at_eof(); ++LineIt) { 90343171Sdim StringRef Symbol = *LineIt; 91343171Sdim 92343171Sdim auto K = Reader.insert(Symbol); 93343171Sdim if (!K) { 94343171Sdim UnparseableSymbols.insert(Symbol); 95343171Sdim continue; 96343171Sdim } 97343171Sdim 98343171Sdim auto ItAndIsNew = MappedNames.insert({K, Symbol}); 99343171Sdim if (WarnAmbiguous && !ItAndIsNew.second && 100343171Sdim ItAndIsNew.first->second != Symbol) { 101343171Sdim warn("symbol " + Symbol + " is equivalent to earlier symbol " + 102343171Sdim ItAndIsNew.first->second, 103343171Sdim NewSymbolFile.getBufferIdentifier() + ":" + 104343171Sdim Twine(LineIt.line_number()), 105343171Sdim "later symbol will not be the target of any remappings"); 106343171Sdim } 107343171Sdim } 108343171Sdim 109343171Sdim // Figure out which new symbol each old symbol is equivalent to. 110343171Sdim for (line_iterator LineIt(OldSymbolFile, /*SkipBlanks=*/true, '#'); 111343171Sdim !LineIt.is_at_eof(); ++LineIt) { 112343171Sdim StringRef Symbol = *LineIt; 113343171Sdim 114343171Sdim auto K = Reader.lookup(Symbol); 115343171Sdim StringRef NewSymbol = MappedNames.lookup(K); 116343171Sdim 117343171Sdim if (NewSymbol.empty()) { 118343171Sdim if (WarnIncomplete && !UnparseableSymbols.count(Symbol)) { 119343171Sdim warn("no new symbol matches old symbol " + Symbol, 120343171Sdim OldSymbolFile.getBufferIdentifier() + ":" + 121343171Sdim Twine(LineIt.line_number())); 122343171Sdim } 123343171Sdim continue; 124343171Sdim } 125343171Sdim 126343171Sdim Out << Symbol << " " << NewSymbol << "\n"; 127343171Sdim } 128343171Sdim} 129343171Sdim 130343171Sdimint main(int argc, const char *argv[]) { 131343171Sdim InitLLVM X(argc, argv); 132343171Sdim 133343171Sdim cl::ParseCommandLineOptions(argc, argv, "LLVM C++ mangled name remapper\n"); 134343171Sdim 135343171Sdim auto OldSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(OldSymbolFile); 136343171Sdim if (!OldSymbolBufOrError) 137343171Sdim exitWithErrorCode(OldSymbolBufOrError.getError(), OldSymbolFile); 138343171Sdim 139343171Sdim auto NewSymbolBufOrError = MemoryBuffer::getFileOrSTDIN(NewSymbolFile); 140343171Sdim if (!NewSymbolBufOrError) 141343171Sdim exitWithErrorCode(NewSymbolBufOrError.getError(), NewSymbolFile); 142343171Sdim 143343171Sdim auto RemappingBufOrError = MemoryBuffer::getFileOrSTDIN(RemappingFile); 144343171Sdim if (!RemappingBufOrError) 145343171Sdim exitWithErrorCode(RemappingBufOrError.getError(), RemappingFile); 146343171Sdim 147343171Sdim std::error_code EC; 148360784Sdim raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_Text); 149343171Sdim if (EC) 150343171Sdim exitWithErrorCode(EC, OutputFilename); 151343171Sdim 152343171Sdim remapSymbols(*OldSymbolBufOrError.get(), *NewSymbolBufOrError.get(), 153343171Sdim *RemappingBufOrError.get(), OS); 154343171Sdim} 155