1311116Sdim//===-- llvm-c++filt.cpp --------------------------------------------------===// 2311116Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6311116Sdim// 7311116Sdim//===----------------------------------------------------------------------===// 8311116Sdim 9353358Sdim#include "llvm/ADT/StringExtras.h" 10360784Sdim#include "llvm/ADT/Triple.h" 11311116Sdim#include "llvm/Demangle/Demangle.h" 12321369Sdim#include "llvm/Support/CommandLine.h" 13360784Sdim#include "llvm/Support/Host.h" 14341825Sdim#include "llvm/Support/InitLLVM.h" 15311116Sdim#include "llvm/Support/raw_ostream.h" 16311116Sdim#include <cstdlib> 17311116Sdim#include <iostream> 18311116Sdim 19311116Sdimusing namespace llvm; 20311116Sdim 21321369Sdimenum Style { 22321369Sdim Auto, ///< auto-detect mangling 23321369Sdim GNU, ///< GNU 24321369Sdim Lucid, ///< Lucid compiler (lcc) 25321369Sdim ARM, 26321369Sdim HP, ///< HP compiler (xCC) 27321369Sdim EDG, ///< EDG compiler 28321369Sdim GNUv3, ///< GNU C++ v3 ABI 29321369Sdim Java, ///< Java (gcj) 30353358Sdim GNAT ///< ADA compiler (gnat) 31321369Sdim}; 32321369Sdimstatic cl::opt<Style> 33321369Sdim Format("format", cl::desc("decoration style"), 34321369Sdim cl::values(clEnumValN(Auto, "auto", "auto-detect style"), 35321369Sdim clEnumValN(GNU, "gnu", "GNU (itanium) style")), 36321369Sdim cl::init(Auto)); 37321369Sdimstatic cl::alias FormatShort("s", cl::desc("alias for --format"), 38321369Sdim cl::aliasopt(Format)); 39321369Sdim 40321369Sdimstatic cl::opt<bool> StripUnderscore("strip-underscore", 41321369Sdim cl::desc("strip the leading underscore"), 42321369Sdim cl::init(false)); 43321369Sdimstatic cl::alias StripUnderscoreShort("_", 44321369Sdim cl::desc("alias for --strip-underscore"), 45321369Sdim cl::aliasopt(StripUnderscore)); 46360784Sdimstatic cl::opt<bool> 47360784Sdim NoStripUnderscore("no-strip-underscore", 48360784Sdim cl::desc("do not strip the leading underscore"), 49360784Sdim cl::init(false)); 50360784Sdimstatic cl::alias 51360784Sdim NoStripUnderscoreShort("n", cl::desc("alias for --no-strip-underscore"), 52360784Sdim cl::aliasopt(NoStripUnderscore)); 53321369Sdim 54321369Sdimstatic cl::opt<bool> 55321369Sdim Types("types", 56321369Sdim cl::desc("attempt to demangle types as well as function names"), 57321369Sdim cl::init(false)); 58321369Sdimstatic cl::alias TypesShort("t", cl::desc("alias for --types"), 59321369Sdim cl::aliasopt(Types)); 60321369Sdim 61321369Sdimstatic cl::list<std::string> 62321369SdimDecorated(cl::Positional, cl::desc("<mangled>"), cl::ZeroOrMore); 63321369Sdim 64353358Sdimstatic cl::extrahelp 65353358Sdim HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); 66353358Sdim 67360784Sdimstatic bool shouldStripUnderscore() { 68360784Sdim if (StripUnderscore) 69360784Sdim return true; 70360784Sdim if (NoStripUnderscore) 71360784Sdim return false; 72360784Sdim // If none of them are set, use the default value for platform. 73360784Sdim // macho has symbols prefix with "_" so strip by default. 74360784Sdim return Triple(sys::getProcessTriple()).isOSBinFormatMachO(); 75360784Sdim} 76360784Sdim 77360784Sdimstatic std::string demangle(const std::string &Mangled) { 78311116Sdim int Status; 79360784Sdim std::string Prefix; 80321369Sdim 81353358Sdim const char *DecoratedStr = Mangled.c_str(); 82360784Sdim if (shouldStripUnderscore()) 83353358Sdim if (DecoratedStr[0] == '_') 84353358Sdim ++DecoratedStr; 85353358Sdim size_t DecoratedLength = strlen(DecoratedStr); 86321369Sdim 87321369Sdim char *Undecorated = nullptr; 88321369Sdim 89353358Sdim if (Types || 90353358Sdim ((DecoratedLength >= 2 && strncmp(DecoratedStr, "_Z", 2) == 0) || 91353358Sdim (DecoratedLength >= 4 && strncmp(DecoratedStr, "___Z", 4) == 0))) 92353358Sdim Undecorated = itaniumDemangle(DecoratedStr, nullptr, nullptr, &Status); 93321369Sdim 94321369Sdim if (!Undecorated && 95353358Sdim (DecoratedLength > 6 && strncmp(DecoratedStr, "__imp_", 6) == 0)) { 96360784Sdim Prefix = "import thunk for "; 97353358Sdim Undecorated = itaniumDemangle(DecoratedStr + 6, nullptr, nullptr, &Status); 98321369Sdim } 99321369Sdim 100360784Sdim std::string Result(Undecorated ? Prefix + Undecorated : Mangled); 101321369Sdim free(Undecorated); 102353358Sdim return Result; 103311116Sdim} 104311116Sdim 105353358Sdim// Split 'Source' on any character that fails to pass 'IsLegalChar'. The 106353358Sdim// returned vector consists of pairs where 'first' is the delimited word, and 107353358Sdim// 'second' are the delimiters following that word. 108353358Sdimstatic void SplitStringDelims( 109353358Sdim StringRef Source, 110353358Sdim SmallVectorImpl<std::pair<StringRef, StringRef>> &OutFragments, 111353358Sdim function_ref<bool(char)> IsLegalChar) { 112353358Sdim // The beginning of the input string. 113353358Sdim const auto Head = Source.begin(); 114353358Sdim 115353358Sdim // Obtain any leading delimiters. 116353358Sdim auto Start = std::find_if(Head, Source.end(), IsLegalChar); 117353358Sdim if (Start != Head) 118353358Sdim OutFragments.push_back({"", Source.slice(0, Start - Head)}); 119353358Sdim 120353358Sdim // Capture each word and the delimiters following that word. 121353358Sdim while (Start != Source.end()) { 122353358Sdim Start = std::find_if(Start, Source.end(), IsLegalChar); 123353358Sdim auto End = std::find_if_not(Start, Source.end(), IsLegalChar); 124353358Sdim auto DEnd = std::find_if(End, Source.end(), IsLegalChar); 125353358Sdim OutFragments.push_back({Source.slice(Start - Head, End - Head), 126353358Sdim Source.slice(End - Head, DEnd - Head)}); 127353358Sdim Start = DEnd; 128353358Sdim } 129353358Sdim} 130353358Sdim 131353358Sdim// This returns true if 'C' is a character that can show up in an 132353358Sdim// Itanium-mangled string. 133353358Sdimstatic bool IsLegalItaniumChar(char C) { 134353358Sdim // Itanium CXX ABI [External Names]p5.1.1: 135353358Sdim // '$' and '.' in mangled names are reserved for private implementations. 136353358Sdim return isalnum(C) || C == '.' || C == '$' || C == '_'; 137353358Sdim} 138353358Sdim 139353358Sdim// If 'Split' is true, then 'Mangled' is broken into individual words and each 140353358Sdim// word is demangled. Otherwise, the entire string is treated as a single 141353358Sdim// mangled item. The result is output to 'OS'. 142353358Sdimstatic void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) { 143353358Sdim std::string Result; 144353358Sdim if (Split) { 145353358Sdim SmallVector<std::pair<StringRef, StringRef>, 16> Words; 146353358Sdim SplitStringDelims(Mangled, Words, IsLegalItaniumChar); 147353358Sdim for (const auto &Word : Words) 148360784Sdim Result += ::demangle(Word.first) + Word.second.str(); 149353358Sdim } else 150360784Sdim Result = ::demangle(Mangled); 151353358Sdim OS << Result << '\n'; 152353358Sdim OS.flush(); 153353358Sdim} 154353358Sdim 155311116Sdimint main(int argc, char **argv) { 156341825Sdim InitLLVM X(argc, argv); 157321369Sdim 158321369Sdim cl::ParseCommandLineOptions(argc, argv, "llvm symbol undecoration tool\n"); 159321369Sdim 160321369Sdim if (Decorated.empty()) 161311116Sdim for (std::string Mangled; std::getline(std::cin, Mangled);) 162353358Sdim demangleLine(llvm::outs(), Mangled, true); 163311116Sdim else 164321369Sdim for (const auto &Symbol : Decorated) 165353358Sdim demangleLine(llvm::outs(), Symbol, false); 166311116Sdim 167311116Sdim return EXIT_SUCCESS; 168311116Sdim} 169