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