xref: /llvm-project/llvm/lib/Demangle/DLangDemangle.cpp (revision 86b6ac5d54d7fe5cd21beff64b5c2194b1368bdf)
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