200 lines · cpp
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-exception6//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 24using namespace llvm;25 26namespace {27enum 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 OPTION32};33 34#define OPTTABLE_STR_TABLE_CODE35#include "Opts.inc"36#undef OPTTABLE_STR_TABLE_CODE37 38#define OPTTABLE_PREFIXES_TABLE_CODE39#include "Opts.inc"40#undef OPTTABLE_PREFIXES_TABLE_CODE41 42using namespace llvm::opt;43static constexpr opt::OptTable::Info InfoTable[] = {44#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),45#include "Opts.inc"46#undef OPTION47};48 49class CxxfiltOptTable : public opt::GenericOptTable {50public:51 CxxfiltOptTable()52 : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {53 setGroupedShortOptions(true);54 }55};56} // namespace57 58static bool ParseParams;59static bool Quote;60static bool StripUnderscore;61static bool Types;62 63static StringRef ToolName;64 65static 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 '"'.71static 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 78static 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'. The110// returned vector consists of pairs where 'first' is the delimited word, and111// 'second' are the delimiters following that word.112static 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 an136// Itanium-mangled string.137static 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 each144// word is demangled. Otherwise, the entire string is treated as a single145// mangled item. The result is output to 'OS'.146static 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 } else155 Result = ::demangle(std::string(Mangled), "");156 OS << Result << '\n';157 OS.flush();158}159 160int 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 else195 for (const auto &Symbol : Decorated)196 demangleLine(llvm::outs(), Symbol, false);197 198 return EXIT_SUCCESS;199}200