llvm-cxxfilt.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. //===-- llvm-c++filt.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. #include "llvm/ADT/StringExtras.h"
  9. #include "llvm/ADT/Triple.h"
  10. #include "llvm/Demangle/Demangle.h"
  11. #include "llvm/Option/Arg.h"
  12. #include "llvm/Option/ArgList.h"
  13. #include "llvm/Option/Option.h"
  14. #include "llvm/Support/CommandLine.h"
  15. #include "llvm/Support/Host.h"
  16. #include "llvm/Support/InitLLVM.h"
  17. #include "llvm/Support/WithColor.h"
  18. #include "llvm/Support/raw_ostream.h"
  19. #include <cstdlib>
  20. #include <iostream>
  21. using namespace llvm;
  22. namespace {
  23. enum ID {
  24. OPT_INVALID = 0, // This is not an option ID.
  25. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  26. HELPTEXT, METAVAR, VALUES) \
  27. OPT_##ID,
  28. #include "Opts.inc"
  29. #undef OPTION
  30. };
  31. #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
  32. #include "Opts.inc"
  33. #undef PREFIX
  34. const opt::OptTable::Info InfoTable[] = {
  35. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  36. HELPTEXT, METAVAR, VALUES) \
  37. { \
  38. PREFIX, NAME, HELPTEXT, \
  39. METAVAR, OPT_##ID, opt::Option::KIND##Class, \
  40. PARAM, FLAGS, OPT_##GROUP, \
  41. OPT_##ALIAS, ALIASARGS, VALUES},
  42. #include "Opts.inc"
  43. #undef OPTION
  44. };
  45. class CxxfiltOptTable : public opt::OptTable {
  46. public:
  47. CxxfiltOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
  48. };
  49. } // namespace
  50. static bool StripUnderscore;
  51. static bool Types;
  52. static StringRef ToolName;
  53. static void error(const Twine &Message) {
  54. WithColor::error(errs(), ToolName) << Message << '\n';
  55. exit(1);
  56. }
  57. static std::string demangle(const std::string &Mangled) {
  58. const char *DecoratedStr = Mangled.c_str();
  59. if (StripUnderscore)
  60. if (DecoratedStr[0] == '_')
  61. ++DecoratedStr;
  62. std::string Result;
  63. if (nonMicrosoftDemangle(DecoratedStr, Result))
  64. return Result;
  65. std::string Prefix;
  66. char *Undecorated = nullptr;
  67. if (Types)
  68. Undecorated = itaniumDemangle(DecoratedStr, nullptr, nullptr, nullptr);
  69. if (!Undecorated && strncmp(DecoratedStr, "__imp_", 6) == 0) {
  70. Prefix = "import thunk for ";
  71. Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, nullptr);
  72. }
  73. Result = Undecorated ? Prefix + Undecorated : Mangled;
  74. free(Undecorated);
  75. return Result;
  76. }
  77. // Split 'Source' on any character that fails to pass 'IsLegalChar'. The
  78. // returned vector consists of pairs where 'first' is the delimited word, and
  79. // 'second' are the delimiters following that word.
  80. static void SplitStringDelims(
  81. StringRef Source,
  82. SmallVectorImpl<std::pair<StringRef, StringRef>> &OutFragments,
  83. function_ref<bool(char)> IsLegalChar) {
  84. // The beginning of the input string.
  85. const auto Head = Source.begin();
  86. // Obtain any leading delimiters.
  87. auto Start = std::find_if(Head, Source.end(), IsLegalChar);
  88. if (Start != Head)
  89. OutFragments.push_back({"", Source.slice(0, Start - Head)});
  90. // Capture each word and the delimiters following that word.
  91. while (Start != Source.end()) {
  92. Start = std::find_if(Start, Source.end(), IsLegalChar);
  93. auto End = std::find_if_not(Start, Source.end(), IsLegalChar);
  94. auto DEnd = std::find_if(End, Source.end(), IsLegalChar);
  95. OutFragments.push_back({Source.slice(Start - Head, End - Head),
  96. Source.slice(End - Head, DEnd - Head)});
  97. Start = DEnd;
  98. }
  99. }
  100. // This returns true if 'C' is a character that can show up in an
  101. // Itanium-mangled string.
  102. static bool IsLegalItaniumChar(char C) {
  103. // Itanium CXX ABI [External Names]p5.1.1:
  104. // '$' and '.' in mangled names are reserved for private implementations.
  105. return isAlnum(C) || C == '.' || C == '$' || C == '_';
  106. }
  107. // If 'Split' is true, then 'Mangled' is broken into individual words and each
  108. // word is demangled. Otherwise, the entire string is treated as a single
  109. // mangled item. The result is output to 'OS'.
  110. static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) {
  111. std::string Result;
  112. if (Split) {
  113. SmallVector<std::pair<StringRef, StringRef>, 16> Words;
  114. SplitStringDelims(Mangled, Words, IsLegalItaniumChar);
  115. for (const auto &Word : Words)
  116. Result += ::demangle(std::string(Word.first)) + Word.second.str();
  117. } else
  118. Result = ::demangle(std::string(Mangled));
  119. OS << Result << '\n';
  120. OS.flush();
  121. }
  122. int main(int argc, char **argv) {
  123. InitLLVM X(argc, argv);
  124. BumpPtrAllocator A;
  125. StringSaver Saver(A);
  126. CxxfiltOptTable Tbl;
  127. ToolName = argv[0];
  128. opt::InputArgList Args = Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver,
  129. [&](StringRef Msg) { error(Msg); });
  130. if (Args.hasArg(OPT_help)) {
  131. Tbl.printHelp(outs(),
  132. (Twine(ToolName) + " [options] <mangled>").str().c_str(),
  133. "LLVM symbol undecoration tool");
  134. // TODO Replace this with OptTable API once it adds extrahelp support.
  135. outs() << "\nPass @FILE as argument to read options from FILE.\n";
  136. return 0;
  137. }
  138. if (Args.hasArg(OPT_version)) {
  139. outs() << ToolName << '\n';
  140. cl::PrintVersionMessage();
  141. return 0;
  142. }
  143. // The default value depends on the default triple. Mach-O has symbols
  144. // prefixed with "_", so strip by default.
  145. if (opt::Arg *A =
  146. Args.getLastArg(OPT_strip_underscore, OPT_no_strip_underscore))
  147. StripUnderscore = A->getOption().matches(OPT_strip_underscore);
  148. else
  149. StripUnderscore = Triple(sys::getProcessTriple()).isOSBinFormatMachO();
  150. Types = Args.hasArg(OPT_types);
  151. std::vector<std::string> Decorated = Args.getAllArgValues(OPT_INPUT);
  152. if (Decorated.empty())
  153. for (std::string Mangled; std::getline(std::cin, Mangled);)
  154. demangleLine(llvm::outs(), Mangled, true);
  155. else
  156. for (const auto &Symbol : Decorated)
  157. demangleLine(llvm::outs(), Symbol, false);
  158. return EXIT_SUCCESS;
  159. }