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"
17e63c799aSDavid Blaikie #include "llvm/Demangle/StringView.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>
2322a1aa5aSLuís Ferreira 
2422a1aa5aSLuís Ferreira using namespace llvm;
2522a1aa5aSLuís Ferreira using llvm::itanium_demangle::OutputBuffer;
26e63c799aSDavid Blaikie using llvm::itanium_demangle::StringView;
27e63c799aSDavid Blaikie 
28e63c799aSDavid Blaikie namespace {
29e63c799aSDavid Blaikie 
30e63c799aSDavid Blaikie /// Demangle information structure.
31e63c799aSDavid Blaikie struct Demangler {
32e63c799aSDavid Blaikie   /// Initialize the information structure we use to pass around information.
33e63c799aSDavid Blaikie   ///
34e63c799aSDavid Blaikie   /// \param Mangled String to demangle.
35e63c799aSDavid Blaikie   Demangler(const char *Mangled);
36e63c799aSDavid Blaikie 
37e63c799aSDavid Blaikie   /// Extract and demangle the mangled symbol and append it to the output
38e63c799aSDavid Blaikie   /// string.
39e63c799aSDavid Blaikie   ///
40e63c799aSDavid Blaikie   /// \param Demangled Output buffer to write the demangled name.
41e63c799aSDavid Blaikie   ///
42e63c799aSDavid Blaikie   /// \return The remaining string on success or nullptr on failure.
43e63c799aSDavid Blaikie   ///
44e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#name_mangling .
45e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#MangledName .
46e63c799aSDavid Blaikie   const char *parseMangle(OutputBuffer *Demangled);
47e63c799aSDavid Blaikie 
48e63c799aSDavid Blaikie private:
49e63c799aSDavid Blaikie   /// Extract and demangle a given mangled symbol and append it to the output
50e63c799aSDavid Blaikie   /// string.
51e63c799aSDavid Blaikie   ///
52e63c799aSDavid Blaikie   /// \param Demangled output buffer to write the demangled name.
53e63c799aSDavid Blaikie   /// \param Mangled mangled symbol to be demangled.
54e63c799aSDavid Blaikie   ///
55e63c799aSDavid Blaikie   /// \return The remaining string on success or nullptr on failure.
56e63c799aSDavid Blaikie   ///
57e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#name_mangling .
58e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#MangledName .
59e63c799aSDavid Blaikie   const char *parseMangle(OutputBuffer *Demangled, const char *Mangled);
60e63c799aSDavid Blaikie 
61e63c799aSDavid Blaikie   /// Extract the number from a given string.
62e63c799aSDavid Blaikie   ///
63e63c799aSDavid Blaikie   /// \param Mangled string to extract the number.
64e63c799aSDavid Blaikie   /// \param Ret assigned result value.
65e63c799aSDavid Blaikie   ///
66e63c799aSDavid Blaikie   /// \return The remaining string on success or nullptr on failure.
67e63c799aSDavid Blaikie   ///
68e63c799aSDavid Blaikie   /// \note A result larger than UINT_MAX is considered a failure.
69e63c799aSDavid Blaikie   ///
70e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#Number .
716983968eSLuís Ferreira   const char *decodeNumber(const char *Mangled, unsigned long &Ret);
72e63c799aSDavid Blaikie 
73bec08795SLuís Ferreira   /// Extract the back reference position from a given string.
74bec08795SLuís Ferreira   ///
75bec08795SLuís Ferreira   /// \param Mangled string to extract the back reference position.
76bec08795SLuís Ferreira   /// \param Ret assigned result value.
77bec08795SLuís Ferreira   ///
78bec08795SLuís Ferreira   /// \return the remaining string on success or nullptr on failure.
79bec08795SLuís Ferreira   ///
80bec08795SLuís Ferreira   /// \note Ret is always >= 0 on success, and unspecified on failure
81bec08795SLuís Ferreira   ///
82bec08795SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#back_ref .
83bec08795SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#NumberBackRef .
84bec08795SLuís Ferreira   const char *decodeBackrefPos(const char *Mangled, long &Ret);
85bec08795SLuís Ferreira 
86bec08795SLuís Ferreira   /// Extract the symbol pointed by the back reference form a given string.
87bec08795SLuís Ferreira   ///
88bec08795SLuís Ferreira   /// \param Mangled string to extract the back reference position.
89bec08795SLuís Ferreira   /// \param Ret assigned result value.
90bec08795SLuís Ferreira   ///
91bec08795SLuís Ferreira   /// \return the remaining string on success or nullptr on failure.
92bec08795SLuís Ferreira   ///
93bec08795SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#back_ref .
94bec08795SLuís Ferreira   const char *decodeBackref(const char *Mangled, const char *&Ret);
95bec08795SLuís Ferreira 
96bec08795SLuís Ferreira   /// Extract and demangle backreferenced symbol from a given mangled symbol
97bec08795SLuís Ferreira   /// and append it to the output string.
98bec08795SLuís Ferreira   ///
99bec08795SLuís Ferreira   /// \param Demangled output buffer to write the demangled name.
100bec08795SLuís Ferreira   /// \param Mangled mangled symbol to be demangled.
101bec08795SLuís Ferreira   ///
102bec08795SLuís Ferreira   /// \return the remaining string on success or nullptr on failure.
103bec08795SLuís Ferreira   ///
104bec08795SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#back_ref .
105bec08795SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#IdentifierBackRef .
106bec08795SLuís Ferreira   const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled);
107bec08795SLuís Ferreira 
108b21ea1c2SLuís Ferreira   /// Extract and demangle backreferenced type from a given mangled symbol
109b21ea1c2SLuís Ferreira   /// and append it to the output string.
110b21ea1c2SLuís Ferreira   ///
111b21ea1c2SLuís Ferreira   /// \param Mangled mangled symbol to be demangled.
112b21ea1c2SLuís Ferreira   ///
113b21ea1c2SLuís Ferreira   /// \return the remaining string on success or nullptr on failure.
114b21ea1c2SLuís Ferreira   ///
115b21ea1c2SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#back_ref .
116b21ea1c2SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#TypeBackRef .
117b21ea1c2SLuís Ferreira   const char *parseTypeBackref(const char *Mangled);
118b21ea1c2SLuís Ferreira 
1196e08abdcSDavid Blaikie   /// Check whether it is the beginning of a symbol name.
1206e08abdcSDavid Blaikie   ///
1216e08abdcSDavid Blaikie   /// \param Mangled string to extract the symbol name.
1226e08abdcSDavid Blaikie   ///
1236e08abdcSDavid Blaikie   /// \return true on success, false otherwise.
1246e08abdcSDavid Blaikie   ///
1256e08abdcSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#SymbolName .
1266e08abdcSDavid Blaikie   bool isSymbolName(const char *Mangled);
1276e08abdcSDavid Blaikie 
128e63c799aSDavid Blaikie   /// Extract and demangle an identifier from a given mangled symbol append it
129e63c799aSDavid Blaikie   /// to the output string.
130e63c799aSDavid Blaikie   ///
131e63c799aSDavid Blaikie   /// \param Demangled Output buffer to write the demangled name.
132e63c799aSDavid Blaikie   /// \param Mangled Mangled symbol to be demangled.
133e63c799aSDavid Blaikie   ///
134e63c799aSDavid Blaikie   /// \return The remaining string on success or nullptr on failure.
135e63c799aSDavid Blaikie   ///
136e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#SymbolName .
137e63c799aSDavid Blaikie   const char *parseIdentifier(OutputBuffer *Demangled, const char *Mangled);
138e63c799aSDavid Blaikie 
139e63c799aSDavid Blaikie   /// Extract and demangle the plain identifier from a given mangled symbol and
140e63c799aSDavid Blaikie   /// prepend/append it to the output string, with a special treatment for some
141e63c799aSDavid Blaikie   /// magic compiler generated symbols.
142e63c799aSDavid Blaikie   ///
143e63c799aSDavid Blaikie   /// \param Demangled Output buffer to write the demangled name.
144e63c799aSDavid Blaikie   /// \param Mangled Mangled symbol to be demangled.
145e63c799aSDavid Blaikie   /// \param Len Length of the mangled symbol name.
146e63c799aSDavid Blaikie   ///
147e63c799aSDavid Blaikie   /// \return The remaining string on success or nullptr on failure.
148e63c799aSDavid Blaikie   ///
149e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#LName .
150e63c799aSDavid Blaikie   const char *parseLName(OutputBuffer *Demangled, const char *Mangled,
151e63c799aSDavid Blaikie                          unsigned long Len);
152e63c799aSDavid Blaikie 
153e63c799aSDavid Blaikie   /// Extract and demangle the qualified symbol from a given mangled symbol
154e63c799aSDavid Blaikie   /// append it to the output string.
155e63c799aSDavid Blaikie   ///
156e63c799aSDavid Blaikie   /// \param Demangled Output buffer to write the demangled name.
157e63c799aSDavid Blaikie   /// \param Mangled Mangled symbol to be demangled.
158e63c799aSDavid Blaikie   ///
159e63c799aSDavid Blaikie   /// \return The remaining string on success or nullptr on failure.
160e63c799aSDavid Blaikie   ///
161e63c799aSDavid Blaikie   /// \see https://dlang.org/spec/abi.html#QualifiedName .
162e63c799aSDavid Blaikie   const char *parseQualified(OutputBuffer *Demangled, const char *Mangled);
163e63c799aSDavid Blaikie 
164669bfcf0SLuís Ferreira   /// Extract and demangle a type from a given mangled symbol append it to
165669bfcf0SLuís Ferreira   /// the output string.
166669bfcf0SLuís Ferreira   ///
167669bfcf0SLuís Ferreira   /// \param Mangled mangled symbol to be demangled.
168669bfcf0SLuís Ferreira   ///
169669bfcf0SLuís Ferreira   /// \return the remaining string on success or nullptr on failure.
170669bfcf0SLuís Ferreira   ///
171669bfcf0SLuís Ferreira   /// \see https://dlang.org/spec/abi.html#Type .
172669bfcf0SLuís Ferreira   const char *parseType(const char *Mangled);
173669bfcf0SLuís Ferreira 
174e63c799aSDavid Blaikie   /// The string we are demangling.
175e63c799aSDavid Blaikie   const char *Str;
176b21ea1c2SLuís Ferreira   /// The index of the last back reference.
177b21ea1c2SLuís Ferreira   int LastBackref;
178e63c799aSDavid Blaikie };
179e63c799aSDavid Blaikie 
180e63c799aSDavid Blaikie } // namespace
181e63c799aSDavid Blaikie 
decodeNumber(const char * Mangled,unsigned long & Ret)1826983968eSLuís Ferreira const char *Demangler::decodeNumber(const char *Mangled, unsigned long &Ret) {
183e63c799aSDavid Blaikie   // Return nullptr if trying to extract something that isn't a digit.
184e63c799aSDavid Blaikie   if (Mangled == nullptr || !std::isdigit(*Mangled))
185e63c799aSDavid Blaikie     return nullptr;
186e63c799aSDavid Blaikie 
187e63c799aSDavid Blaikie   unsigned long Val = 0;
188e63c799aSDavid Blaikie 
189e63c799aSDavid Blaikie   do {
190e63c799aSDavid Blaikie     unsigned long Digit = Mangled[0] - '0';
191e63c799aSDavid Blaikie 
192e63c799aSDavid Blaikie     // Check for overflow.
193e63c799aSDavid Blaikie     if (Val > (std::numeric_limits<unsigned int>::max() - Digit) / 10)
194e63c799aSDavid Blaikie       return nullptr;
195e63c799aSDavid Blaikie 
196e63c799aSDavid Blaikie     Val = Val * 10 + Digit;
197e63c799aSDavid Blaikie     ++Mangled;
198e63c799aSDavid Blaikie   } while (std::isdigit(*Mangled));
199e63c799aSDavid Blaikie 
200e63c799aSDavid Blaikie   if (*Mangled == '\0')
201e63c799aSDavid Blaikie     return nullptr;
202e63c799aSDavid Blaikie 
2036983968eSLuís Ferreira   Ret = Val;
204e63c799aSDavid Blaikie   return Mangled;
205e63c799aSDavid Blaikie }
206e63c799aSDavid Blaikie 
decodeBackrefPos(const char * Mangled,long & Ret)207bec08795SLuís Ferreira const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) {
208bec08795SLuís Ferreira   // Return nullptr if trying to extract something that isn't a digit
209bec08795SLuís Ferreira   if (Mangled == nullptr || !std::isalpha(*Mangled))
210bec08795SLuís Ferreira     return nullptr;
211bec08795SLuís Ferreira 
212bec08795SLuís Ferreira   // Any identifier or non-basic type that has been emitted to the mangled
213bec08795SLuís Ferreira   // symbol before will not be emitted again, but is referenced by a special
214bec08795SLuís Ferreira   // sequence encoding the relative position of the original occurrence in the
215bec08795SLuís Ferreira   // mangled symbol name.
216bec08795SLuís Ferreira   // Numbers in back references are encoded with base 26 by upper case letters
217bec08795SLuís Ferreira   // A-Z for higher digits but lower case letters a-z for the last digit.
218bec08795SLuís Ferreira   //    NumberBackRef:
219bec08795SLuís Ferreira   //        [a-z]
220bec08795SLuís Ferreira   //        [A-Z] NumberBackRef
221bec08795SLuís Ferreira   //        ^
222bec08795SLuís Ferreira   unsigned long Val = 0;
223bec08795SLuís Ferreira 
224bec08795SLuís Ferreira   while (std::isalpha(*Mangled)) {
225bec08795SLuís Ferreira     // Check for overflow
226bec08795SLuís Ferreira     if (Val > (std::numeric_limits<unsigned long>::max() - 25) / 26)
227bec08795SLuís Ferreira       break;
228bec08795SLuís Ferreira 
229bec08795SLuís Ferreira     Val *= 26;
230bec08795SLuís Ferreira 
231bec08795SLuís Ferreira     if (Mangled[0] >= 'a' && Mangled[0] <= 'z') {
232bec08795SLuís Ferreira       Val += Mangled[0] - 'a';
233bec08795SLuís Ferreira       if ((long)Val <= 0)
234bec08795SLuís Ferreira         break;
235bec08795SLuís Ferreira       Ret = Val;
236bec08795SLuís Ferreira       return Mangled + 1;
237bec08795SLuís Ferreira     }
238bec08795SLuís Ferreira 
239bec08795SLuís Ferreira     Val += Mangled[0] - 'A';
240bec08795SLuís Ferreira     ++Mangled;
241bec08795SLuís Ferreira   }
242bec08795SLuís Ferreira 
243bec08795SLuís Ferreira   return nullptr;
244bec08795SLuís Ferreira }
245bec08795SLuís Ferreira 
decodeBackref(const char * Mangled,const char * & Ret)246bec08795SLuís Ferreira const char *Demangler::decodeBackref(const char *Mangled, const char *&Ret) {
247bec08795SLuís Ferreira   assert(Mangled != nullptr && *Mangled == 'Q' && "Invalid back reference!");
248bec08795SLuís Ferreira   Ret = nullptr;
249bec08795SLuís Ferreira 
250bec08795SLuís Ferreira   // Position of 'Q'
251bec08795SLuís Ferreira   const char *Qpos = Mangled;
252bec08795SLuís Ferreira   long RefPos;
253bec08795SLuís Ferreira   ++Mangled;
254bec08795SLuís Ferreira 
255bec08795SLuís Ferreira   Mangled = decodeBackrefPos(Mangled, RefPos);
256bec08795SLuís Ferreira   if (Mangled == nullptr)
257bec08795SLuís Ferreira     return nullptr;
258bec08795SLuís Ferreira 
259bec08795SLuís Ferreira   if (RefPos > Qpos - Str)
260bec08795SLuís Ferreira     return nullptr;
261bec08795SLuís Ferreira 
262bec08795SLuís Ferreira   // Set the position of the back reference.
263bec08795SLuís Ferreira   Ret = Qpos - RefPos;
264bec08795SLuís Ferreira 
265bec08795SLuís Ferreira   return Mangled;
266bec08795SLuís Ferreira }
267bec08795SLuís Ferreira 
parseSymbolBackref(OutputBuffer * Demangled,const char * Mangled)268bec08795SLuís Ferreira const char *Demangler::parseSymbolBackref(OutputBuffer *Demangled,
269bec08795SLuís Ferreira                                           const char *Mangled) {
270bec08795SLuís Ferreira   // An identifier back reference always points to a digit 0 to 9.
271bec08795SLuís Ferreira   //    IdentifierBackRef:
272bec08795SLuís Ferreira   //        Q NumberBackRef
273bec08795SLuís Ferreira   //        ^
274bec08795SLuís Ferreira   const char *Backref;
275bec08795SLuís Ferreira   unsigned long Len;
276bec08795SLuís Ferreira 
277bec08795SLuís Ferreira   // Get position of the back reference
278bec08795SLuís Ferreira   Mangled = decodeBackref(Mangled, Backref);
279bec08795SLuís Ferreira 
280bec08795SLuís Ferreira   // Must point to a simple identifier
2816983968eSLuís Ferreira   Backref = decodeNumber(Backref, Len);
282bec08795SLuís Ferreira   if (Backref == nullptr || strlen(Backref) < Len)
283bec08795SLuís Ferreira     return nullptr;
284bec08795SLuís Ferreira 
285bec08795SLuís Ferreira   Backref = parseLName(Demangled, Backref, Len);
286bec08795SLuís Ferreira   if (Backref == nullptr)
287bec08795SLuís Ferreira     return nullptr;
288bec08795SLuís Ferreira 
289bec08795SLuís Ferreira   return Mangled;
290bec08795SLuís Ferreira }
291bec08795SLuís Ferreira 
parseTypeBackref(const char * Mangled)292b21ea1c2SLuís Ferreira const char *Demangler::parseTypeBackref(const char *Mangled) {
293b21ea1c2SLuís Ferreira   // A type back reference always points to a letter.
294b21ea1c2SLuís Ferreira   //    TypeBackRef:
295b21ea1c2SLuís Ferreira   //        Q NumberBackRef
296b21ea1c2SLuís Ferreira   //        ^
297b21ea1c2SLuís Ferreira   const char *Backref;
298b21ea1c2SLuís Ferreira 
299b21ea1c2SLuís Ferreira   // If we appear to be moving backwards through the mangle string, then
300b21ea1c2SLuís Ferreira   // bail as this may be a recursive back reference.
301b21ea1c2SLuís Ferreira   if (Mangled - Str >= LastBackref)
302b21ea1c2SLuís Ferreira     return nullptr;
303b21ea1c2SLuís Ferreira 
304b21ea1c2SLuís Ferreira   int SaveRefPos = LastBackref;
305b21ea1c2SLuís Ferreira   LastBackref = Mangled - Str;
306b21ea1c2SLuís Ferreira 
307b21ea1c2SLuís Ferreira   // Get position of the back reference.
308b21ea1c2SLuís Ferreira   Mangled = decodeBackref(Mangled, Backref);
309b21ea1c2SLuís Ferreira 
310b21ea1c2SLuís Ferreira   // Can't decode back reference.
311b21ea1c2SLuís Ferreira   if (Backref == nullptr)
312b21ea1c2SLuís Ferreira     return nullptr;
313b21ea1c2SLuís Ferreira 
314b21ea1c2SLuís Ferreira   // TODO: Add support for function type back references.
315b21ea1c2SLuís Ferreira   Backref = parseType(Backref);
316b21ea1c2SLuís Ferreira 
317b21ea1c2SLuís Ferreira   LastBackref = SaveRefPos;
318b21ea1c2SLuís Ferreira 
319b21ea1c2SLuís Ferreira   if (Backref == nullptr)
320b21ea1c2SLuís Ferreira     return nullptr;
321b21ea1c2SLuís Ferreira 
322b21ea1c2SLuís Ferreira   return Mangled;
323b21ea1c2SLuís Ferreira }
324b21ea1c2SLuís Ferreira 
isSymbolName(const char * Mangled)3256e08abdcSDavid Blaikie bool Demangler::isSymbolName(const char *Mangled) {
326bec08795SLuís Ferreira   long Ret;
327bec08795SLuís Ferreira   const char *Qref = Mangled;
328bec08795SLuís Ferreira 
3296e08abdcSDavid Blaikie   if (std::isdigit(*Mangled))
3306e08abdcSDavid Blaikie     return true;
3316e08abdcSDavid Blaikie 
332bec08795SLuís Ferreira   // TODO: Handle template instances.
333bec08795SLuís Ferreira 
334bec08795SLuís Ferreira   if (*Mangled != 'Q')
3356e08abdcSDavid Blaikie     return false;
336bec08795SLuís Ferreira 
337bec08795SLuís Ferreira   Mangled = decodeBackrefPos(Mangled + 1, Ret);
338bec08795SLuís Ferreira   if (Mangled == nullptr || Ret > Qref - Str)
339bec08795SLuís Ferreira     return false;
340bec08795SLuís Ferreira 
341bec08795SLuís Ferreira   return std::isdigit(Qref[-Ret]);
3426e08abdcSDavid Blaikie }
3436e08abdcSDavid Blaikie 
parseMangle(OutputBuffer * Demangled,const char * Mangled)344e63c799aSDavid Blaikie const char *Demangler::parseMangle(OutputBuffer *Demangled,
345e63c799aSDavid Blaikie                                    const char *Mangled) {
346e63c799aSDavid Blaikie   // A D mangled symbol is comprised of both scope and type information.
347e63c799aSDavid Blaikie   //    MangleName:
348e63c799aSDavid Blaikie   //        _D QualifiedName Type
349e63c799aSDavid Blaikie   //        _D QualifiedName Z
350e63c799aSDavid Blaikie   //        ^
351e63c799aSDavid Blaikie   // The caller should have guaranteed that the start pointer is at the
352e63c799aSDavid Blaikie   // above location.
353e63c799aSDavid Blaikie   // Note that type is never a function type, but only the return type of
354e63c799aSDavid Blaikie   // a function or the type of a variable.
355e63c799aSDavid Blaikie   Mangled += 2;
356e63c799aSDavid Blaikie 
357e63c799aSDavid Blaikie   Mangled = parseQualified(Demangled, Mangled);
358e63c799aSDavid Blaikie 
359e63c799aSDavid Blaikie   if (Mangled != nullptr) {
360e63c799aSDavid Blaikie     // Artificial symbols end with 'Z' and have no type.
361e63c799aSDavid Blaikie     if (*Mangled == 'Z')
362e63c799aSDavid Blaikie       ++Mangled;
363e63c799aSDavid Blaikie     else {
364669bfcf0SLuís Ferreira       Mangled = parseType(Mangled);
365e63c799aSDavid Blaikie     }
366e63c799aSDavid Blaikie   }
367e63c799aSDavid Blaikie 
368e63c799aSDavid Blaikie   return Mangled;
369e63c799aSDavid Blaikie }
370e63c799aSDavid Blaikie 
parseQualified(OutputBuffer * Demangled,const char * Mangled)371e63c799aSDavid Blaikie const char *Demangler::parseQualified(OutputBuffer *Demangled,
372e63c799aSDavid Blaikie                                       const char *Mangled) {
373e63c799aSDavid Blaikie   // Qualified names are identifiers separated by their encoded length.
374e63c799aSDavid Blaikie   // Nested functions also encode their argument types without specifying
375e63c799aSDavid Blaikie   // what they return.
376e63c799aSDavid Blaikie   //    QualifiedName:
377e63c799aSDavid Blaikie   //        SymbolFunctionName
378e63c799aSDavid Blaikie   //        SymbolFunctionName QualifiedName
379e63c799aSDavid Blaikie   //        ^
380e63c799aSDavid Blaikie   //    SymbolFunctionName:
381e63c799aSDavid Blaikie   //        SymbolName
382e63c799aSDavid Blaikie   //        SymbolName TypeFunctionNoReturn
383e63c799aSDavid Blaikie   //        SymbolName M TypeFunctionNoReturn
384e63c799aSDavid Blaikie   //        SymbolName M TypeModifiers TypeFunctionNoReturn
385e63c799aSDavid Blaikie   // The start pointer should be at the above location.
386e63c799aSDavid Blaikie 
3876e08abdcSDavid Blaikie   // Whether it has more than one symbol
3886e08abdcSDavid Blaikie   size_t NotFirst = false;
3896e08abdcSDavid Blaikie   do {
390b779f02aSLuís Ferreira     // Skip over anonymous symbols.
391b779f02aSLuís Ferreira     if (*Mangled == '0') {
392b779f02aSLuís Ferreira       do
393b779f02aSLuís Ferreira         ++Mangled;
394b779f02aSLuís Ferreira       while (*Mangled == '0');
395b779f02aSLuís Ferreira 
396b779f02aSLuís Ferreira       continue;
397b779f02aSLuís Ferreira     }
398b779f02aSLuís Ferreira 
3996e08abdcSDavid Blaikie     if (NotFirst)
4006e08abdcSDavid Blaikie       *Demangled << '.';
4016e08abdcSDavid Blaikie     NotFirst = true;
402e63c799aSDavid Blaikie 
4036e08abdcSDavid Blaikie     Mangled = parseIdentifier(Demangled, Mangled);
4046e08abdcSDavid Blaikie 
4056e08abdcSDavid Blaikie   } while (Mangled && isSymbolName(Mangled));
4066e08abdcSDavid Blaikie 
4076e08abdcSDavid Blaikie   return Mangled;
408e63c799aSDavid Blaikie }
409e63c799aSDavid Blaikie 
parseIdentifier(OutputBuffer * Demangled,const char * Mangled)410e63c799aSDavid Blaikie const char *Demangler::parseIdentifier(OutputBuffer *Demangled,
411e63c799aSDavid Blaikie                                        const char *Mangled) {
412e63c799aSDavid Blaikie   unsigned long Len;
413e63c799aSDavid Blaikie 
414e63c799aSDavid Blaikie   if (Mangled == nullptr || *Mangled == '\0')
415e63c799aSDavid Blaikie     return nullptr;
416e63c799aSDavid Blaikie 
417bec08795SLuís Ferreira   if (*Mangled == 'Q')
418bec08795SLuís Ferreira     return parseSymbolBackref(Demangled, Mangled);
419bec08795SLuís Ferreira 
420bec08795SLuís Ferreira   // TODO: Parse lengthless template instances.
421e63c799aSDavid Blaikie 
4226983968eSLuís Ferreira   const char *Endptr = decodeNumber(Mangled, Len);
423e63c799aSDavid Blaikie 
424e63c799aSDavid Blaikie   if (Endptr == nullptr || Len == 0)
425e63c799aSDavid Blaikie     return nullptr;
426e63c799aSDavid Blaikie 
427e63c799aSDavid Blaikie   if (strlen(Endptr) < Len)
428e63c799aSDavid Blaikie     return nullptr;
429e63c799aSDavid Blaikie 
430e63c799aSDavid Blaikie   Mangled = Endptr;
431e63c799aSDavid Blaikie 
432e63c799aSDavid Blaikie   // TODO: Parse template instances with a length prefix.
433e63c799aSDavid Blaikie 
43483087c09SLuís Ferreira   // There can be multiple different declarations in the same function that
43583087c09SLuís Ferreira   // have the same mangled name.  To make the mangled names unique, a fake
43683087c09SLuís Ferreira   // parent in the form `__Sddd' is added to the symbol.
43783087c09SLuís Ferreira   if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') {
43883087c09SLuís Ferreira     const char *NumPtr = Mangled + 3;
43983087c09SLuís Ferreira     while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr))
44083087c09SLuís Ferreira       ++NumPtr;
44183087c09SLuís Ferreira 
44283087c09SLuís Ferreira     if (Mangled + Len == NumPtr) {
44383087c09SLuís Ferreira       // Skip over the fake parent.
44483087c09SLuís Ferreira       Mangled += Len;
44583087c09SLuís Ferreira       return parseIdentifier(Demangled, Mangled);
44683087c09SLuís Ferreira     }
44783087c09SLuís Ferreira 
44883087c09SLuís Ferreira     // Else demangle it as a plain identifier.
44983087c09SLuís Ferreira   }
45083087c09SLuís Ferreira 
451e63c799aSDavid Blaikie   return parseLName(Demangled, Mangled, Len);
452e63c799aSDavid Blaikie }
453e63c799aSDavid Blaikie 
parseType(const char * Mangled)454669bfcf0SLuís Ferreira const char *Demangler::parseType(const char *Mangled) {
455669bfcf0SLuís Ferreira   if (*Mangled == '\0')
456669bfcf0SLuís Ferreira     return nullptr;
457669bfcf0SLuís Ferreira 
458669bfcf0SLuís Ferreira   switch (*Mangled) {
459669bfcf0SLuís Ferreira   // TODO: Parse type qualifiers.
460669bfcf0SLuís Ferreira   // TODO: Parse function types.
461669bfcf0SLuís Ferreira   // TODO: Parse compound types.
462669bfcf0SLuís Ferreira   // TODO: Parse delegate types.
463669bfcf0SLuís Ferreira   // TODO: Parse tuple types.
464669bfcf0SLuís Ferreira 
465669bfcf0SLuís Ferreira   // Basic types.
466669bfcf0SLuís Ferreira   case 'i':
467669bfcf0SLuís Ferreira     ++Mangled;
468669bfcf0SLuís Ferreira     // TODO: Add type name dumping
469669bfcf0SLuís Ferreira     return Mangled;
470669bfcf0SLuís Ferreira 
471669bfcf0SLuís Ferreira     // TODO: Add support for the rest of the basic types.
472b21ea1c2SLuís Ferreira 
473b21ea1c2SLuís Ferreira   // Back referenced type.
474b21ea1c2SLuís Ferreira   case 'Q':
475b21ea1c2SLuís Ferreira     return parseTypeBackref(Mangled);
476669bfcf0SLuís Ferreira 
477669bfcf0SLuís Ferreira   default: // unhandled.
478669bfcf0SLuís Ferreira     return nullptr;
479669bfcf0SLuís Ferreira   }
480669bfcf0SLuís Ferreira }
481669bfcf0SLuís Ferreira 
parseLName(OutputBuffer * Demangled,const char * Mangled,unsigned long Len)482e63c799aSDavid Blaikie const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled,
483e63c799aSDavid Blaikie                                   unsigned long Len) {
4848a7ddf9eSLuís Ferreira   switch (Len) {
4858a7ddf9eSLuís Ferreira   case 6:
4868a7ddf9eSLuís Ferreira     if (strncmp(Mangled, "__initZ", Len + 1) == 0) {
4878a7ddf9eSLuís Ferreira       // The static initializer for a given symbol.
4888a7ddf9eSLuís Ferreira       Demangled->prepend("initializer for ");
4898a7ddf9eSLuís Ferreira       Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
4908a7ddf9eSLuís Ferreira       Mangled += Len;
4918a7ddf9eSLuís Ferreira       return Mangled;
4928a7ddf9eSLuís Ferreira     }
4938a7ddf9eSLuís Ferreira     if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) {
4948a7ddf9eSLuís Ferreira       // The vtable symbol for a given class.
4958a7ddf9eSLuís Ferreira       Demangled->prepend("vtable for ");
4968a7ddf9eSLuís Ferreira       Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
4978a7ddf9eSLuís Ferreira       Mangled += Len;
4988a7ddf9eSLuís Ferreira       return Mangled;
4998a7ddf9eSLuís Ferreira     }
5008a7ddf9eSLuís Ferreira     break;
5018a7ddf9eSLuís Ferreira 
5028a7ddf9eSLuís Ferreira   case 7:
5038a7ddf9eSLuís Ferreira     if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) {
5048a7ddf9eSLuís Ferreira       // The classinfo symbol for a given class.
5058a7ddf9eSLuís Ferreira       Demangled->prepend("ClassInfo for ");
5068a7ddf9eSLuís Ferreira       Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
5078a7ddf9eSLuís Ferreira       Mangled += Len;
5088a7ddf9eSLuís Ferreira       return Mangled;
5098a7ddf9eSLuís Ferreira     }
5108a7ddf9eSLuís Ferreira     break;
5118a7ddf9eSLuís Ferreira 
5128a7ddf9eSLuís Ferreira   case 11:
5138a7ddf9eSLuís Ferreira     if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) {
5148a7ddf9eSLuís Ferreira       // The interface symbol for a given class.
5158a7ddf9eSLuís Ferreira       Demangled->prepend("Interface for ");
5168a7ddf9eSLuís Ferreira       Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
5178a7ddf9eSLuís Ferreira       Mangled += Len;
5188a7ddf9eSLuís Ferreira       return Mangled;
5198a7ddf9eSLuís Ferreira     }
5208a7ddf9eSLuís Ferreira     break;
5218a7ddf9eSLuís Ferreira 
5228a7ddf9eSLuís Ferreira   case 12:
5238a7ddf9eSLuís Ferreira     if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) {
5248a7ddf9eSLuís Ferreira       // The ModuleInfo symbol for a given module.
5258a7ddf9eSLuís Ferreira       Demangled->prepend("ModuleInfo for ");
5268a7ddf9eSLuís Ferreira       Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
5278a7ddf9eSLuís Ferreira       Mangled += Len;
5288a7ddf9eSLuís Ferreira       return Mangled;
5298a7ddf9eSLuís Ferreira     }
5308a7ddf9eSLuís Ferreira     break;
5318a7ddf9eSLuís Ferreira   }
5328a7ddf9eSLuís Ferreira 
533e63c799aSDavid Blaikie   *Demangled << StringView(Mangled, Len);
534e63c799aSDavid Blaikie   Mangled += Len;
535e63c799aSDavid Blaikie 
536e63c799aSDavid Blaikie   return Mangled;
537e63c799aSDavid Blaikie }
538e63c799aSDavid Blaikie 
Demangler(const char * Mangled)539b21ea1c2SLuís Ferreira Demangler::Demangler(const char *Mangled)
540b21ea1c2SLuís Ferreira     : Str(Mangled), LastBackref(strlen(Mangled)) {}
541e63c799aSDavid Blaikie 
parseMangle(OutputBuffer * Demangled)542e63c799aSDavid Blaikie const char *Demangler::parseMangle(OutputBuffer *Demangled) {
543e63c799aSDavid Blaikie   return parseMangle(Demangled, this->Str);
544e63c799aSDavid Blaikie }
54522a1aa5aSLuís Ferreira 
dlangDemangle(const char * MangledName)54622a1aa5aSLuís Ferreira char *llvm::dlangDemangle(const char *MangledName) {
54722a1aa5aSLuís Ferreira   if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0)
54822a1aa5aSLuís Ferreira     return nullptr;
54922a1aa5aSLuís Ferreira 
55022a1aa5aSLuís Ferreira   OutputBuffer Demangled;
551*aabeb5ebSKirill Stoimenov   if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024))
552*aabeb5ebSKirill Stoimenov     return nullptr;
553*aabeb5ebSKirill Stoimenov 
554e63c799aSDavid Blaikie   if (strcmp(MangledName, "_Dmain") == 0) {
55522a1aa5aSLuís Ferreira     Demangled << "D main";
556e63c799aSDavid Blaikie   } else {
557e63c799aSDavid Blaikie 
558e63c799aSDavid Blaikie     Demangler D = Demangler(MangledName);
559e63c799aSDavid Blaikie     MangledName = D.parseMangle(&Demangled);
560e63c799aSDavid Blaikie 
561e63c799aSDavid Blaikie     // Check that the entire symbol was successfully demangled.
562e63c799aSDavid Blaikie     if (MangledName == nullptr || *MangledName != '\0') {
563e63c799aSDavid Blaikie       std::free(Demangled.getBuffer());
564e63c799aSDavid Blaikie       return nullptr;
565e63c799aSDavid Blaikie     }
566e63c799aSDavid Blaikie   }
56722a1aa5aSLuís Ferreira 
56822a1aa5aSLuís Ferreira   // OutputBuffer's internal buffer is not null terminated and therefore we need
56922a1aa5aSLuís Ferreira   // to add it to comply with C null terminated strings.
57022a1aa5aSLuís Ferreira   if (Demangled.getCurrentPosition() > 0) {
57122a1aa5aSLuís Ferreira     Demangled << '\0';
57222a1aa5aSLuís Ferreira     Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1);
57322a1aa5aSLuís Ferreira     return Demangled.getBuffer();
57422a1aa5aSLuís Ferreira   }
57522a1aa5aSLuís Ferreira 
576e63c799aSDavid Blaikie   std::free(Demangled.getBuffer());
57722a1aa5aSLuís Ferreira   return nullptr;
57822a1aa5aSLuís Ferreira }
579