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