xref: /freebsd-src/contrib/llvm-project/lldb/source/Core/Mangled.cpp (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
1 //===-- Mangled.cpp -------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Core/Mangled.h"
10 
11 #include "lldb/Core/RichManglingContext.h"
12 #include "lldb/Target/Language.h"
13 #include "lldb/Utility/ConstString.h"
14 #include "lldb/Utility/Log.h"
15 #include "lldb/Utility/Logging.h"
16 #include "lldb/Utility/RegularExpression.h"
17 #include "lldb/Utility/Stream.h"
18 #include "lldb/lldb-enumerations.h"
19 
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Demangle/Demangle.h"
22 #include "llvm/Support/Compiler.h"
23 
24 #include <mutex>
25 #include <string>
26 #include <utility>
27 
28 #include <cstdlib>
29 #include <cstring>
30 using namespace lldb_private;
31 
32 static inline bool cstring_is_mangled(llvm::StringRef s) {
33   return Mangled::GetManglingScheme(s) != Mangled::eManglingSchemeNone;
34 }
35 
36 #pragma mark Mangled
37 
38 Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) {
39   if (name.empty())
40     return Mangled::eManglingSchemeNone;
41 
42   if (name.startswith("?"))
43     return Mangled::eManglingSchemeMSVC;
44 
45   if (name.startswith("_R"))
46     return Mangled::eManglingSchemeRustV0;
47 
48   if (name.startswith("_D"))
49     return Mangled::eManglingSchemeD;
50 
51   if (name.startswith("_Z"))
52     return Mangled::eManglingSchemeItanium;
53 
54   // ___Z is a clang extension of block invocations
55   if (name.startswith("___Z"))
56     return Mangled::eManglingSchemeItanium;
57 
58   return Mangled::eManglingSchemeNone;
59 }
60 
61 Mangled::Mangled(ConstString s) : m_mangled(), m_demangled() {
62   if (s)
63     SetValue(s);
64 }
65 
66 Mangled::Mangled(llvm::StringRef name) {
67   if (!name.empty())
68     SetValue(ConstString(name));
69 }
70 
71 // Convert to pointer operator. This allows code to check any Mangled objects
72 // to see if they contain anything valid using code such as:
73 //
74 //  Mangled mangled(...);
75 //  if (mangled)
76 //  { ...
77 Mangled::operator void *() const {
78   return (m_mangled) ? const_cast<Mangled *>(this) : nullptr;
79 }
80 
81 // Logical NOT operator. This allows code to check any Mangled objects to see
82 // if they are invalid using code such as:
83 //
84 //  Mangled mangled(...);
85 //  if (!file_spec)
86 //  { ...
87 bool Mangled::operator!() const { return !m_mangled; }
88 
89 // Clear the mangled and demangled values.
90 void Mangled::Clear() {
91   m_mangled.Clear();
92   m_demangled.Clear();
93 }
94 
95 // Compare the string values.
96 int Mangled::Compare(const Mangled &a, const Mangled &b) {
97   return ConstString::Compare(a.GetName(ePreferMangled),
98                               b.GetName(ePreferMangled));
99 }
100 
101 // Set the string value in this objects. If "mangled" is true, then the mangled
102 // named is set with the new value in "s", else the demangled name is set.
103 void Mangled::SetValue(ConstString s, bool mangled) {
104   if (s) {
105     if (mangled) {
106       m_demangled.Clear();
107       m_mangled = s;
108     } else {
109       m_demangled = s;
110       m_mangled.Clear();
111     }
112   } else {
113     m_demangled.Clear();
114     m_mangled.Clear();
115   }
116 }
117 
118 void Mangled::SetValue(ConstString name) {
119   if (name) {
120     if (cstring_is_mangled(name.GetStringRef())) {
121       m_demangled.Clear();
122       m_mangled = name;
123     } else {
124       m_demangled = name;
125       m_mangled.Clear();
126     }
127   } else {
128     m_demangled.Clear();
129     m_mangled.Clear();
130   }
131 }
132 
133 // Local helpers for different demangling implementations.
134 static char *GetMSVCDemangledStr(const char *M) {
135   char *demangled_cstr = llvm::microsoftDemangle(
136       M, nullptr, nullptr, nullptr, nullptr,
137       llvm::MSDemangleFlags(
138           llvm::MSDF_NoAccessSpecifier | llvm::MSDF_NoCallingConvention |
139           llvm::MSDF_NoMemberType | llvm::MSDF_NoVariableType));
140 
141   if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
142     if (demangled_cstr && demangled_cstr[0])
143       LLDB_LOGF(log, "demangled msvc: %s -> \"%s\"", M, demangled_cstr);
144     else
145       LLDB_LOGF(log, "demangled msvc: %s -> error", M);
146   }
147 
148   return demangled_cstr;
149 }
150 
151 static char *GetItaniumDemangledStr(const char *M) {
152   char *demangled_cstr = nullptr;
153 
154   llvm::ItaniumPartialDemangler ipd;
155   bool err = ipd.partialDemangle(M);
156   if (!err) {
157     // Default buffer and size (will realloc in case it's too small).
158     size_t demangled_size = 80;
159     demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
160     demangled_cstr = ipd.finishDemangle(demangled_cstr, &demangled_size);
161 
162     assert(demangled_cstr &&
163            "finishDemangle must always succeed if partialDemangle did");
164     assert(demangled_cstr[demangled_size - 1] == '\0' &&
165            "Expected demangled_size to return length including trailing null");
166   }
167 
168   if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
169     if (demangled_cstr)
170       LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr);
171     else
172       LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M);
173   }
174 
175   return demangled_cstr;
176 }
177 
178 static char *GetRustV0DemangledStr(const char *M) {
179   char *demangled_cstr = llvm::rustDemangle(M, nullptr, nullptr, nullptr);
180 
181   if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
182     if (demangled_cstr && demangled_cstr[0])
183       LLDB_LOG(log, "demangled rustv0: {0} -> \"{1}\"", M, demangled_cstr);
184     else
185       LLDB_LOG(log, "demangled rustv0: {0} -> error: failed to demangle", M);
186   }
187 
188   return demangled_cstr;
189 }
190 
191 static char *GetDLangDemangledStr(const char *M) {
192   char *demangled_cstr = llvm::dlangDemangle(M);
193 
194   if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
195     if (demangled_cstr && demangled_cstr[0])
196       LLDB_LOG(log, "demangled dlang: {0} -> \"{1}\"", M, demangled_cstr);
197     else
198       LLDB_LOG(log, "demangled dlang: {0} -> error: failed to demangle", M);
199   }
200 
201   return demangled_cstr;
202 }
203 
204 // Explicit demangling for scheduled requests during batch processing. This
205 // makes use of ItaniumPartialDemangler's rich demangle info
206 bool Mangled::DemangleWithRichManglingInfo(
207     RichManglingContext &context, SkipMangledNameFn *skip_mangled_name) {
208   // Others are not meant to arrive here. ObjC names or C's main() for example
209   // have their names stored in m_demangled, while m_mangled is empty.
210   assert(m_mangled);
211 
212   // Check whether or not we are interested in this name at all.
213   ManglingScheme scheme = GetManglingScheme(m_mangled.GetStringRef());
214   if (skip_mangled_name && skip_mangled_name(m_mangled.GetStringRef(), scheme))
215     return false;
216 
217   switch (scheme) {
218   case eManglingSchemeNone:
219     // The current mangled_name_filter would allow llvm_unreachable here.
220     return false;
221 
222   case eManglingSchemeItanium:
223     // We want the rich mangling info here, so we don't care whether or not
224     // there is a demangled string in the pool already.
225     if (context.FromItaniumName(m_mangled)) {
226       // If we got an info, we have a name. Copy to string pool and connect the
227       // counterparts to accelerate later access in GetDemangledName().
228       context.ParseFullName();
229       m_demangled.SetStringWithMangledCounterpart(context.GetBufferRef(),
230                                                   m_mangled);
231       return true;
232     } else {
233       m_demangled.SetCString("");
234       return false;
235     }
236 
237   case eManglingSchemeMSVC: {
238     // We have no rich mangling for MSVC-mangled names yet, so first try to
239     // demangle it if necessary.
240     if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) {
241       if (char *d = GetMSVCDemangledStr(m_mangled.GetCString())) {
242         // If we got an info, we have a name. Copy to string pool and connect
243         // the counterparts to accelerate later access in GetDemangledName().
244         m_demangled.SetStringWithMangledCounterpart(llvm::StringRef(d),
245                                                     m_mangled);
246         ::free(d);
247       } else {
248         m_demangled.SetCString("");
249       }
250     }
251 
252     if (m_demangled.IsEmpty()) {
253       // Cannot demangle it, so don't try parsing.
254       return false;
255     } else {
256       // Demangled successfully, we can try and parse it with
257       // CPlusPlusLanguage::MethodName.
258       return context.FromCxxMethodName(m_demangled);
259     }
260   }
261 
262   case eManglingSchemeRustV0:
263   case eManglingSchemeD:
264     // Rich demangling scheme is not supported
265     return false;
266   }
267   llvm_unreachable("Fully covered switch above!");
268 }
269 
270 // Generate the demangled name on demand using this accessor. Code in this
271 // class will need to use this accessor if it wishes to decode the demangled
272 // name. The result is cached and will be kept until a new string value is
273 // supplied to this object, or until the end of the object's lifetime.
274 ConstString Mangled::GetDemangledName() const {
275   // Check to make sure we have a valid mangled name and that we haven't
276   // already decoded our mangled name.
277   if (m_mangled && m_demangled.IsNull()) {
278     // Don't bother running anything that isn't mangled
279     const char *mangled_name = m_mangled.GetCString();
280     ManglingScheme mangling_scheme =
281         GetManglingScheme(m_mangled.GetStringRef());
282     if (mangling_scheme != eManglingSchemeNone &&
283         !m_mangled.GetMangledCounterpart(m_demangled)) {
284       // We didn't already mangle this name, demangle it and if all goes well
285       // add it to our map.
286       char *demangled_name = nullptr;
287       switch (mangling_scheme) {
288       case eManglingSchemeMSVC:
289         demangled_name = GetMSVCDemangledStr(mangled_name);
290         break;
291       case eManglingSchemeItanium: {
292         demangled_name = GetItaniumDemangledStr(mangled_name);
293         break;
294       }
295       case eManglingSchemeRustV0:
296         demangled_name = GetRustV0DemangledStr(mangled_name);
297         break;
298       case eManglingSchemeD:
299         demangled_name = GetDLangDemangledStr(mangled_name);
300         break;
301       case eManglingSchemeNone:
302         llvm_unreachable("eManglingSchemeNone was handled already");
303       }
304       if (demangled_name) {
305         m_demangled.SetStringWithMangledCounterpart(
306             llvm::StringRef(demangled_name), m_mangled);
307         free(demangled_name);
308       }
309     }
310     if (m_demangled.IsNull()) {
311       // Set the demangled string to the empty string to indicate we tried to
312       // parse it once and failed.
313       m_demangled.SetCString("");
314     }
315   }
316 
317   return m_demangled;
318 }
319 
320 ConstString Mangled::GetDisplayDemangledName() const {
321   return GetDemangledName();
322 }
323 
324 bool Mangled::NameMatches(const RegularExpression &regex) const {
325   if (m_mangled && regex.Execute(m_mangled.GetStringRef()))
326     return true;
327 
328   ConstString demangled = GetDemangledName();
329   return demangled && regex.Execute(demangled.GetStringRef());
330 }
331 
332 // Get the demangled name if there is one, else return the mangled name.
333 ConstString Mangled::GetName(Mangled::NamePreference preference) const {
334   if (preference == ePreferMangled && m_mangled)
335     return m_mangled;
336 
337   // Call the accessor to make sure we get a demangled name in case it hasn't
338   // been demangled yet...
339   ConstString demangled = GetDemangledName();
340 
341   if (preference == ePreferDemangledWithoutArguments) {
342     if (Language *lang = Language::FindPlugin(GuessLanguage())) {
343       return lang->GetDemangledFunctionNameWithoutArguments(*this);
344     }
345   }
346   if (preference == ePreferDemangled) {
347     if (demangled)
348       return demangled;
349     return m_mangled;
350   }
351   return demangled;
352 }
353 
354 // Dump a Mangled object to stream "s". We don't force our demangled name to be
355 // computed currently (we don't use the accessor).
356 void Mangled::Dump(Stream *s) const {
357   if (m_mangled) {
358     *s << ", mangled = " << m_mangled;
359   }
360   if (m_demangled) {
361     const char *demangled = m_demangled.AsCString();
362     s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");
363   }
364 }
365 
366 // Dumps a debug version of this string with extra object and state information
367 // to stream "s".
368 void Mangled::DumpDebug(Stream *s) const {
369   s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2),
370             static_cast<const void *>(this));
371   m_mangled.DumpDebug(s);
372   s->Printf(", demangled = ");
373   m_demangled.DumpDebug(s);
374 }
375 
376 // Return the size in byte that this object takes in memory. The size includes
377 // the size of the objects it owns, and not the strings that it references
378 // because they are shared strings.
379 size_t Mangled::MemorySize() const {
380   return m_mangled.MemorySize() + m_demangled.MemorySize();
381 }
382 
383 // We "guess" the language because we can't determine a symbol's language from
384 // it's name.  For example, a Pascal symbol can be mangled using the C++
385 // Itanium scheme, and defined in a compilation unit within the same module as
386 // other C++ units.  In addition, different targets could have different ways
387 // of mangling names from a given language, likewise the compilation units
388 // within those targets.
389 lldb::LanguageType Mangled::GuessLanguage() const {
390   lldb::LanguageType result = lldb::eLanguageTypeUnknown;
391   // Ask each language plugin to check if the mangled name belongs to it.
392   Language::ForEach([this, &result](Language *l) {
393     if (l->SymbolNameFitsToLanguage(*this)) {
394       result = l->GetLanguageType();
395       return false;
396     }
397     return true;
398   });
399   return result;
400 }
401 
402 // Dump OBJ to the supplied stream S.
403 Stream &operator<<(Stream &s, const Mangled &obj) {
404   if (obj.GetMangledName())
405     s << "mangled = '" << obj.GetMangledName() << "'";
406 
407   ConstString demangled = obj.GetDemangledName();
408   if (demangled)
409     s << ", demangled = '" << demangled << '\'';
410   else
411     s << ", demangled = <error>";
412   return s;
413 }
414