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/Log.h"
19#include "lldb/Utility/Stream.h"
21
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/ADT/StringRef.h"
24#include "llvm/Demangle/Demangle.h"
25#include "llvm/Support/Compiler.h"
26
27#include <mutex>
28#include <optional>
29#include <string>
30#include <string_view>
31#include <utility>
32
33#include <cstdlib>
34#include <cstring>
35using namespace lldb_private;
36
37#pragma mark Mangled
38
39bool Mangled::IsMangledName(llvm::StringRef name) {
41}
42
44 if (name.empty())
46
47 if (name.starts_with("?"))
49
50 if (name.starts_with("_R"))
52
53 if (name.starts_with("_D")) {
54 // A dlang mangled name begins with `_D`, followed by a numeric length. One
55 // known exception is the symbol `_Dmain`.
56 // See `SymbolName` and `LName` in
57 // https://dlang.org/spec/abi.html#name_mangling
58 llvm::StringRef buf = name.drop_front(2);
59 if (!buf.empty() && (llvm::isDigit(buf.front()) || name == "_Dmain"))
61 }
62
63 if (name.starts_with("_Z"))
65
66 // ___Z is a clang extension of block invocations
67 if (name.starts_with("___Z"))
69
70 // Swift's older style of mangling used "_T" as a mangling prefix. This can
71 // lead to false positives with other symbols that just so happen to start
72 // with "_T". To minimize the chance of that happening, we only return true
73 // for select old-style swift mangled names. The known cases are ObjC classes
74 // and protocols. Classes are either prefixed with "_TtC" or "_TtGC".
75 // Protocols are prefixed with "_TtP".
76 if (name.starts_with("_TtC") || name.starts_with("_TtGC") ||
77 name.starts_with("_TtP"))
79
80 // Swift 4.2 used "$S" and "_$S".
81 // Swift 5 and onward uses "$s" and "_$s".
82 // Swift also uses "@__swiftmacro_" as a prefix for mangling filenames.
83 // Embedded Swift introduced "$e" and "_$e" as Swift mangling prefixes.
84 if (name.starts_with("$S") || name.starts_with("_$S") ||
85 name.starts_with("$s") || name.starts_with("_$s") ||
86 name.starts_with("$e") || name.starts_with("_$e") ||
87 name.starts_with("@__swiftmacro_"))
89
91}
92
97
98Mangled::Mangled(llvm::StringRef name) {
99 if (!name.empty())
100 SetValue(ConstString(name));
101}
102
103// Convert to bool operator. This allows code to check any Mangled objects
104// to see if they contain anything valid using code such as:
105//
106// Mangled mangled(...);
107// if (mangled)
108// { ...
109Mangled::operator bool() const { return m_mangled || m_demangled; }
110
111// Clear the mangled and demangled values.
113 m_mangled.Clear();
114 m_demangled.Clear();
115}
116
117// Compare the string values.
122
124 if (name) {
125 if (IsMangledName(name.GetStringRef())) {
126 m_demangled.Clear();
127 m_mangled = name;
128 } else {
129 m_demangled = name;
130 m_mangled.Clear();
131 }
132 } else {
133 m_demangled.Clear();
134 m_mangled.Clear();
135 }
136}
137
138// Local helpers for different demangling implementations.
139static char *GetRustV0DemangledStr(llvm::StringRef M) {
140 char *demangled_cstr = llvm::rustDemangle(M);
141
142 if (Log *log = GetLog(LLDBLog::Demangle)) {
143 if (demangled_cstr && demangled_cstr[0])
144 LLDB_LOG(log, "demangled rustv0: {0} -> \"{1}\"", M, demangled_cstr);
145 else
146 LLDB_LOG(log, "demangled rustv0: {0} -> error: failed to demangle",
147 static_cast<std::string_view>(M));
148 }
149
150 return demangled_cstr;
151}
152
153static char *GetDLangDemangledStr(llvm::StringRef M) {
154 char *demangled_cstr = llvm::dlangDemangle(M);
155
156 if (Log *log = GetLog(LLDBLog::Demangle)) {
157 if (demangled_cstr && demangled_cstr[0])
158 LLDB_LOG(log, "demangled dlang: {0} -> \"{1}\"", M, demangled_cstr);
159 else
160 LLDB_LOG(log, "demangled dlang: {0} -> error: failed to demangle",
161 static_cast<std::string_view>(M));
162 }
163
164 return demangled_cstr;
165}
166
167// Generate the demangled name on demand using this accessor. Code in this
168// class will need to use this accessor if it wishes to decode the demangled
169// name. The result is cached and will be kept until a new string value is
170// supplied to this object, or until the end of the object's lifetime.
172 if (!m_mangled)
173 return m_demangled;
174
175 // Re-use previously demangled names.
176 if (!m_demangled.IsNull())
177 return m_demangled;
178
179 if (m_mangled.GetMangledCounterpart(m_demangled) && !m_demangled.IsNull())
180 return m_demangled;
181
182 // We didn't already mangle this name, demangle it and if all goes well
183 // add it to our map.
184 ManglingScheme scheme = GetManglingScheme(m_mangled.GetStringRef());
185 char *demangled_name = nullptr;
186 switch (scheme) {
189 // The C++ language plugin demangles C++ names.
191 Language::DemangledName demangled =
192 lang->DemangleSymbol(m_mangled, scheme, Language::DemangleOptions());
193 if (!demangled.name.empty())
194 m_demangled.SetStringWithMangledCounterpart(demangled.name, m_mangled);
195 }
196 break;
198 demangled_name = GetRustV0DemangledStr(m_mangled);
199 break;
200 case eManglingSchemeD:
201 demangled_name = GetDLangDemangledStr(m_mangled);
202 break;
204 // Demangling a swift name requires the swift compiler. This is
205 // explicitly unsupported on llvm.org.
206 break;
208 // Don't bother demangling anything that isn't mangled.
209 break;
210 }
211
212 if (demangled_name) {
213 m_demangled.SetStringWithMangledCounterpart(demangled_name, m_mangled);
214 free(demangled_name);
215 }
216
217 if (m_demangled.IsNull()) {
218 // Set the demangled string to the empty string to indicate we tried to
219 // parse it once and failed.
220 m_demangled.SetCString("");
221 }
222
223 return m_demangled;
224}
225
226std::optional<DemangledNameInfo> Mangled::ComputeDemangledInfo() const {
227 // Only supported for itanium.
228 if (!m_mangled ||
230 return std::nullopt;
231
232 Language *lang =
234 if (!lang)
235 return std::nullopt;
236
238 options.want_info = true;
239 return lang->DemangleSymbol(m_mangled, eManglingSchemeItanium, options).info;
240}
241
244 return lang->GetDisplayDemangledName(*this);
245 return GetDemangledName();
246}
247
248bool Mangled::NameMatches(const RegularExpression &regex) const {
249 if (m_mangled && regex.Execute(m_mangled.GetStringRef()))
250 return true;
251
252 ConstString demangled = GetDemangledName();
253 return demangled && regex.Execute(demangled.GetStringRef());
254}
255
256// Get the demangled name if there is one, else return the mangled name.
258 if (preference == ePreferMangled && m_mangled)
259 return m_mangled;
260
261 // Call the accessor to make sure we get a demangled name in case it hasn't
262 // been demangled yet...
263 ConstString demangled = GetDemangledName();
264
265 if (preference == ePreferDemangledWithoutArguments) {
267 return lang->GetDemangledFunctionNameWithoutArguments(*this);
268 }
269 }
270 if (preference == ePreferDemangled) {
271 if (demangled)
272 return demangled;
273 return m_mangled;
274 }
275 return demangled;
276}
277
278// Dump a Mangled object to stream "s". We don't force our demangled name to be
279// computed currently (we don't use the accessor).
280void Mangled::Dump(Stream *s) const {
281 if (m_mangled) {
282 *s << ", mangled = " << m_mangled;
283 }
284 if (m_demangled)
285 s->Format(", demangled = {0}", m_demangled.GetStringRef());
286}
287
288// Dumps a debug version of this string with extra object and state information
289// to stream "s".
291 s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2),
292 static_cast<const void *>(this));
293 m_mangled.DumpDebug(s);
294 s->PutCString(", demangled = ");
295 m_demangled.DumpDebug(s);
296}
297
298// We "guess" the language because we can't determine a symbol's language from
299// it's name. For example, a Pascal symbol can be mangled using the C++
300// Itanium scheme, and defined in a compilation unit within the same module as
301// other C++ units. In addition, different targets could have different ways
302// of mangling names from a given language, likewise the compilation units
303// within those targets.
306 // Ask each language plugin to check if the mangled name belongs to it.
307 Language::ForEach([this, &result](Language *l) {
308 if (l->SymbolNameFitsToLanguage(*this)) {
309 result = l->GetLanguageType();
311 }
313 });
314 return result;
315}
316
317// Dump OBJ to the supplied stream S.
318Stream &operator<<(Stream &s, const Mangled &obj) {
319 if (obj.GetMangledName())
320 s << "mangled = '" << obj.GetMangledName() << "'";
321
322 ConstString demangled = obj.GetDemangledName();
323 if (demangled)
324 s << ", demangled = '" << demangled << '\'';
325 else
326 s << ", demangled = <error>";
327 return s;
328}
329
330// When encoding Mangled objects we can get away with encoding as little
331// information as is required. The enumeration below helps us to efficiently
332// encode Mangled objects.
334 /// If the Mangled object has neither a mangled name or demangled name we can
335 /// encode the object with one zero byte using the Empty enumeration.
336 Empty = 0u,
337 /// If the Mangled object has only a demangled name and no mangled named, we
338 /// can encode only the demangled name.
340 /// If the mangle name can calculate the demangled name (it is the
341 /// mangled/demangled counterpart), then we only need to encode the mangled
342 /// name as the demangled name can be recomputed.
344 /// If we have a Mangled object with two different names that are not related
345 /// then we need to save both strings. This can happen if we have a name that
346 /// isn't a true mangled name, but we want to be able to lookup a symbol by
347 /// name and type in the symbol table. We do this for Objective C symbols like
348 /// "OBJC_CLASS_$_NSValue" where the mangled named will be set to
349 /// "OBJC_CLASS_$_NSValue" and the demangled name will be manually set to
350 /// "NSValue". If we tried to demangled the name "OBJC_CLASS_$_NSValue" it
351 /// would fail, but in these cases we want these unrelated names to be
352 /// preserved.
354};
355
356bool Mangled::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
357 const StringTableReader &strtab) {
358 m_mangled.Clear();
359 m_demangled.Clear();
360 MangledEncoding encoding = (MangledEncoding)data.GetU8(offset_ptr);
361 switch (encoding) {
362 case Empty:
363 return true;
364
365 case DemangledOnly:
366 m_demangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
367 return true;
368
369 case MangledOnly:
370 m_mangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
371 return true;
372
374 m_mangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
375 m_demangled.SetString(strtab.Get(data.GetU32(offset_ptr)));
376 return true;
377 }
378 return false;
379}
380/// The encoding format for the Mangled object is as follows:
381///
382/// uint8_t encoding;
383/// char str1[]; (only if DemangledOnly, MangledOnly)
384/// char str2[]; (only if MangledAndDemangled)
385///
386/// The strings are stored as null-terminated UTF8 strings and str1 and str2
387/// are only saved if we need them based on the encoding.
388///
389/// Some mangled names have a mangled name that can be demangled by the built
390/// in demanglers. These kinds of mangled objects know when the mangled and
391/// demangled names are the counterparts for each other. This is done because
392/// demangling is very expensive and avoiding demangling the same name twice
393/// saves us a lot of compute time. For these kinds of names we only need to
394/// save the mangled name and have the encoding set to "MangledOnly".
395///
396/// If a mangled object has only a demangled name, then we save only that string
397/// and have the encoding set to "DemangledOnly".
398///
399/// Some mangled objects have both mangled and demangled names, but the
400/// demangled name can not be computed from the mangled name. This is often used
401/// for runtime named, like Objective C runtime V2 and V3 names. Both these
402/// names must be saved and the encoding is set to "MangledAndDemangled".
403///
404/// For a Mangled object with no names, we only need to set the encoding to
405/// "Empty" and not store any string values.
406void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const {
407 MangledEncoding encoding = Empty;
408 if (m_mangled) {
409 encoding = MangledOnly;
410 if (m_demangled) {
411 // We have both mangled and demangled names. If the demangled name is the
412 // counterpart of the mangled name, then we only need to save the mangled
413 // name. If they are different, we need to save both.
414 ConstString s;
415 if (!(m_mangled.GetMangledCounterpart(s) && s == m_demangled))
416 encoding = MangledAndDemangled;
417 }
418 } else if (m_demangled) {
419 encoding = DemangledOnly;
420 }
421 file.AppendU8(encoding);
422 switch (encoding) {
423 case Empty:
424 break;
425 case DemangledOnly:
426 file.AppendU32(strtab.Add(m_demangled));
427 break;
428 case MangledOnly:
429 file.AppendU32(strtab.Add(m_mangled));
430 break;
432 file.AppendU32(strtab.Add(m_mangled));
433 file.AppendU32(strtab.Add(m_demangled));
434 break;
435 }
436}
437
439 std::optional<DemangledNameInfo> demangled_info = ComputeDemangledInfo();
440 if (!demangled_info)
441 return {};
442
443 ConstString demangled_name = GetDemangledName();
444 if (!demangled_name)
445 return {};
446
447 const auto &range = demangled_info->BasenameRange;
448 return ConstString(
449 demangled_name.GetStringRef().slice(range.first, range.second));
450}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
static char * GetDLangDemangledStr(llvm::StringRef M)
Definition Mangled.cpp:153
static char * GetRustV0DemangledStr(llvm::StringRef M)
Definition Mangled.cpp:139
MangledEncoding
Definition Mangled.cpp:333
@ 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:353
@ DemangledOnly
If the Mangled object has only a demangled name and no mangled named, we can encode only the demangle...
Definition Mangled.cpp:339
@ Empty
If the Mangled object has neither a mangled name or demangled name we can encode the object with one ...
Definition Mangled.cpp:336
@ MangledOnly
If the mangle name can calculate the demangled name (it is the mangled/demangled counterpart),...
Definition Mangled.cpp:343
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 handles.
Definition Language.h:354
static void ForEach(llvm::function_ref< IterationAction(Language *)> callback)
Definition Language.cpp:156
static Language * FindPlugin(lldb::LanguageType language)
Definition Language.cpp:86
static Language * FindPluginForManglingScheme(Mangled::ManglingScheme scheme)
Returns the Language that handles names mangled with scheme, or a nullptr if there is none.
Definition Language.cpp:130
A class that handles mangled names.
Definition Mangled.h:34
void Encode(DataEncoder &encoder, ConstStringTable &strtab) const
Encode this object into a data encoder object.
Definition Mangled.cpp:406
bool NameMatches(ConstString name) const
Check if "name" matches either the mangled or demangled name.
Definition Mangled.h:190
static int Compare(const Mangled &lhs, const Mangled &rhs)
Compare the mangled string values.
Definition Mangled.cpp:118
static bool IsMangledName(llvm::StringRef name)
Definition Mangled.cpp:39
@ ePreferDemangledWithoutArguments
Definition Mangled.h:39
Mangled()=default
Default constructor.
void DumpDebug(Stream *s) const
Dump a debug description of this object to a Stream s.
Definition Mangled.cpp:290
std::optional< DemangledNameInfo > ComputeDemangledInfo() const
Compute the DemangledNameInfo of the demangled name.
Definition Mangled.cpp:226
ConstString GetMangledName() const
Mangled name get accessor.
Definition Mangled.h:170
ConstString GetDemangledName() const
Demangled name get accessor.
Definition Mangled.cpp:171
ConstString GetBaseName() const
Compute the base name (without namespace/class qualifiers) from the demangled name.
Definition Mangled.cpp:438
lldb::LanguageType GuessLanguage() const
Try to guess the language from the mangling.
Definition Mangled.cpp:304
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:356
void SetValue(ConstString name)
Set the string value in this object.
Definition Mangled.cpp:123
ConstString GetName(NamePreference preference=ePreferDemangled) const
Best name get accessor.
Definition Mangled.cpp:257
static Mangled::ManglingScheme GetManglingScheme(llvm::StringRef name)
Try to identify the mangling scheme used.
Definition Mangled.cpp:43
ConstString m_mangled
The mangled version of the name.
Definition Mangled.h:285
ConstString m_demangled
Mutable so we can get it on demand with a const version of this object.
Definition Mangled.h:289
ConstString GetDisplayDemangledName() const
Display demangled name get accessor.
Definition Mangled.cpp:242
void Dump(Stream *s) const
Dump a description of this object to a Stream s.
Definition Mangled.cpp:280
void Clear()
Clear the mangled and demangled values.
Definition Mangled.cpp:112
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.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
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:339
bool want_info
Whether to compute the DemangledNameInfo too.
Definition Language.h:341
A demangled name and, if requested, where its parts begin and end.
Definition Language.h:345
std::optional< DemangledNameInfo > info
Only computed if DemangleOptions::want_info is true.
Definition Language.h:349
std::string name
Empty if the name couldn't be demangled.
Definition Language.h:347