122a1aa5aSLuís Ferreira //===--- DLangDemangle.cpp ------------------------------------------------===//
222a1aa5aSLuís Ferreira //
322a1aa5aSLuís Ferreira // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422a1aa5aSLuís Ferreira // See https://llvm.org/LICENSE.txt for license information.
522a1aa5aSLuís Ferreira // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
622a1aa5aSLuís Ferreira //
722a1aa5aSLuís Ferreira //===----------------------------------------------------------------------===//
822a1aa5aSLuís Ferreira ///
922a1aa5aSLuís Ferreira /// \file
1022a1aa5aSLuís Ferreira /// This file defines a demangler for the D programming language as specified
1122a1aa5aSLuís Ferreira /// in the ABI specification, available at:
1222a1aa5aSLuís Ferreira /// https://dlang.org/spec/abi.html#name_mangling
1322a1aa5aSLuís Ferreira ///
1422a1aa5aSLuís Ferreira //===----------------------------------------------------------------------===//
1522a1aa5aSLuís Ferreira
1622a1aa5aSLuís Ferreira #include "llvm/Demangle/Demangle.h"
17f5371eb3SNick Desaulniers #include "llvm/Demangle/StringViewExtras.h"
1822a1aa5aSLuís Ferreira #include "llvm/Demangle/Utility.h"
1922a1aa5aSLuís Ferreira
20bd4c6a47SDavid Blaikie #include <cctype>
2122a1aa5aSLuís Ferreira #include <cstring>
22e63c799aSDavid Blaikie #include <limits>
23*86b6ac5dSNick Desaulniers #include <string_view>
2422a1aa5aSLuís Ferreira
2522a1aa5aSLuís Ferreira using namespace llvm;
2622a1aa5aSLuís Ferreira using llvm::itanium_demangle::OutputBuffer;
27f5371eb3SNick Desaulniers using llvm::itanium_demangle::starts_with;
28e63c799aSDavid Blaikie
29e63c799aSDavid Blaikie namespace {
30e63c799aSDavid Blaikie
31e63c799aSDavid Blaikie /// Demangle information structure.
32e63c799aSDavid Blaikie struct Demangler {
33e63c799aSDavid Blaikie /// Initialize the information structure we use to pass around information.
34e63c799aSDavid Blaikie ///
35e63c799aSDavid Blaikie /// \param Mangled String to demangle.
36*86b6ac5dSNick Desaulniers Demangler(std::string_view Mangled);
37e63c799aSDavid Blaikie
38e63c799aSDavid Blaikie /// Extract and demangle the mangled symbol and append it to the output
39e63c799aSDavid Blaikie /// string.
40e63c799aSDavid Blaikie ///
41e63c799aSDavid Blaikie /// \param Demangled Output buffer to write the demangled name.
42e63c799aSDavid Blaikie ///
43e63c799aSDavid Blaikie /// \return The remaining string on success or nullptr on failure.
44e63c799aSDavid Blaikie ///
45e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#name_mangling .
46e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#MangledName .
47e63c799aSDavid Blaikie const char *parseMangle(OutputBuffer *Demangled);
48e63c799aSDavid Blaikie
49e63c799aSDavid Blaikie private:
50e63c799aSDavid Blaikie /// Extract and demangle a given mangled symbol and append it to the output
51e63c799aSDavid Blaikie /// string.
52e63c799aSDavid Blaikie ///
53e63c799aSDavid Blaikie /// \param Demangled output buffer to write the demangled name.
54e63c799aSDavid Blaikie /// \param Mangled mangled symbol to be demangled.
55e63c799aSDavid Blaikie ///
56e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#name_mangling .
57e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#MangledName .
58*86b6ac5dSNick Desaulniers void parseMangle(OutputBuffer *Demangled, std::string_view &Mangled);
59e63c799aSDavid Blaikie
60e63c799aSDavid Blaikie /// Extract the number from a given string.
61e63c799aSDavid Blaikie ///
62e63c799aSDavid Blaikie /// \param Mangled string to extract the number.
63e63c799aSDavid Blaikie /// \param Ret assigned result value.
64e63c799aSDavid Blaikie ///
65*86b6ac5dSNick Desaulniers /// \note Ret larger than UINT_MAX is considered a failure.
66e63c799aSDavid Blaikie ///
67e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#Number .
68*86b6ac5dSNick Desaulniers void decodeNumber(std::string_view &Mangled, unsigned long &Ret);
69e63c799aSDavid Blaikie
70bec08795SLuís Ferreira /// Extract the back reference position from a given string.
71bec08795SLuís Ferreira ///
72bec08795SLuís Ferreira /// \param Mangled string to extract the back reference position.
73bec08795SLuís Ferreira /// \param Ret assigned result value.
74bec08795SLuís Ferreira ///
75*86b6ac5dSNick Desaulniers /// \return true on success, false on error.
76bec08795SLuís Ferreira ///
77bec08795SLuís Ferreira /// \note Ret is always >= 0 on success, and unspecified on failure
78bec08795SLuís Ferreira ///
79bec08795SLuís Ferreira /// \see https://dlang.org/spec/abi.html#back_ref .
80bec08795SLuís Ferreira /// \see https://dlang.org/spec/abi.html#NumberBackRef .
81*86b6ac5dSNick Desaulniers bool decodeBackrefPos(std::string_view &Mangled, long &Ret);
82bec08795SLuís Ferreira
83bec08795SLuís Ferreira /// Extract the symbol pointed by the back reference form a given string.
84bec08795SLuís Ferreira ///
85bec08795SLuís Ferreira /// \param Mangled string to extract the back reference position.
86bec08795SLuís Ferreira /// \param Ret assigned result value.
87bec08795SLuís Ferreira ///
88*86b6ac5dSNick Desaulniers /// \return true on success, false on error.
89bec08795SLuís Ferreira ///
90bec08795SLuís Ferreira /// \see https://dlang.org/spec/abi.html#back_ref .
91*86b6ac5dSNick Desaulniers bool decodeBackref(std::string_view &Mangled, std::string_view &Ret);
92bec08795SLuís Ferreira
93bec08795SLuís Ferreira /// Extract and demangle backreferenced symbol from a given mangled symbol
94bec08795SLuís Ferreira /// and append it to the output string.
95bec08795SLuís Ferreira ///
96bec08795SLuís Ferreira /// \param Demangled output buffer to write the demangled name.
97bec08795SLuís Ferreira /// \param Mangled mangled symbol to be demangled.
98bec08795SLuís Ferreira ///
99bec08795SLuís Ferreira /// \see https://dlang.org/spec/abi.html#back_ref .
100bec08795SLuís Ferreira /// \see https://dlang.org/spec/abi.html#IdentifierBackRef .
101*86b6ac5dSNick Desaulniers void parseSymbolBackref(OutputBuffer *Demangled, std::string_view &Mangled);
102bec08795SLuís Ferreira
103b21ea1c2SLuís Ferreira /// Extract and demangle backreferenced type from a given mangled symbol
104b21ea1c2SLuís Ferreira /// and append it to the output string.
105b21ea1c2SLuís Ferreira ///
106b21ea1c2SLuís Ferreira /// \param Mangled mangled symbol to be demangled.
107b21ea1c2SLuís Ferreira ///
108b21ea1c2SLuís Ferreira /// \see https://dlang.org/spec/abi.html#back_ref .
109b21ea1c2SLuís Ferreira /// \see https://dlang.org/spec/abi.html#TypeBackRef .
110*86b6ac5dSNick Desaulniers void parseTypeBackref(std::string_view &Mangled);
111b21ea1c2SLuís Ferreira
1126e08abdcSDavid Blaikie /// Check whether it is the beginning of a symbol name.
1136e08abdcSDavid Blaikie ///
1146e08abdcSDavid Blaikie /// \param Mangled string to extract the symbol name.
1156e08abdcSDavid Blaikie ///
1166e08abdcSDavid Blaikie /// \return true on success, false otherwise.
1176e08abdcSDavid Blaikie ///
1186e08abdcSDavid Blaikie /// \see https://dlang.org/spec/abi.html#SymbolName .
119*86b6ac5dSNick Desaulniers bool isSymbolName(std::string_view Mangled);
1206e08abdcSDavid Blaikie
121e63c799aSDavid Blaikie /// Extract and demangle an identifier from a given mangled symbol append it
122e63c799aSDavid Blaikie /// to the output string.
123e63c799aSDavid Blaikie ///
124e63c799aSDavid Blaikie /// \param Demangled Output buffer to write the demangled name.
125e63c799aSDavid Blaikie /// \param Mangled Mangled symbol to be demangled.
126e63c799aSDavid Blaikie ///
127e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#SymbolName .
128*86b6ac5dSNick Desaulniers void parseIdentifier(OutputBuffer *Demangled, std::string_view &Mangled);
129e63c799aSDavid Blaikie
130e63c799aSDavid Blaikie /// Extract and demangle the plain identifier from a given mangled symbol and
131e63c799aSDavid Blaikie /// prepend/append it to the output string, with a special treatment for some
132e63c799aSDavid Blaikie /// magic compiler generated symbols.
133e63c799aSDavid Blaikie ///
134e63c799aSDavid Blaikie /// \param Demangled Output buffer to write the demangled name.
135e63c799aSDavid Blaikie /// \param Mangled Mangled symbol to be demangled.
136e63c799aSDavid Blaikie /// \param Len Length of the mangled symbol name.
137e63c799aSDavid Blaikie ///
138e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#LName .
139*86b6ac5dSNick Desaulniers void parseLName(OutputBuffer *Demangled, std::string_view &Mangled,
140e63c799aSDavid Blaikie unsigned long Len);
141e63c799aSDavid Blaikie
142e63c799aSDavid Blaikie /// Extract and demangle the qualified symbol from a given mangled symbol
143e63c799aSDavid Blaikie /// append it to the output string.
144e63c799aSDavid Blaikie ///
145e63c799aSDavid Blaikie /// \param Demangled Output buffer to write the demangled name.
146e63c799aSDavid Blaikie /// \param Mangled Mangled symbol to be demangled.
147e63c799aSDavid Blaikie ///
148e63c799aSDavid Blaikie /// \see https://dlang.org/spec/abi.html#QualifiedName .
149*86b6ac5dSNick Desaulniers void parseQualified(OutputBuffer *Demangled, std::string_view &Mangled);
150e63c799aSDavid Blaikie
151669bfcf0SLuís Ferreira /// Extract and demangle a type from a given mangled symbol append it to
152669bfcf0SLuís Ferreira /// the output string.
153669bfcf0SLuís Ferreira ///
154669bfcf0SLuís Ferreira /// \param Mangled mangled symbol to be demangled.
155669bfcf0SLuís Ferreira ///
156*86b6ac5dSNick Desaulniers /// \return true on success, false on error.
157669bfcf0SLuís Ferreira ///
158669bfcf0SLuís Ferreira /// \see https://dlang.org/spec/abi.html#Type .
159*86b6ac5dSNick Desaulniers bool parseType(std::string_view &Mangled);
160669bfcf0SLuís Ferreira
161*86b6ac5dSNick Desaulniers /// An immutable view of the string we are demangling.
162*86b6ac5dSNick Desaulniers const std::string_view Str;
163b21ea1c2SLuís Ferreira /// The index of the last back reference.
164b21ea1c2SLuís Ferreira int LastBackref;
165e63c799aSDavid Blaikie };
166e63c799aSDavid Blaikie
167e63c799aSDavid Blaikie } // namespace
168e63c799aSDavid Blaikie
decodeNumber(std::string_view & Mangled,unsigned long & Ret)169*86b6ac5dSNick Desaulniers void Demangler::decodeNumber(std::string_view &Mangled, unsigned long &Ret) {
170*86b6ac5dSNick Desaulniers // Clear Mangled if trying to extract something that isn't a digit.
171*86b6ac5dSNick Desaulniers if (Mangled.empty()) {
172*86b6ac5dSNick Desaulniers Mangled = {};
173*86b6ac5dSNick Desaulniers return;
174*86b6ac5dSNick Desaulniers }
175*86b6ac5dSNick Desaulniers
176*86b6ac5dSNick Desaulniers if (!std::isdigit(Mangled.front())) {
177*86b6ac5dSNick Desaulniers Mangled = {};
178*86b6ac5dSNick Desaulniers return;
179*86b6ac5dSNick Desaulniers }
180e63c799aSDavid Blaikie
181e63c799aSDavid Blaikie unsigned long Val = 0;
182e63c799aSDavid Blaikie
183e63c799aSDavid Blaikie do {
184e63c799aSDavid Blaikie unsigned long Digit = Mangled[0] - '0';
185e63c799aSDavid Blaikie
186e63c799aSDavid Blaikie // Check for overflow.
187*86b6ac5dSNick Desaulniers if (Val > (std::numeric_limits<unsigned int>::max() - Digit) / 10) {
188*86b6ac5dSNick Desaulniers Mangled = {};
189*86b6ac5dSNick Desaulniers return;
190e63c799aSDavid Blaikie }
191e63c799aSDavid Blaikie
192*86b6ac5dSNick Desaulniers Val = Val * 10 + Digit;
193*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
194*86b6ac5dSNick Desaulniers } while (!Mangled.empty() && std::isdigit(Mangled.front()));
195bec08795SLuís Ferreira
196*86b6ac5dSNick Desaulniers if (Mangled.empty()) {
197*86b6ac5dSNick Desaulniers Mangled = {};
198*86b6ac5dSNick Desaulniers return;
199*86b6ac5dSNick Desaulniers }
200*86b6ac5dSNick Desaulniers
201*86b6ac5dSNick Desaulniers Ret = Val;
202*86b6ac5dSNick Desaulniers }
203*86b6ac5dSNick Desaulniers
decodeBackrefPos(std::string_view & Mangled,long & Ret)204*86b6ac5dSNick Desaulniers bool Demangler::decodeBackrefPos(std::string_view &Mangled, long &Ret) {
205*86b6ac5dSNick Desaulniers // Return nullptr if trying to extract something that isn't a digit
206*86b6ac5dSNick Desaulniers if (Mangled.empty()) {
207*86b6ac5dSNick Desaulniers Mangled = {};
208*86b6ac5dSNick Desaulniers return false;
209*86b6ac5dSNick Desaulniers }
210bec08795SLuís Ferreira // Any identifier or non-basic type that has been emitted to the mangled
211bec08795SLuís Ferreira // symbol before will not be emitted again, but is referenced by a special
212bec08795SLuís Ferreira // sequence encoding the relative position of the original occurrence in the
213bec08795SLuís Ferreira // mangled symbol name.
214bec08795SLuís Ferreira // Numbers in back references are encoded with base 26 by upper case letters
215bec08795SLuís Ferreira // A-Z for higher digits but lower case letters a-z for the last digit.
216bec08795SLuís Ferreira // NumberBackRef:
217bec08795SLuís Ferreira // [a-z]
218bec08795SLuís Ferreira // [A-Z] NumberBackRef
219bec08795SLuís Ferreira // ^
220bec08795SLuís Ferreira unsigned long Val = 0;
221bec08795SLuís Ferreira
222*86b6ac5dSNick Desaulniers while (!Mangled.empty() && std::isalpha(Mangled.front())) {
223bec08795SLuís Ferreira // Check for overflow
224bec08795SLuís Ferreira if (Val > (std::numeric_limits<unsigned long>::max() - 25) / 26)
225bec08795SLuís Ferreira break;
226bec08795SLuís Ferreira
227bec08795SLuís Ferreira Val *= 26;
228bec08795SLuís Ferreira
229bec08795SLuís Ferreira if (Mangled[0] >= 'a' && Mangled[0] <= 'z') {
230bec08795SLuís Ferreira Val += Mangled[0] - 'a';
231bec08795SLuís Ferreira if ((long)Val <= 0)
232bec08795SLuís Ferreira break;
233bec08795SLuís Ferreira Ret = Val;
234*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
235*86b6ac5dSNick Desaulniers return true;
236bec08795SLuís Ferreira }
237bec08795SLuís Ferreira
238bec08795SLuís Ferreira Val += Mangled[0] - 'A';
239*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
240bec08795SLuís Ferreira }
241bec08795SLuís Ferreira
242*86b6ac5dSNick Desaulniers Mangled = {};
243*86b6ac5dSNick Desaulniers return false;
244bec08795SLuís Ferreira }
245bec08795SLuís Ferreira
decodeBackref(std::string_view & Mangled,std::string_view & Ret)246*86b6ac5dSNick Desaulniers bool Demangler::decodeBackref(std::string_view &Mangled,
247*86b6ac5dSNick Desaulniers std::string_view &Ret) {
248*86b6ac5dSNick Desaulniers assert(!Mangled.empty() && Mangled.front() == 'Q' &&
249*86b6ac5dSNick Desaulniers "Invalid back reference!");
250*86b6ac5dSNick Desaulniers Ret = {};
251bec08795SLuís Ferreira
252bec08795SLuís Ferreira // Position of 'Q'
253*86b6ac5dSNick Desaulniers const char *Qpos = Mangled.data();
254bec08795SLuís Ferreira long RefPos;
255*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
256bec08795SLuís Ferreira
257*86b6ac5dSNick Desaulniers if (!decodeBackrefPos(Mangled, RefPos)) {
258*86b6ac5dSNick Desaulniers Mangled = {};
259*86b6ac5dSNick Desaulniers return false;
260*86b6ac5dSNick Desaulniers }
261bec08795SLuís Ferreira
262*86b6ac5dSNick Desaulniers if (RefPos > Qpos - Str.data()) {
263*86b6ac5dSNick Desaulniers Mangled = {};
264*86b6ac5dSNick Desaulniers return false;
265*86b6ac5dSNick Desaulniers }
266bec08795SLuís Ferreira
267bec08795SLuís Ferreira // Set the position of the back reference.
268bec08795SLuís Ferreira Ret = Qpos - RefPos;
269bec08795SLuís Ferreira
270*86b6ac5dSNick Desaulniers return true;
271bec08795SLuís Ferreira }
272bec08795SLuís Ferreira
parseSymbolBackref(OutputBuffer * Demangled,std::string_view & Mangled)273*86b6ac5dSNick Desaulniers void Demangler::parseSymbolBackref(OutputBuffer *Demangled,
274*86b6ac5dSNick Desaulniers std::string_view &Mangled) {
275bec08795SLuís Ferreira // An identifier back reference always points to a digit 0 to 9.
276bec08795SLuís Ferreira // IdentifierBackRef:
277bec08795SLuís Ferreira // Q NumberBackRef
278bec08795SLuís Ferreira // ^
279bec08795SLuís Ferreira unsigned long Len;
280bec08795SLuís Ferreira
281bec08795SLuís Ferreira // Get position of the back reference
282*86b6ac5dSNick Desaulniers std::string_view Backref;
283*86b6ac5dSNick Desaulniers if (!decodeBackref(Mangled, Backref)) {
284*86b6ac5dSNick Desaulniers Mangled = {};
285*86b6ac5dSNick Desaulniers return;
286bec08795SLuís Ferreira }
287bec08795SLuís Ferreira
288*86b6ac5dSNick Desaulniers // Must point to a simple identifier
289*86b6ac5dSNick Desaulniers decodeNumber(Backref, Len);
290*86b6ac5dSNick Desaulniers if (Backref.empty() || Backref.length() < Len) {
291*86b6ac5dSNick Desaulniers Mangled = {};
292*86b6ac5dSNick Desaulniers return;
293*86b6ac5dSNick Desaulniers }
294*86b6ac5dSNick Desaulniers
295*86b6ac5dSNick Desaulniers parseLName(Demangled, Backref, Len);
296*86b6ac5dSNick Desaulniers if (Backref.empty())
297*86b6ac5dSNick Desaulniers Mangled = {};
298*86b6ac5dSNick Desaulniers }
299*86b6ac5dSNick Desaulniers
parseTypeBackref(std::string_view & Mangled)300*86b6ac5dSNick Desaulniers void Demangler::parseTypeBackref(std::string_view &Mangled) {
301b21ea1c2SLuís Ferreira // A type back reference always points to a letter.
302b21ea1c2SLuís Ferreira // TypeBackRef:
303b21ea1c2SLuís Ferreira // Q NumberBackRef
304b21ea1c2SLuís Ferreira // ^
305b21ea1c2SLuís Ferreira
306b21ea1c2SLuís Ferreira // If we appear to be moving backwards through the mangle string, then
307b21ea1c2SLuís Ferreira // bail as this may be a recursive back reference.
308*86b6ac5dSNick Desaulniers if (Mangled.data() - Str.data() >= LastBackref) {
309*86b6ac5dSNick Desaulniers Mangled = {};
310*86b6ac5dSNick Desaulniers return;
311*86b6ac5dSNick Desaulniers }
312b21ea1c2SLuís Ferreira
313b21ea1c2SLuís Ferreira int SaveRefPos = LastBackref;
314*86b6ac5dSNick Desaulniers LastBackref = Mangled.data() - Str.data();
315b21ea1c2SLuís Ferreira
316b21ea1c2SLuís Ferreira // Get position of the back reference.
317*86b6ac5dSNick Desaulniers std::string_view Backref;
318*86b6ac5dSNick Desaulniers if (!decodeBackref(Mangled, Backref)) {
319*86b6ac5dSNick Desaulniers Mangled = {};
320*86b6ac5dSNick Desaulniers return;
321*86b6ac5dSNick Desaulniers }
322b21ea1c2SLuís Ferreira
323b21ea1c2SLuís Ferreira // Can't decode back reference.
324*86b6ac5dSNick Desaulniers if (Backref.empty()) {
325*86b6ac5dSNick Desaulniers Mangled = {};
326*86b6ac5dSNick Desaulniers return;
327*86b6ac5dSNick Desaulniers }
328b21ea1c2SLuís Ferreira
329b21ea1c2SLuís Ferreira // TODO: Add support for function type back references.
330*86b6ac5dSNick Desaulniers if (!parseType(Backref))
331*86b6ac5dSNick Desaulniers Mangled = {};
332b21ea1c2SLuís Ferreira
333b21ea1c2SLuís Ferreira LastBackref = SaveRefPos;
334b21ea1c2SLuís Ferreira
335*86b6ac5dSNick Desaulniers if (Backref.empty())
336*86b6ac5dSNick Desaulniers Mangled = {};
337b21ea1c2SLuís Ferreira }
338b21ea1c2SLuís Ferreira
isSymbolName(std::string_view Mangled)339*86b6ac5dSNick Desaulniers bool Demangler::isSymbolName(std::string_view Mangled) {
340bec08795SLuís Ferreira long Ret;
341*86b6ac5dSNick Desaulniers const char *Qref = Mangled.data();
342bec08795SLuís Ferreira
343*86b6ac5dSNick Desaulniers if (std::isdigit(Mangled.front()))
3446e08abdcSDavid Blaikie return true;
3456e08abdcSDavid Blaikie
346bec08795SLuís Ferreira // TODO: Handle template instances.
347bec08795SLuís Ferreira
348*86b6ac5dSNick Desaulniers if (Mangled.front() != 'Q')
3496e08abdcSDavid Blaikie return false;
350bec08795SLuís Ferreira
351*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
352*86b6ac5dSNick Desaulniers bool Valid = decodeBackrefPos(Mangled, Ret);
353*86b6ac5dSNick Desaulniers if (!Valid || Ret > Qref - Str.data())
354bec08795SLuís Ferreira return false;
355bec08795SLuís Ferreira
356bec08795SLuís Ferreira return std::isdigit(Qref[-Ret]);
3576e08abdcSDavid Blaikie }
3586e08abdcSDavid Blaikie
parseMangle(OutputBuffer * Demangled,std::string_view & Mangled)359*86b6ac5dSNick Desaulniers void Demangler::parseMangle(OutputBuffer *Demangled,
360*86b6ac5dSNick Desaulniers std::string_view &Mangled) {
361e63c799aSDavid Blaikie // A D mangled symbol is comprised of both scope and type information.
362e63c799aSDavid Blaikie // MangleName:
363e63c799aSDavid Blaikie // _D QualifiedName Type
364e63c799aSDavid Blaikie // _D QualifiedName Z
365e63c799aSDavid Blaikie // ^
366e63c799aSDavid Blaikie // The caller should have guaranteed that the start pointer is at the
367e63c799aSDavid Blaikie // above location.
368e63c799aSDavid Blaikie // Note that type is never a function type, but only the return type of
369e63c799aSDavid Blaikie // a function or the type of a variable.
370*86b6ac5dSNick Desaulniers Mangled.remove_prefix(2);
371e63c799aSDavid Blaikie
372*86b6ac5dSNick Desaulniers parseQualified(Demangled, Mangled);
373e63c799aSDavid Blaikie
374*86b6ac5dSNick Desaulniers if (Mangled.empty()) {
375*86b6ac5dSNick Desaulniers Mangled = {};
376*86b6ac5dSNick Desaulniers return;
377*86b6ac5dSNick Desaulniers }
378*86b6ac5dSNick Desaulniers
379e63c799aSDavid Blaikie // Artificial symbols end with 'Z' and have no type.
380*86b6ac5dSNick Desaulniers if (Mangled.front() == 'Z') {
381*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
382*86b6ac5dSNick Desaulniers } else if (!parseType(Mangled))
383*86b6ac5dSNick Desaulniers Mangled = {};
384e63c799aSDavid Blaikie }
385e63c799aSDavid Blaikie
parseQualified(OutputBuffer * Demangled,std::string_view & Mangled)386*86b6ac5dSNick Desaulniers void Demangler::parseQualified(OutputBuffer *Demangled,
387*86b6ac5dSNick Desaulniers std::string_view &Mangled) {
388e63c799aSDavid Blaikie // Qualified names are identifiers separated by their encoded length.
389e63c799aSDavid Blaikie // Nested functions also encode their argument types without specifying
390e63c799aSDavid Blaikie // what they return.
391e63c799aSDavid Blaikie // QualifiedName:
392e63c799aSDavid Blaikie // SymbolFunctionName
393e63c799aSDavid Blaikie // SymbolFunctionName QualifiedName
394e63c799aSDavid Blaikie // ^
395e63c799aSDavid Blaikie // SymbolFunctionName:
396e63c799aSDavid Blaikie // SymbolName
397e63c799aSDavid Blaikie // SymbolName TypeFunctionNoReturn
398e63c799aSDavid Blaikie // SymbolName M TypeFunctionNoReturn
399e63c799aSDavid Blaikie // SymbolName M TypeModifiers TypeFunctionNoReturn
400e63c799aSDavid Blaikie // The start pointer should be at the above location.
401e63c799aSDavid Blaikie
4026e08abdcSDavid Blaikie // Whether it has more than one symbol
4036e08abdcSDavid Blaikie size_t NotFirst = false;
4046e08abdcSDavid Blaikie do {
405b779f02aSLuís Ferreira // Skip over anonymous symbols.
406*86b6ac5dSNick Desaulniers if (!Mangled.empty() && Mangled.front() == '0') {
407b779f02aSLuís Ferreira do
408*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
409*86b6ac5dSNick Desaulniers while (!Mangled.empty() && Mangled.front() == '0');
410b779f02aSLuís Ferreira
411b779f02aSLuís Ferreira continue;
412b779f02aSLuís Ferreira }
413b779f02aSLuís Ferreira
4146e08abdcSDavid Blaikie if (NotFirst)
4156e08abdcSDavid Blaikie *Demangled << '.';
4166e08abdcSDavid Blaikie NotFirst = true;
417e63c799aSDavid Blaikie
418*86b6ac5dSNick Desaulniers parseIdentifier(Demangled, Mangled);
419*86b6ac5dSNick Desaulniers } while (!Mangled.empty() && isSymbolName(Mangled));
420e63c799aSDavid Blaikie }
421e63c799aSDavid Blaikie
parseIdentifier(OutputBuffer * Demangled,std::string_view & Mangled)422*86b6ac5dSNick Desaulniers void Demangler::parseIdentifier(OutputBuffer *Demangled,
423*86b6ac5dSNick Desaulniers std::string_view &Mangled) {
424*86b6ac5dSNick Desaulniers if (Mangled.empty()) {
425*86b6ac5dSNick Desaulniers Mangled = {};
426*86b6ac5dSNick Desaulniers return;
427*86b6ac5dSNick Desaulniers }
428e63c799aSDavid Blaikie
429*86b6ac5dSNick Desaulniers if (Mangled.front() == 'Q')
430bec08795SLuís Ferreira return parseSymbolBackref(Demangled, Mangled);
431bec08795SLuís Ferreira
432bec08795SLuís Ferreira // TODO: Parse lengthless template instances.
433e63c799aSDavid Blaikie
434*86b6ac5dSNick Desaulniers unsigned long Len;
435*86b6ac5dSNick Desaulniers decodeNumber(Mangled, Len);
436e63c799aSDavid Blaikie
437*86b6ac5dSNick Desaulniers if (Mangled.empty()) {
438*86b6ac5dSNick Desaulniers Mangled = {};
439*86b6ac5dSNick Desaulniers return;
440*86b6ac5dSNick Desaulniers }
441*86b6ac5dSNick Desaulniers if (!Len || Mangled.length() < Len) {
442*86b6ac5dSNick Desaulniers Mangled = {};
443*86b6ac5dSNick Desaulniers return;
444*86b6ac5dSNick Desaulniers }
445e63c799aSDavid Blaikie
446e63c799aSDavid Blaikie // TODO: Parse template instances with a length prefix.
447e63c799aSDavid Blaikie
44883087c09SLuís Ferreira // There can be multiple different declarations in the same function that
44983087c09SLuís Ferreira // have the same mangled name. To make the mangled names unique, a fake
45083087c09SLuís Ferreira // parent in the form `__Sddd' is added to the symbol.
451*86b6ac5dSNick Desaulniers if (Len >= 4 && starts_with(Mangled, "__S")) {
452*86b6ac5dSNick Desaulniers const size_t SuffixLen = Mangled.length() - Len;
453*86b6ac5dSNick Desaulniers std::string_view P = Mangled.substr(3);
454*86b6ac5dSNick Desaulniers while (P.length() > SuffixLen && std::isdigit(P.front()))
455*86b6ac5dSNick Desaulniers P.remove_prefix(1);
456*86b6ac5dSNick Desaulniers if (P.length() == SuffixLen) {
45783087c09SLuís Ferreira // Skip over the fake parent.
458*86b6ac5dSNick Desaulniers Mangled.remove_prefix(Len);
45983087c09SLuís Ferreira return parseIdentifier(Demangled, Mangled);
46083087c09SLuís Ferreira }
46183087c09SLuís Ferreira
46283087c09SLuís Ferreira // Else demangle it as a plain identifier.
46383087c09SLuís Ferreira }
46483087c09SLuís Ferreira
465*86b6ac5dSNick Desaulniers parseLName(Demangled, Mangled, Len);
466e63c799aSDavid Blaikie }
467e63c799aSDavid Blaikie
parseType(std::string_view & Mangled)468*86b6ac5dSNick Desaulniers bool Demangler::parseType(std::string_view &Mangled) {
469*86b6ac5dSNick Desaulniers if (Mangled.empty()) {
470*86b6ac5dSNick Desaulniers Mangled = {};
471*86b6ac5dSNick Desaulniers return false;
472*86b6ac5dSNick Desaulniers }
473669bfcf0SLuís Ferreira
474*86b6ac5dSNick Desaulniers switch (Mangled.front()) {
475669bfcf0SLuís Ferreira // TODO: Parse type qualifiers.
476669bfcf0SLuís Ferreira // TODO: Parse function types.
477669bfcf0SLuís Ferreira // TODO: Parse compound types.
478669bfcf0SLuís Ferreira // TODO: Parse delegate types.
479669bfcf0SLuís Ferreira // TODO: Parse tuple types.
480669bfcf0SLuís Ferreira
481669bfcf0SLuís Ferreira // Basic types.
482669bfcf0SLuís Ferreira case 'i':
483*86b6ac5dSNick Desaulniers Mangled.remove_prefix(1);
484669bfcf0SLuís Ferreira // TODO: Add type name dumping
485*86b6ac5dSNick Desaulniers return true;
486669bfcf0SLuís Ferreira
487669bfcf0SLuís Ferreira // TODO: Add support for the rest of the basic types.
488b21ea1c2SLuís Ferreira
489b21ea1c2SLuís Ferreira // Back referenced type.
490*86b6ac5dSNick Desaulniers case 'Q': {
491*86b6ac5dSNick Desaulniers parseTypeBackref(Mangled);
492*86b6ac5dSNick Desaulniers return true;
493*86b6ac5dSNick Desaulniers }
494669bfcf0SLuís Ferreira
495669bfcf0SLuís Ferreira default: // unhandled.
496*86b6ac5dSNick Desaulniers Mangled = {};
497*86b6ac5dSNick Desaulniers return false;
498669bfcf0SLuís Ferreira }
499669bfcf0SLuís Ferreira }
500669bfcf0SLuís Ferreira
parseLName(OutputBuffer * Demangled,std::string_view & Mangled,unsigned long Len)501*86b6ac5dSNick Desaulniers void Demangler::parseLName(OutputBuffer *Demangled, std::string_view &Mangled,
502e63c799aSDavid Blaikie unsigned long Len) {
5038a7ddf9eSLuís Ferreira switch (Len) {
5048a7ddf9eSLuís Ferreira case 6:
505*86b6ac5dSNick Desaulniers if (starts_with(Mangled, "__initZ")) {
5068a7ddf9eSLuís Ferreira // The static initializer for a given symbol.
5078a7ddf9eSLuís Ferreira Demangled->prepend("initializer for ");
5088a7ddf9eSLuís Ferreira Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
509*86b6ac5dSNick Desaulniers Mangled.remove_prefix(Len);
510*86b6ac5dSNick Desaulniers return;
5118a7ddf9eSLuís Ferreira }
512*86b6ac5dSNick Desaulniers if (starts_with(Mangled, "__vtblZ")) {
5138a7ddf9eSLuís Ferreira // The vtable symbol for a given class.
5148a7ddf9eSLuís Ferreira Demangled->prepend("vtable for ");
5158a7ddf9eSLuís Ferreira Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
516*86b6ac5dSNick Desaulniers Mangled.remove_prefix(Len);
517*86b6ac5dSNick Desaulniers return;
5188a7ddf9eSLuís Ferreira }
5198a7ddf9eSLuís Ferreira break;
5208a7ddf9eSLuís Ferreira
5218a7ddf9eSLuís Ferreira case 7:
522*86b6ac5dSNick Desaulniers if (starts_with(Mangled, "__ClassZ")) {
5238a7ddf9eSLuís Ferreira // The classinfo symbol for a given class.
5248a7ddf9eSLuís Ferreira Demangled->prepend("ClassInfo for ");
5258a7ddf9eSLuís Ferreira Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
526*86b6ac5dSNick Desaulniers Mangled.remove_prefix(Len);
527*86b6ac5dSNick Desaulniers return;
5288a7ddf9eSLuís Ferreira }
5298a7ddf9eSLuís Ferreira break;
5308a7ddf9eSLuís Ferreira
5318a7ddf9eSLuís Ferreira case 11:
532*86b6ac5dSNick Desaulniers if (starts_with(Mangled, "__InterfaceZ")) {
5338a7ddf9eSLuís Ferreira // The interface symbol for a given class.
5348a7ddf9eSLuís Ferreira Demangled->prepend("Interface for ");
5358a7ddf9eSLuís Ferreira Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
536*86b6ac5dSNick Desaulniers Mangled.remove_prefix(Len);
537*86b6ac5dSNick Desaulniers return;
5388a7ddf9eSLuís Ferreira }
5398a7ddf9eSLuís Ferreira break;
5408a7ddf9eSLuís Ferreira
5418a7ddf9eSLuís Ferreira case 12:
542*86b6ac5dSNick Desaulniers if (starts_with(Mangled, "__ModuleInfoZ")) {
5438a7ddf9eSLuís Ferreira // The ModuleInfo symbol for a given module.
5448a7ddf9eSLuís Ferreira Demangled->prepend("ModuleInfo for ");
5458a7ddf9eSLuís Ferreira Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
546*86b6ac5dSNick Desaulniers Mangled.remove_prefix(Len);
547*86b6ac5dSNick Desaulniers return;
5488a7ddf9eSLuís Ferreira }
5498a7ddf9eSLuís Ferreira break;
5508a7ddf9eSLuís Ferreira }
5518a7ddf9eSLuís Ferreira
552*86b6ac5dSNick Desaulniers *Demangled << Mangled.substr(0, Len);
553*86b6ac5dSNick Desaulniers Mangled.remove_prefix(Len);
554e63c799aSDavid Blaikie }
555e63c799aSDavid Blaikie
Demangler(std::string_view Mangled)556*86b6ac5dSNick Desaulniers Demangler::Demangler(std::string_view Mangled)
557*86b6ac5dSNick Desaulniers : Str(Mangled), LastBackref(Mangled.length()) {}
558e63c799aSDavid Blaikie
parseMangle(OutputBuffer * Demangled)559e63c799aSDavid Blaikie const char *Demangler::parseMangle(OutputBuffer *Demangled) {
560*86b6ac5dSNick Desaulniers std::string_view M(this->Str);
561*86b6ac5dSNick Desaulniers parseMangle(Demangled, M);
562*86b6ac5dSNick Desaulniers return M.data();
563e63c799aSDavid Blaikie }
56422a1aa5aSLuís Ferreira
dlangDemangle(std::string_view MangledName)565f5371eb3SNick Desaulniers char *llvm::dlangDemangle(std::string_view MangledName) {
566f5371eb3SNick Desaulniers if (MangledName.empty() || !starts_with(MangledName, "_D"))
56722a1aa5aSLuís Ferreira return nullptr;
56822a1aa5aSLuís Ferreira
56922a1aa5aSLuís Ferreira OutputBuffer Demangled;
570f5371eb3SNick Desaulniers if (MangledName == "_Dmain") {
57122a1aa5aSLuís Ferreira Demangled << "D main";
572e63c799aSDavid Blaikie } else {
573e63c799aSDavid Blaikie
574*86b6ac5dSNick Desaulniers Demangler D(MangledName);
575f5371eb3SNick Desaulniers const char *M = D.parseMangle(&Demangled);
576e63c799aSDavid Blaikie
577e63c799aSDavid Blaikie // Check that the entire symbol was successfully demangled.
578f5371eb3SNick Desaulniers if (M == nullptr || *M != '\0') {
579e63c799aSDavid Blaikie std::free(Demangled.getBuffer());
580e63c799aSDavid Blaikie return nullptr;
581e63c799aSDavid Blaikie }
582e63c799aSDavid Blaikie }
58322a1aa5aSLuís Ferreira
58422a1aa5aSLuís Ferreira // OutputBuffer's internal buffer is not null terminated and therefore we need
58522a1aa5aSLuís Ferreira // to add it to comply with C null terminated strings.
58622a1aa5aSLuís Ferreira if (Demangled.getCurrentPosition() > 0) {
58722a1aa5aSLuís Ferreira Demangled << '\0';
58822a1aa5aSLuís Ferreira Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1);
58922a1aa5aSLuís Ferreira return Demangled.getBuffer();
59022a1aa5aSLuís Ferreira }
59122a1aa5aSLuís Ferreira
592e63c799aSDavid Blaikie std::free(Demangled.getBuffer());
59322a1aa5aSLuís Ferreira return nullptr;
59422a1aa5aSLuís Ferreira }
595