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/ADT/Triple.h" 11 #include "llvm/Demangle/Demangle.h" 12 #include "llvm/Support/CommandLine.h" 13 #include "llvm/Support/Host.h" 14 #include "llvm/Support/InitLLVM.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include <cstdlib> 17 #include <iostream> 18 19 using namespace llvm; 20 21 enum Style { 22 Auto, ///< auto-detect mangling 23 GNU, ///< GNU 24 Lucid, ///< Lucid compiler (lcc) 25 ARM, 26 HP, ///< HP compiler (xCC) 27 EDG, ///< EDG compiler 28 GNUv3, ///< GNU C++ v3 ABI 29 Java, ///< Java (gcj) 30 GNAT ///< ADA compiler (gnat) 31 }; 32 static cl::opt<Style> 33 Format("format", cl::desc("decoration style"), 34 cl::values(clEnumValN(Auto, "auto", "auto-detect style"), 35 clEnumValN(GNU, "gnu", "GNU (itanium) style")), 36 cl::init(Auto)); 37 static cl::alias FormatShort("s", cl::desc("alias for --format"), 38 cl::aliasopt(Format)); 39 40 static cl::opt<bool> StripUnderscore("strip-underscore", 41 cl::desc("strip the leading underscore"), 42 cl::init(false)); 43 static cl::alias StripUnderscoreShort("_", 44 cl::desc("alias for --strip-underscore"), 45 cl::aliasopt(StripUnderscore)); 46 static cl::opt<bool> 47 NoStripUnderscore("no-strip-underscore", 48 cl::desc("do not strip the leading underscore"), 49 cl::init(false)); 50 static cl::alias 51 NoStripUnderscoreShort("n", cl::desc("alias for --no-strip-underscore"), 52 cl::aliasopt(NoStripUnderscore)); 53 54 static cl::opt<bool> 55 Types("types", 56 cl::desc("attempt to demangle types as well as function names"), 57 cl::init(false)); 58 static cl::alias TypesShort("t", cl::desc("alias for --types"), 59 cl::aliasopt(Types)); 60 61 static cl::list<std::string> 62 Decorated(cl::Positional, cl::desc("<mangled>"), cl::ZeroOrMore); 63 64 static cl::extrahelp 65 HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); 66 67 static bool shouldStripUnderscore() { 68 if (StripUnderscore) 69 return true; 70 if (NoStripUnderscore) 71 return false; 72 // If none of them are set, use the default value for platform. 73 // macho has symbols prefix with "_" so strip by default. 74 return Triple(sys::getProcessTriple()).isOSBinFormatMachO(); 75 } 76 77 static std::string demangle(const std::string &Mangled) { 78 int Status; 79 std::string Prefix; 80 81 const char *DecoratedStr = Mangled.c_str(); 82 if (shouldStripUnderscore()) 83 if (DecoratedStr[0] == '_') 84 ++DecoratedStr; 85 size_t DecoratedLength = strlen(DecoratedStr); 86 87 char *Undecorated = nullptr; 88 89 if (Types || 90 ((DecoratedLength >= 2 && strncmp(DecoratedStr, "_Z", 2) == 0) || 91 (DecoratedLength >= 4 && strncmp(DecoratedStr, "___Z", 4) == 0))) 92 Undecorated = itaniumDemangle(DecoratedStr, nullptr, nullptr, &Status); 93 94 if (!Undecorated && 95 (DecoratedLength > 6 && strncmp(DecoratedStr, "__imp_", 6) == 0)) { 96 Prefix = "import thunk for "; 97 Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, &Status); 98 } 99 100 std::string Result(Undecorated ? Prefix + Undecorated : Mangled); 101 free(Undecorated); 102 return Result; 103 } 104 105 // Split 'Source' on any character that fails to pass 'IsLegalChar'. The 106 // returned vector consists of pairs where 'first' is the delimited word, and 107 // 'second' are the delimiters following that word. 108 static void SplitStringDelims( 109 StringRef Source, 110 SmallVectorImpl<std::pair<StringRef, StringRef>> &OutFragments, 111 function_ref<bool(char)> IsLegalChar) { 112 // The beginning of the input string. 113 const auto Head = Source.begin(); 114 115 // Obtain any leading delimiters. 116 auto Start = std::find_if(Head, Source.end(), IsLegalChar); 117 if (Start != Head) 118 OutFragments.push_back({"", Source.slice(0, Start - Head)}); 119 120 // Capture each word and the delimiters following that word. 121 while (Start != Source.end()) { 122 Start = std::find_if(Start, Source.end(), IsLegalChar); 123 auto End = std::find_if_not(Start, Source.end(), IsLegalChar); 124 auto DEnd = std::find_if(End, Source.end(), IsLegalChar); 125 OutFragments.push_back({Source.slice(Start - Head, End - Head), 126 Source.slice(End - Head, DEnd - Head)}); 127 Start = DEnd; 128 } 129 } 130 131 // This returns true if 'C' is a character that can show up in an 132 // Itanium-mangled string. 133 static bool IsLegalItaniumChar(char C) { 134 // Itanium CXX ABI [External Names]p5.1.1: 135 // '$' and '.' in mangled names are reserved for private implementations. 136 return isalnum(C) || C == '.' || C == '$' || C == '_'; 137 } 138 139 // If 'Split' is true, then 'Mangled' is broken into individual words and each 140 // word is demangled. Otherwise, the entire string is treated as a single 141 // mangled item. The result is output to 'OS'. 142 static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) { 143 std::string Result; 144 if (Split) { 145 SmallVector<std::pair<StringRef, StringRef>, 16> Words; 146 SplitStringDelims(Mangled, Words, IsLegalItaniumChar); 147 for (const auto &Word : Words) 148 Result += ::demangle(std::string(Word.first)) + Word.second.str(); 149 } else 150 Result = ::demangle(std::string(Mangled)); 151 OS << Result << '\n'; 152 OS.flush(); 153 } 154 155 int main(int argc, char **argv) { 156 InitLLVM X(argc, argv); 157 158 cl::ParseCommandLineOptions(argc, argv, "llvm symbol undecoration tool\n"); 159 160 if (Decorated.empty()) 161 for (std::string Mangled; std::getline(std::cin, Mangled);) 162 demangleLine(llvm::outs(), Mangled, true); 163 else 164 for (const auto &Symbol : Decorated) 165 demangleLine(llvm::outs(), Symbol, false); 166 167 return EXIT_SUCCESS; 168 } 169