llvm-cxxfilt.cpp 6.5 KB

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