LLDB mainline
Mangled.cpp
Go to the documentation of this file.
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
17#include "lldb/Utility/Stream.h"
19
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/StringRef.h"
24
25#include <mutex>
26#include <optional>
27#include <vector>
28
29using namespace lldb_private;
30
31#pragma mark Mangled
32
33namespace {
34struct RegisteredManglingScheme {
35 llvm::SmallVector<llvm::SmallString<16>, 12> prefixes;
36 /// If set, a name that starts with one of the prefixes must also match.
37 Mangled::ManglingSchemeMatcher matches = nullptr;
39 bool active = false;
40};
41
42class ManglingSchemeRegistry {
43public:
44 Mangled::ManglingScheme Register(llvm::ArrayRef<llvm::StringRef> prefixes,
45 lldb::LanguageType language,
47 void Unregister(Mangled::ManglingScheme scheme);
48 lldb::LanguageType GetLanguage(Mangled::ManglingScheme scheme) const;
49 Mangled::ManglingScheme Find(llvm::StringRef name) const;
50
51private:
52 /// Returns the index of \p scheme in m_schemes, if it was registered.
53 /// Requires m_mutex.
54 std::optional<size_t> GetIndex(Mangled::ManglingScheme scheme) const;
55
56 mutable std::mutex m_mutex;
57 /// Indexed by scheme - eFirstRegisteredManglingScheme. Unregistered schemes
58 /// are kept, so that registering them again returns the same scheme.
59 std::vector<RegisteredManglingScheme> m_schemes;
60};
61} // namespace
62
63static ManglingSchemeRegistry &GetManglingSchemeRegistry() {
64 // Never destroyed, since other threads may still look up mangling schemes
65 // while static destructors run at exit.
66 static ManglingSchemeRegistry *g_registry = new ManglingSchemeRegistry();
67 return *g_registry;
68}
69
71 return static_cast<Mangled::ManglingScheme>(
73}
74
75/// Returns true if a name could start with both one of \p prefixes and a
76/// prefix of one of the active \p schemes.
77[[maybe_unused]] static bool
78OverlapsActiveScheme(llvm::ArrayRef<llvm::StringRef> prefixes,
79 llvm::ArrayRef<RegisteredManglingScheme> schemes) {
80 for (const RegisteredManglingScheme &scheme : schemes) {
81 if (!scheme.active)
82 continue;
83 for (llvm::StringRef prefix : prefixes)
84 for (llvm::StringRef other : scheme.prefixes)
85 if (prefix.starts_with(other) || other.starts_with(prefix))
86 return true;
87 }
88 return false;
89}
90
92ManglingSchemeRegistry::Register(llvm::ArrayRef<llvm::StringRef> prefixes,
93 lldb::LanguageType language,
95 std::lock_guard<std::mutex> guard(m_mutex);
96 auto it =
97 llvm::find_if(m_schemes, [&](const RegisteredManglingScheme &scheme) {
98 return scheme.language == language && scheme.matches == matches &&
99 llvm::equal(scheme.prefixes, prefixes);
100 });
101 const size_t index = std::distance(m_schemes.begin(), it);
102
103 if (it == m_schemes.end()) {
104 const bool full = Mangled::eFirstRegisteredManglingScheme + index >=
106 assert(!full && "too many mangling schemes");
107 if (full)
109 assert(!OverlapsActiveScheme(prefixes, m_schemes) &&
110 "mangling scheme prefixes overlap");
111 RegisteredManglingScheme &scheme = m_schemes.emplace_back();
112 scheme.prefixes.assign(prefixes.begin(), prefixes.end());
113 scheme.matches = matches;
114 scheme.language = language;
115 }
116 m_schemes[index].active = true;
117 return SchemeForIndex(index);
118}
119
120std::optional<size_t>
121ManglingSchemeRegistry::GetIndex(Mangled::ManglingScheme scheme) const {
123 return std::nullopt;
124 size_t index = scheme - Mangled::eFirstRegisteredManglingScheme;
125 if (index >= m_schemes.size())
126 return std::nullopt;
127 return index;
128}
129
130void ManglingSchemeRegistry::Unregister(Mangled::ManglingScheme scheme) {
131 std::lock_guard<std::mutex> guard(m_mutex);
132 if (std::optional<size_t> index = GetIndex(scheme))
133 m_schemes[*index].active = false;
134}
135
137ManglingSchemeRegistry::GetLanguage(Mangled::ManglingScheme scheme) const {
138 std::lock_guard<std::mutex> guard(m_mutex);
139 if (std::optional<size_t> index = GetIndex(scheme))
140 return m_schemes[*index].language;
142}
143
145ManglingSchemeRegistry::Find(llvm::StringRef name) const {
146 std::lock_guard<std::mutex> guard(m_mutex);
147 for (auto [index, scheme] : llvm::enumerate(m_schemes)) {
148 if (!scheme.active ||
149 !llvm::any_of(scheme.prefixes, [&](llvm::StringRef prefix) {
150 return name.starts_with(prefix);
151 }))
152 continue;
153 // Prefixes don't overlap, so no other scheme can match the name. The
154 // matcher runs under the lock, so it must not use the registry.
155 if (scheme.matches && !scheme.matches(name))
157 return SchemeForIndex(index);
158 }
160}
161
163Mangled::RegisterManglingScheme(llvm::ArrayRef<llvm::StringRef> prefixes,
164 lldb::LanguageType language,
165 ManglingSchemeMatcher matches) {
166 return GetManglingSchemeRegistry().Register(prefixes, language, matches);
167}
168
172
177
178bool Mangled::IsMangledName(llvm::StringRef name) {
180}
181
183 if (name.empty())
185
186 return GetManglingSchemeRegistry().Find(name);
187}
188
190 if (s)
191 SetValue(s);
192}
193
194Mangled::Mangled(llvm::StringRef name) {
195 if (!name.empty())
196 SetValue(ConstString(name));
197}
198
199// Convert to bool operator. This allows code to check any Mangled objects
200// to see if they contain anything valid using code such as:
201//
202// Mangled mangled(...);
203// if (mangled)
204// { ...
205Mangled::operator bool() const { return m_mangled || m_demangled; }
206
207// Clear the mangled and demangled values.
209 m_mangled.Clear();
210 m_demangled.Clear();
211}
212
213// Compare the string values.
218
220 if (name) {
221 if (IsMangledName(name.GetStringRef())) {
222 m_demangled.Clear();
223 m_mangled = name;
224 } else {
225 m_demangled = name;
226 m_mangled.Clear();
227 }
228 } else {
229 m_demangled.Clear();
230 m_mangled.Clear();
231 }
232}
233
234// Generate the demangled name on demand using this accessor. Code in this
235// class will need to use this accessor if it wishes to decode the demangled
236// name. The result is cached and will be kept until a new string value is
237// supplied to this object, or until the end of the object's lifetime.
239 if (!m_mangled)
240 return m_demangled;
241
242 // Re-use previously demangled names.
243 if (!m_demangled.IsNull())
244 return m_demangled;
245
246 if (m_mangled.GetMangledCounterpart(m_demangled) && !m_demangled.IsNull())
247 return m_demangled;
248
249 // We didn't already demangle this name, demangle it and if all goes well
250 // add it to our map.
251 ManglingScheme scheme = GetManglingScheme(m_mangled.GetStringRef());
253 Language::DemangledName demangled =
254 lang->DemangleSymbol(m_mangled, scheme, Language::DemangleOptions());
255 if (!demangled.name.empty())
256 m_demangled.SetStringWithMangledCounterpart(demangled.name, m_mangled);
257 }
258
259 if (m_demangled.IsNull()) {
260 // Set the demangled string to the empty string to indicate we tried to
261 // parse it once and failed.
262 m_demangled.SetCString("");
263 }
264
265 return m_demangled;
266}
267
268std::optional<DemangledNameInfo> Mangled::ComputeDemangledInfo() const {
269 if (!m_mangled)
270 return std::nullopt;
271
272 ManglingScheme scheme = GetManglingScheme(m_mangled.GetStringRef());
274 if (!lang)
275 return std::nullopt;
276
278 options.want_info = true;
279 return lang->DemangleSymbol(m_mangled, scheme, options).info;
280}
281
284 return lang->GetDisplayDemangledName(*this);
285 return GetDemangledName();
286}
287
288bool Mangled::NameMatches(const RegularExpression &regex) const {
289 if (m_mangled && regex.Execute(m_mangled.GetStringRef()))
290 return true;
291
292 ConstString demangled = GetDemangledName();
293 return demangled && regex.Execute(demangled.GetStringRef());
294}
295
296// Get the demangled name if there is one, else return the mangled name.
298 if (preference == ePreferMangled && m_mangled)
299 return m_mangled;
300
301 // Call the accessor to make sure we get a demangled name in case it hasn't
302 // been demangled yet...
303 ConstString demangled = GetDemangledName();
304
305 if (preference == ePreferDemangledWithoutArguments) {
307 return lang->GetDemangledFunctionNameWithoutArguments(*this);
308 }
309 }
310 if (preference == ePreferDemangled) {
311 if (demangled)
312 return demangled;
313 return m_mangled;
314 }
315 return demangled;
316}
317
318// Dump a Mangled object to stream "s". We don't force our demangled name to be
319// computed currently (we don't use the accessor).
320void Mangled::Dump(Stream *s) const {
321 if (m_mangled) {
322 *s << ", mangled = " << m_mangled;
323 }
324 if (m_demangled)
325 s->Format(", demangled = {0}", m_demangled.GetStringRef());
326}
327
328// Dumps a debug version of this string with extra object and state information
329// to stream "s".
331 s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2),
332 static_cast<const void *>(this));
333 m_mangled.DumpDebug(s);
334 s->PutCString(", demangled = ");
335 m_demangled.DumpDebug(s);
336}
337
338// We "guess" the language because we can't determine a symbol's language from
339// it's name. For example, a Pascal symbol can be mangled using the C++
340// Itanium scheme, and defined in a compilation unit within the same module as
341// other C++ units. In addition, different targets could have different ways
342// of mangling names from a given language, likewise the compilation units
343// within those targets.
345 // The language that registered the mangling scheme knows the name best.
346 if (m_mangled) {
348 GetManglingScheme(m_mangled.GetStringRef()));
349 if (language != lldb::eLanguageTypeUnknown)
350 return language;
351 }
352
354 // Ask each language plugin to check if the mangled name belongs to it.
355 Language::ForEach([this, &result](Language *l) {
356 if (l->SymbolNameFitsToLanguage(*this)) {
357 result = l->GetLanguageType();
359 }
361 });
362 return result;
363}
364
365// Dump OBJ to the supplied stream S.
366Stream &operator<<(Stream &s, const Mangled &obj) {
367 if (obj.GetMangledName())
368 s << "mangled = '" << obj.GetMangledName() << "'";
369
370 ConstString demangled = obj.GetDemangledName();
371 if (demangled)
372 s << ", demangled = '" << demangled << '\'';
373 else
374 s << ", demangled = <error>";
375 return s;
376}
377
378// When encoding Mangled objects we can get away with encoding as little
379// information as is required. The enumeration below helps us to efficiently
380// encode Mangled objects.
382 /// If the Mangled object has neither a mangled name or demangled name we can
383 /// encode the object with one zero byte using the Empty enumeration.
384 Empty = 0u,
385 /// If the Mangled object has only a demangled name and no mangled named, we
386 /// can encode only the demangled name.
388 /// If the mangle name can calculate the demangled name (it is the
389 /// mangled/demangled counterpart), then we only need to encode the mangled
390 /// name as the demangled name can be recomputed.
392 /// If we have a Mangled object with two different names that are not related
393 /// then we need to save both strings. This can happen if we have a name that
394 /// isn't a true mangled name, but we want to be able to lookup a symbol by
395 /// name and type in the symbol table. We do this for Objective C symbols like
396 /// "OBJC_CLASS_$_NSValue" where the mangled named will be set to
397 /// "OBJC_CLASS_$_NSValue" and the demangled name will be manually set to
398 /// "NSValue". If we tried to demangled the name "OBJC_CLASS_$_NSValue" it
399 /// would fail, but in these cases we want these unrelated names to be
400 /// preserved.
402};
403
404bool Mangled::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
405 const StringTableReader &strtab) {
406 m_mangled.Clear();
407 m_demangled.Clear();
408 MangledEncoding encoding = (MangledEncoding)data.GetU8(offset_ptr);
409 switch (encoding) {
410 case Empty:
411 return true;
412
413 case DemangledOnly:
414 m_demangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
415 return true;
416
417 case MangledOnly:
418 m_mangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
419 return true;
420
422 m_mangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
423 m_demangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
424 return true;
425 }
426 return false;
427}
428/// The encoding format for the Mangled object is as follows:
429///
430/// uint8_t encoding;
431/// char str1[]; (only if DemangledOnly, MangledOnly)
432/// char str2[]; (only if MangledAndDemangled)
433///
434/// The strings are stored as null-terminated UTF8 strings and str1 and str2
435/// are only saved if we need them based on the encoding.
436///
437/// Some mangled names have a mangled name that can be demangled by a
438/// plugin. These kinds of mangled objects know when the mangled and
439/// demangled names are the counterparts for each other. This is done
440/// because demangling is very expensive and avoiding demangling the
441/// same name twice saves us a lot of compute time. For these kinds of
442/// names we only need to save the mangled name and have the encoding
443/// set to "MangledOnly".
444///
445/// If a mangled object has only a demangled name, then we save only that string
446/// and have the encoding set to "DemangledOnly".
447///
448/// Some mangled objects have both mangled and demangled names, but the
449/// demangled name can not be computed from the mangled name. This is often used
450/// for runtime named, like Objective C runtime V2 and V3 names. Both these
451/// names must be saved and the encoding is set to "MangledAndDemangled".
452///
453/// For a Mangled object with no names, we only need to set the encoding to
454/// "Empty" and not store any string values.
455void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const {
456 MangledEncoding encoding = Empty;
457 if (m_mangled) {
458 encoding = MangledOnly;
459 if (m_demangled) {
460 // We have both mangled and demangled names. If the demangled name is the
461 // counterpart of the mangled name, then we only need to save the mangled
462 // name. If they are different, we need to save both.
463 ConstString s;
464 if (!(m_mangled.GetMangledCounterpart(s) && s == m_demangled))
465 encoding = MangledAndDemangled;
466 }
467 } else if (m_demangled) {
468 encoding = DemangledOnly;
469 }
470 file.AppendU8(encoding);
471 switch (encoding) {
472 case Empty:
473 break;
474 case DemangledOnly:
475 file.AppendU32(strtab.Add(m_demangled));
476 break;
477 case MangledOnly:
478 file.AppendU32(strtab.Add(m_mangled));
479 break;
481 file.AppendU32(strtab.Add(m_mangled));
482 file.AppendU32(strtab.Add(m_demangled));
483 break;
484 }
485}
486
488 std::optional<DemangledNameInfo> demangled_info = ComputeDemangledInfo();
489 if (!demangled_info)
490 return {};
491
492 ConstString demangled_name = GetDemangledName();
493 if (!demangled_name)
494 return {};
495
496 const auto &range = demangled_info->BasenameRange;
497 return ConstString(
498 demangled_name.GetStringRef().slice(range.first, range.second));
499}
static Mangled::ManglingScheme SchemeForIndex(size_t index)
Definition Mangled.cpp:70
static ManglingSchemeRegistry & GetManglingSchemeRegistry()
Definition Mangled.cpp:63
MangledEncoding
Definition Mangled.cpp:381
@ MangledAndDemangled
If we have a Mangled object with two different names that are not related then we need to save both s...
Definition Mangled.cpp:401
@ DemangledOnly
If the Mangled object has only a demangled name and no mangled named, we can encode only the demangle...
Definition Mangled.cpp:387
@ Empty
If the Mangled object has neither a mangled name or demangled name we can encode the object with one ...
Definition Mangled.cpp:384
@ MangledOnly
If the mangle name can calculate the demangled name (it is the mangled/demangled counterpart),...
Definition Mangled.cpp:391
static bool OverlapsActiveScheme(llvm::ArrayRef< llvm::StringRef > prefixes, llvm::ArrayRef< RegisteredManglingScheme > schemes)
Returns true if a name could start with both one of prefixes and a prefix of one of the active scheme...
Definition Mangled.cpp:78
Many cache files require string tables to store data efficiently.
uint32_t Add(ConstString s)
Add a string into the string table.
A uniqued constant string class.
Definition ConstString.h:40
static int Compare(ConstString lhs, ConstString rhs, const bool case_sensitive=true)
Compare two string objects.
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
An binary data encoding class.
Definition DataEncoder.h:42
void AppendU32(uint32_t value)
void AppendU8(uint8_t value)
Append a unsigned integer to the end of the owned data.
An data extractor class.
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
uint8_t GetU8(lldb::offset_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
virtual DemangledName DemangleSymbol(ConstString mangled, Mangled::ManglingScheme scheme, const DemangleOptions &options) const
Demangle mangled, a name mangled with scheme, a scheme that this language registered with Mangled::Re...
Definition Language.h:353
static void ForEach(llvm::function_ref< IterationAction(Language *)> callback)
Definition Language.cpp:154
static Language * FindPlugin(lldb::LanguageType language)
Definition Language.cpp:89
static Language * FindPluginForManglingScheme(Mangled::ManglingScheme scheme)
Returns the Language that registered scheme with Mangled::RegisterManglingScheme(),...
Definition Language.cpp:133
A class that handles mangled names.
Definition Mangled.h:36
void Encode(DataEncoder &encoder, ConstStringTable &strtab) const
Encode this object into a data encoder object.
Definition Mangled.cpp:455
bool NameMatches(ConstString name) const
Check if "name" matches either the mangled or demangled name.
Definition Mangled.h:189
static int Compare(const Mangled &lhs, const Mangled &rhs)
Compare the mangled string values.
Definition Mangled.cpp:214
static ManglingScheme RegisterManglingScheme(llvm::ArrayRef< llvm::StringRef > prefixes, lldb::LanguageType language, ManglingSchemeMatcher matches=nullptr)
Register a mangling scheme for language.
Definition Mangled.cpp:163
static bool IsMangledName(llvm::StringRef name)
Definition Mangled.cpp:178
@ ePreferDemangledWithoutArguments
Definition Mangled.h:41
Mangled()=default
Default constructor.
void DumpDebug(Stream *s) const
Dump a debug description of this object to a Stream s.
Definition Mangled.cpp:330
std::optional< DemangledNameInfo > ComputeDemangledInfo() const
Compute the DemangledNameInfo of the demangled name.
Definition Mangled.cpp:268
ConstString GetMangledName() const
Mangled name get accessor.
Definition Mangled.h:169
ConstString GetDemangledName() const
Demangled name get accessor.
Definition Mangled.cpp:238
ConstString GetBaseName() const
Compute the base name (without namespace/class qualifiers) from the demangled name.
Definition Mangled.cpp:487
bool(*)(llvm::StringRef name) ManglingSchemeMatcher
Definition Mangled.h:233
lldb::LanguageType GuessLanguage() const
Try to guess the language from the mangling.
Definition Mangled.cpp:344
bool Decode(const DataExtractor &data, lldb::offset_t *offset_ptr, const StringTableReader &strtab)
Decode a serialized version of this object from data.
Definition Mangled.cpp:404
static constexpr size_t g_num_mangling_schemes
The number of possible mangling schemes, which sizes the tables that are indexed by ManglingScheme.
Definition Mangled.h:51
static lldb::LanguageType GetLanguageForManglingScheme(ManglingScheme scheme)
Returns the language that registered scheme, or eLanguageTypeUnknown if no language did.
Definition Mangled.cpp:174
void SetValue(ConstString name)
Set the string value in this object.
Definition Mangled.cpp:219
ConstString GetName(NamePreference preference=ePreferDemangled) const
Best name get accessor.
Definition Mangled.cpp:297
static Mangled::ManglingScheme GetManglingScheme(llvm::StringRef name)
Try to identify the mangling scheme used.
Definition Mangled.cpp:182
ConstString m_mangled
The mangled version of the name.
Definition Mangled.h:309
ConstString m_demangled
Mutable so we can get it on demand with a const version of this object.
Definition Mangled.h:313
ConstString GetDisplayDemangledName() const
Display demangled name get accessor.
Definition Mangled.cpp:282
void Dump(Stream *s) const
Dump a description of this object to a Stream s.
Definition Mangled.cpp:320
static void UnregisterManglingScheme(ManglingScheme scheme)
Stop recognizing the names of scheme, a scheme returned by RegisterManglingScheme().
Definition Mangled.cpp:169
void Clear()
Clear the mangled and demangled values.
Definition Mangled.cpp:208
bool Execute(llvm::StringRef string, llvm::SmallVectorImpl< llvm::StringRef > *matches=nullptr) const
Execute a regular expression match using the compiled regular expression that is already in this obje...
A stream class that can stream formatted output to a file.
Definition Stream.h:28
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
Definition Stream.h:370
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
Many cache files require string tables to store data efficiently.
llvm::StringRef Get(uint32_t offset) const
A class that represents a running process on the host machine.
Stream & operator<<(Stream &s, const Mangled &obj)
uint64_t offset_t
Definition lldb-types.h:86
LanguageType
Programming language type.
@ eLanguageTypeUnknown
Unknown or invalid language value.
How to demangle a name in DemangleSymbol().
Definition Language.h:338
bool want_info
Whether to compute the DemangledNameInfo too.
Definition Language.h:340
A demangled name and, if requested, where its parts begin and end.
Definition Language.h:344
std::optional< DemangledNameInfo > info
Only computed if DemangleOptions::want_info is true.
Definition Language.h:348
std::string name
Empty if the name couldn't be demangled.
Definition Language.h:346