llvm-cxxmap.cpp 5.4 KB

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