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 9 #include "llvm/ADT/StringExtras.h" 10 #include "llvm/Demangle/Demangle.h" 11 #include "llvm/Demangle/StringViewExtras.h" 12 #include "llvm/Option/Arg.h" 13 #include "llvm/Option/ArgList.h" 14 #include "llvm/Option/Option.h" 15 #include "llvm/Support/CommandLine.h" 16 #include "llvm/Support/LLVMDriver.h" 17 #include "llvm/Support/WithColor.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include "llvm/TargetParser/Host.h" 20 #include "llvm/TargetParser/Triple.h" 21 #include <cstdlib> 22 #include <iostream> 23 24 using namespace llvm; 25 26 namespace { 27 enum ID { 28 OPT_INVALID = 0, // This is not an option ID. 29 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), 30 #include "Opts.inc" 31 #undef OPTION 32 }; 33 34 #define OPTTABLE_STR_TABLE_CODE 35 #include "Opts.inc" 36 #undef OPTTABLE_STR_TABLE_CODE 37 38 #define OPTTABLE_PREFIXES_TABLE_CODE 39 #include "Opts.inc" 40 #undef OPTTABLE_PREFIXES_TABLE_CODE 41 42 using namespace llvm::opt; 43 static constexpr opt::OptTable::Info InfoTable[] = { 44 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), 45 #include "Opts.inc" 46 #undef OPTION 47 }; 48 49 class CxxfiltOptTable : public opt::GenericOptTable { 50 public: 51 CxxfiltOptTable() 52 : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) { 53 setGroupedShortOptions(true); 54 } 55 }; 56 } // namespace 57 58 static bool ParseParams; 59 static bool Quote; 60 static bool StripUnderscore; 61 static bool Types; 62 63 static StringRef ToolName; 64 65 static void error(const Twine &Message) { 66 WithColor::error(errs(), ToolName) << Message << '\n'; 67 exit(1); 68 } 69 70 // Quote Undecorated with "" if asked for and not already followed by a '"'. 71 static std::string optionalQuote(const std::string &Undecorated, 72 StringRef Delimiters) { 73 if (Quote && (Delimiters.empty() || Delimiters[0] != '"')) 74 return '"' + Undecorated + '"'; 75 return Undecorated; 76 } 77 78 static std::string demangle(const std::string &Mangled, StringRef Delimiters) { 79 using llvm::itanium_demangle::starts_with; 80 std::string_view DecoratedStr = Mangled; 81 bool CanHaveLeadingDot = true; 82 if (StripUnderscore && DecoratedStr[0] == '_') { 83 DecoratedStr.remove_prefix(1); 84 CanHaveLeadingDot = false; 85 } 86 87 std::string Result; 88 if (nonMicrosoftDemangle(DecoratedStr, Result, CanHaveLeadingDot, 89 ParseParams)) 90 return optionalQuote(Result, Delimiters); 91 92 std::string Prefix; 93 char *Undecorated = nullptr; 94 95 if (Types) 96 Undecorated = itaniumDemangle(DecoratedStr, ParseParams); 97 98 if (!Undecorated && starts_with(DecoratedStr, "__imp_")) { 99 Prefix = "import thunk for "; 100 Undecorated = itaniumDemangle(DecoratedStr.substr(6), ParseParams); 101 } 102 103 Result = 104 Undecorated ? optionalQuote(Prefix + Undecorated, Delimiters) : Mangled; 105 free(Undecorated); 106 return Result; 107 } 108 109 // Split 'Source' on any character that fails to pass 'IsLegalChar'. The 110 // returned vector consists of pairs where 'first' is the delimited word, and 111 // 'second' are the delimiters following that word. 112 static void SplitStringDelims( 113 StringRef Source, 114 SmallVectorImpl<std::pair<StringRef, StringRef>> &OutFragments, 115 function_ref<bool(char)> IsLegalChar) { 116 // The beginning of the input string. 117 const auto Head = Source.begin(); 118 119 // Obtain any leading delimiters. 120 auto Start = std::find_if(Head, Source.end(), IsLegalChar); 121 if (Start != Head) 122 OutFragments.push_back({"", Source.slice(0, Start - Head)}); 123 124 // Capture each word and the delimiters following that word. 125 while (Start != Source.end()) { 126 Start = std::find_if(Start, Source.end(), IsLegalChar); 127 auto End = std::find_if_not(Start, Source.end(), IsLegalChar); 128 auto DEnd = std::find_if(End, Source.end(), IsLegalChar); 129 OutFragments.push_back({Source.slice(Start - Head, End - Head), 130 Source.slice(End - Head, DEnd - Head)}); 131 Start = DEnd; 132 } 133 } 134 135 // This returns true if 'C' is a character that can show up in an 136 // Itanium-mangled string. 137 static bool IsLegalItaniumChar(char C) { 138 // Itanium CXX ABI [External Names]p5.1.1: 139 // '$' and '.' in mangled names are reserved for private implementations. 140 return isAlnum(C) || C == '.' || C == '$' || C == '_'; 141 } 142 143 // If 'Split' is true, then 'Mangled' is broken into individual words and each 144 // word is demangled. Otherwise, the entire string is treated as a single 145 // mangled item. The result is output to 'OS'. 146 static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) { 147 std::string Result; 148 if (Split) { 149 SmallVector<std::pair<StringRef, StringRef>, 16> Words; 150 SplitStringDelims(Mangled, Words, IsLegalItaniumChar); 151 for (const auto &Word : Words) 152 Result += 153 ::demangle(std::string(Word.first), Word.second) + Word.second.str(); 154 } else 155 Result = ::demangle(std::string(Mangled), ""); 156 OS << Result << '\n'; 157 OS.flush(); 158 } 159 160 int llvm_cxxfilt_main(int argc, char **argv, const llvm::ToolContext &) { 161 BumpPtrAllocator A; 162 StringSaver Saver(A); 163 CxxfiltOptTable Tbl; 164 ToolName = argv[0]; 165 opt::InputArgList Args = Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, 166 [&](StringRef Msg) { error(Msg); }); 167 if (Args.hasArg(OPT_help)) { 168 Tbl.printHelp(outs(), 169 (Twine(ToolName) + " [options] <mangled>").str().c_str(), 170 "LLVM symbol undecoration tool"); 171 // TODO Replace this with OptTable API once it adds extrahelp support. 172 outs() << "\nPass @FILE as argument to read options from FILE.\n"; 173 return 0; 174 } 175 if (Args.hasArg(OPT_version)) { 176 outs() << ToolName << '\n'; 177 cl::PrintVersionMessage(); 178 return 0; 179 } 180 181 StripUnderscore = 182 Args.hasFlag(OPT_strip_underscore, OPT_no_strip_underscore, false); 183 184 ParseParams = !Args.hasArg(OPT_no_params); 185 186 Quote = Args.hasArg(OPT_quote); 187 188 Types = Args.hasArg(OPT_types); 189 190 std::vector<std::string> Decorated = Args.getAllArgValues(OPT_INPUT); 191 if (Decorated.empty()) 192 for (std::string Mangled; std::getline(std::cin, Mangled);) 193 demangleLine(llvm::outs(), Mangled, true); 194 else 195 for (const auto &Symbol : Decorated) 196 demangleLine(llvm::outs(), Symbol, false); 197 198 return EXIT_SUCCESS; 199 } 200