1 //===-- CPlusPlusLanguage.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 "CPlusPlusLanguage.h"
10
11 #include <cctype>
12 #include <cstring>
13
14 #include <functional>
15 #include <memory>
16 #include <mutex>
17 #include <set>
18
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Demangle/ItaniumDemangle.h"
21
22 #include "lldb/Core/Mangled.h"
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/PluginManager.h"
25 #include "lldb/Core/UniqueCStringMap.h"
26 #include "lldb/DataFormatters/CXXFunctionPointer.h"
27 #include "lldb/DataFormatters/DataVisualization.h"
28 #include "lldb/DataFormatters/FormattersHelpers.h"
29 #include "lldb/DataFormatters/VectorType.h"
30 #include "lldb/Interpreter/OptionValueProperties.h"
31 #include "lldb/Symbol/SymbolFile.h"
32 #include "lldb/Symbol/VariableList.h"
33 #include "lldb/Utility/ConstString.h"
34 #include "lldb/Utility/LLDBLog.h"
35 #include "lldb/Utility/Log.h"
36 #include "lldb/Utility/RegularExpression.h"
37 #include "lldb/ValueObject/ValueObjectVariable.h"
38
39 #include "BlockPointer.h"
40 #include "CPlusPlusNameParser.h"
41 #include "Coroutines.h"
42 #include "CxxStringTypes.h"
43 #include "Generic.h"
44 #include "LibCxx.h"
45 #include "LibCxxAtomic.h"
46 #include "LibCxxVariant.h"
47 #include "LibStdcpp.h"
48 #include "MSVCUndecoratedNameParser.h"
49 #include "MsvcStl.h"
50 #include "lldb/lldb-enumerations.h"
51
52 using namespace lldb;
53 using namespace lldb_private;
54 using namespace lldb_private::formatters;
55
LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)56 LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)
57
58 void CPlusPlusLanguage::Initialize() {
59 PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
60 CreateInstance, &DebuggerInitialize);
61 }
62
Terminate()63 void CPlusPlusLanguage::Terminate() {
64 PluginManager::UnregisterPlugin(CreateInstance);
65 }
66
67 std::unique_ptr<Language::MethodName>
GetMethodName(ConstString full_name) const68 CPlusPlusLanguage::GetMethodName(ConstString full_name) const {
69 std::unique_ptr<CxxMethodName> cpp_method =
70 std::make_unique<CxxMethodName>(full_name);
71 cpp_method->IsValid();
72 return cpp_method;
73 }
74
75 std::pair<FunctionNameType, std::optional<ConstString>>
GetFunctionNameInfo(ConstString name) const76 CPlusPlusLanguage::GetFunctionNameInfo(ConstString name) const {
77 if (Mangled::IsMangledName(name.GetCString()))
78 return {eFunctionNameTypeFull, std::nullopt};
79
80 FunctionNameType func_name_type = eFunctionNameTypeNone;
81 CxxMethodName method(name);
82 llvm::StringRef basename = method.GetBasename();
83 if (basename.empty()) {
84 llvm::StringRef context;
85 func_name_type |=
86 (ExtractContextAndIdentifier(name.GetCString(), context, basename)
87 ? (eFunctionNameTypeMethod | eFunctionNameTypeBase)
88 : eFunctionNameTypeFull);
89 } else {
90 func_name_type |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
91 }
92
93 if (!method.GetQualifiers().empty()) {
94 // There is a 'const' or other qualifier following the end of the function
95 // parens, this can't be a eFunctionNameTypeBase.
96 func_name_type &= ~(eFunctionNameTypeBase);
97 }
98
99 if (basename.empty())
100 return {func_name_type, std::nullopt};
101 else
102 return {func_name_type, ConstString(basename)};
103 }
104
SymbolNameFitsToLanguage(Mangled mangled) const105 bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
106 const char *mangled_name = mangled.GetMangledName().GetCString();
107 return mangled_name && Mangled::IsMangledName(mangled_name);
108 }
109
GetDemangledFunctionNameWithoutArguments(Mangled mangled) const110 ConstString CPlusPlusLanguage::GetDemangledFunctionNameWithoutArguments(
111 Mangled mangled) const {
112 const char *mangled_name_cstr = mangled.GetMangledName().GetCString();
113 ConstString demangled_name = mangled.GetDemangledName();
114 if (demangled_name && mangled_name_cstr && mangled_name_cstr[0]) {
115 if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
116 (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure,
117 // typeinfo structure, and typeinfo
118 // mangled_name
119 mangled_name_cstr[2] != 'G' && // avoid guard variables
120 mangled_name_cstr[2] != 'Z')) // named local entities (if we
121 // eventually handle eSymbolTypeData,
122 // we will want this back)
123 {
124 CxxMethodName cxx_method(demangled_name);
125 if (!cxx_method.GetBasename().empty()) {
126 std::string shortname;
127 if (!cxx_method.GetContext().empty())
128 shortname = cxx_method.GetContext().str() + "::";
129 shortname += cxx_method.GetBasename().str();
130 return ConstString(shortname);
131 }
132 }
133 }
134 if (demangled_name)
135 return demangled_name;
136 return mangled.GetMangledName();
137 }
138
139 // Static Functions
140
CreateInstance(lldb::LanguageType language)141 Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) {
142 // Use plugin for C++ but not for Objective-C++ (which has its own plugin).
143 if (Language::LanguageIsCPlusPlus(language) &&
144 language != eLanguageTypeObjC_plus_plus)
145 return new CPlusPlusLanguage();
146 return nullptr;
147 }
148
ReverseFindMatchingChars(const llvm::StringRef & s,const llvm::StringRef & left_right_chars,size_t & left_pos,size_t & right_pos,size_t pos=llvm::StringRef::npos)149 static bool ReverseFindMatchingChars(const llvm::StringRef &s,
150 const llvm::StringRef &left_right_chars,
151 size_t &left_pos, size_t &right_pos,
152 size_t pos = llvm::StringRef::npos) {
153 assert(left_right_chars.size() == 2);
154 left_pos = llvm::StringRef::npos;
155 const char left_char = left_right_chars[0];
156 const char right_char = left_right_chars[1];
157 pos = s.find_last_of(left_right_chars, pos);
158 if (pos == llvm::StringRef::npos || s[pos] == left_char)
159 return false;
160 right_pos = pos;
161 uint32_t depth = 1;
162 while (pos > 0 && depth > 0) {
163 pos = s.find_last_of(left_right_chars, pos);
164 if (pos == llvm::StringRef::npos)
165 return false;
166 if (s[pos] == left_char) {
167 if (--depth == 0) {
168 left_pos = pos;
169 return left_pos < right_pos;
170 }
171 } else if (s[pos] == right_char) {
172 ++depth;
173 }
174 }
175 return false;
176 }
177
IsTrivialBasename(const llvm::StringRef & basename)178 static bool IsTrivialBasename(const llvm::StringRef &basename) {
179 // Check that the basename matches with the following regular expression
180 // "^~?([A-Za-z_][A-Za-z_0-9]*)$" We are using a hand written implementation
181 // because it is significantly more efficient then using the general purpose
182 // regular expression library.
183 size_t idx = 0;
184 if (basename.starts_with('~'))
185 idx = 1;
186
187 if (basename.size() <= idx)
188 return false; // Empty string or "~"
189
190 if (!std::isalpha(basename[idx]) && basename[idx] != '_')
191 return false; // First character (after removing the possible '~'') isn't in
192 // [A-Za-z_]
193
194 // Read all characters matching [A-Za-z_0-9]
195 ++idx;
196 while (idx < basename.size()) {
197 if (!std::isalnum(basename[idx]) && basename[idx] != '_')
198 break;
199 ++idx;
200 }
201
202 // We processed all characters. It is a vaild basename.
203 return idx == basename.size();
204 }
205
206 /// Writes out the function name in 'full_name' to 'out_stream'
207 /// but replaces each argument type with the variable name
208 /// and the corresponding pretty-printed value
PrettyPrintFunctionNameWithArgs(Stream & out_stream,char const * full_name,ExecutionContextScope * exe_scope,VariableList const & args)209 static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
210 char const *full_name,
211 ExecutionContextScope *exe_scope,
212 VariableList const &args) {
213 CPlusPlusLanguage::CxxMethodName cpp_method{ConstString(full_name)};
214
215 if (!cpp_method.IsValid())
216 return false;
217
218 llvm::StringRef return_type = cpp_method.GetReturnType();
219 if (!return_type.empty()) {
220 out_stream.PutCString(return_type);
221 out_stream.PutChar(' ');
222 }
223
224 out_stream.PutCString(cpp_method.GetScopeQualifiedName());
225 out_stream.PutChar('(');
226
227 FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope);
228
229 out_stream.PutChar(')');
230
231 llvm::StringRef qualifiers = cpp_method.GetQualifiers();
232 if (!qualifiers.empty()) {
233 out_stream.PutChar(' ');
234 out_stream.PutCString(qualifiers);
235 }
236
237 return true;
238 }
239
240 static llvm::Expected<std::pair<llvm::StringRef, DemangledNameInfo>>
GetAndValidateInfo(const SymbolContext & sc)241 GetAndValidateInfo(const SymbolContext &sc) {
242 Mangled mangled = sc.GetPossiblyInlinedFunctionName();
243 if (!mangled)
244 return llvm::createStringError("Function does not have a mangled name.");
245
246 auto demangled_name = mangled.GetDemangledName().GetStringRef();
247 if (demangled_name.empty())
248 return llvm::createStringError(
249 "Function '%s' does not have a demangled name.",
250 mangled.GetMangledName().AsCString(""));
251
252 const std::optional<DemangledNameInfo> &info = mangled.GetDemangledInfo();
253 if (!info)
254 return llvm::createStringError(
255 "Function '%s' does not have demangled info.", demangled_name.data());
256
257 // Function without a basename is nonsense.
258 if (!info->hasBasename())
259 return llvm::createStringError(
260 "DemangledInfo for '%s does not have basename range.",
261 demangled_name.data());
262
263 return std::make_pair(demangled_name, *info);
264 }
265
266 static llvm::Expected<llvm::StringRef>
GetDemangledBasename(const SymbolContext & sc)267 GetDemangledBasename(const SymbolContext &sc) {
268 auto info_or_err = GetAndValidateInfo(sc);
269 if (!info_or_err)
270 return info_or_err.takeError();
271
272 auto [demangled_name, info] = *info_or_err;
273
274 return demangled_name.slice(info.BasenameRange.first,
275 info.BasenameRange.second);
276 }
277
278 static llvm::Expected<llvm::StringRef>
GetDemangledTemplateArguments(const SymbolContext & sc)279 GetDemangledTemplateArguments(const SymbolContext &sc) {
280 auto info_or_err = GetAndValidateInfo(sc);
281 if (!info_or_err)
282 return info_or_err.takeError();
283
284 auto [demangled_name, info] = *info_or_err;
285
286 if (info.ArgumentsRange.first < info.BasenameRange.second)
287 return llvm::createStringError("Arguments range for '%s' is invalid.",
288 demangled_name.data());
289
290 return demangled_name.slice(info.BasenameRange.second,
291 info.ArgumentsRange.first);
292 }
293
294 static llvm::Expected<llvm::StringRef>
GetDemangledReturnTypeLHS(const SymbolContext & sc)295 GetDemangledReturnTypeLHS(const SymbolContext &sc) {
296 auto info_or_err = GetAndValidateInfo(sc);
297 if (!info_or_err)
298 return info_or_err.takeError();
299
300 auto [demangled_name, info] = *info_or_err;
301
302 if (info.ScopeRange.first >= demangled_name.size())
303 return llvm::createStringError(
304 "Scope range for '%s' LHS return type is invalid.",
305 demangled_name.data());
306
307 return demangled_name.substr(0, info.ScopeRange.first);
308 }
309
310 static llvm::Expected<llvm::StringRef>
GetDemangledFunctionQualifiers(const SymbolContext & sc)311 GetDemangledFunctionQualifiers(const SymbolContext &sc) {
312 auto info_or_err = GetAndValidateInfo(sc);
313 if (!info_or_err)
314 return info_or_err.takeError();
315
316 auto [demangled_name, info] = *info_or_err;
317
318 if (!info.hasQualifiers())
319 return llvm::createStringError("Qualifiers range for '%s' is invalid.",
320 demangled_name.data());
321
322 return demangled_name.slice(info.QualifiersRange.first,
323 info.QualifiersRange.second);
324 }
325
326 static llvm::Expected<llvm::StringRef>
GetDemangledReturnTypeRHS(const SymbolContext & sc)327 GetDemangledReturnTypeRHS(const SymbolContext &sc) {
328 auto info_or_err = GetAndValidateInfo(sc);
329 if (!info_or_err)
330 return info_or_err.takeError();
331
332 auto [demangled_name, info] = *info_or_err;
333
334 if (info.QualifiersRange.first < info.ArgumentsRange.second)
335 return llvm::createStringError(
336 "Qualifiers range for '%s' RHS return type is invalid.",
337 demangled_name.data());
338
339 return demangled_name.slice(info.ArgumentsRange.second,
340 info.QualifiersRange.first);
341 }
342
343 static llvm::Expected<llvm::StringRef>
GetDemangledScope(const SymbolContext & sc)344 GetDemangledScope(const SymbolContext &sc) {
345 auto info_or_err = GetAndValidateInfo(sc);
346 if (!info_or_err)
347 return info_or_err.takeError();
348
349 auto [demangled_name, info] = *info_or_err;
350
351 if (!info.hasScope())
352 return llvm::createStringError("Scope range for '%s' is invalid.",
353 demangled_name.data());
354
355 return demangled_name.slice(info.ScopeRange.first, info.ScopeRange.second);
356 }
357
358 /// Handles anything printed after the FunctionEncoding ItaniumDemangle
359 /// node. Most notably the DotSUffix node.
360 static llvm::Expected<llvm::StringRef>
GetDemangledFunctionSuffix(const SymbolContext & sc)361 GetDemangledFunctionSuffix(const SymbolContext &sc) {
362 auto info_or_err = GetAndValidateInfo(sc);
363 if (!info_or_err)
364 return info_or_err.takeError();
365
366 auto [demangled_name, info] = *info_or_err;
367
368 if (!info.hasSuffix())
369 return llvm::createStringError("Suffix range for '%s' is invalid.",
370 demangled_name.data());
371
372 return demangled_name.slice(info.SuffixRange.first, info.SuffixRange.second);
373 }
374
PrintDemangledArgumentList(Stream & s,const SymbolContext & sc)375 static bool PrintDemangledArgumentList(Stream &s, const SymbolContext &sc) {
376 assert(sc.symbol);
377
378 auto info_or_err = GetAndValidateInfo(sc);
379 if (!info_or_err) {
380 LLDB_LOG_ERROR(GetLog(LLDBLog::Language), info_or_err.takeError(),
381 "Failed to handle ${{function.formatted-arguments}} "
382 "frame-format variable: {0}");
383 return false;
384 }
385 auto [demangled_name, info] = *info_or_err;
386
387 if (!info.hasArguments())
388 return false;
389
390 s << demangled_name.slice(info.ArgumentsRange.first,
391 info.ArgumentsRange.second);
392
393 return true;
394 }
395
TrySimplifiedParse()396 bool CPlusPlusLanguage::CxxMethodName::TrySimplifiedParse() {
397 // This method tries to parse simple method definitions which are presumably
398 // most comman in user programs. Definitions that can be parsed by this
399 // function don't have return types and templates in the name.
400 // A::B::C::fun(std::vector<T> &) const
401 size_t arg_start, arg_end;
402 llvm::StringRef full(m_full.GetCString());
403 llvm::StringRef parens("()", 2);
404 if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
405 m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
406 if (arg_end + 1 < full.size())
407 m_qualifiers = full.substr(arg_end + 1).ltrim();
408
409 if (arg_start == 0)
410 return false;
411 size_t basename_end = arg_start;
412 size_t context_start = 0;
413 size_t context_end = full.rfind(':', basename_end);
414 if (context_end == llvm::StringRef::npos)
415 m_basename = full.substr(0, basename_end);
416 else {
417 if (context_start < context_end)
418 m_context = full.substr(context_start, context_end - 1 - context_start);
419 const size_t basename_begin = context_end + 1;
420 m_basename = full.substr(basename_begin, basename_end - basename_begin);
421 }
422
423 if (IsTrivialBasename(m_basename)) {
424 return true;
425 } else {
426 // The C++ basename doesn't match our regular expressions so this can't
427 // be a valid C++ method, clear everything out and indicate an error
428 m_context = llvm::StringRef();
429 m_basename = llvm::StringRef();
430 m_arguments = llvm::StringRef();
431 m_qualifiers = llvm::StringRef();
432 m_return_type = llvm::StringRef();
433 return false;
434 }
435 }
436 return false;
437 }
438
Parse()439 void CPlusPlusLanguage::CxxMethodName::Parse() {
440 if (!m_parsed && m_full) {
441 if (TrySimplifiedParse()) {
442 m_parse_error = false;
443 } else {
444 CPlusPlusNameParser parser(m_full.GetStringRef());
445 if (auto function = parser.ParseAsFunctionDefinition()) {
446 m_basename = function->name.basename;
447 m_context = function->name.context;
448 m_arguments = function->arguments;
449 m_qualifiers = function->qualifiers;
450 m_return_type = function->return_type;
451 m_parse_error = false;
452 } else {
453 m_parse_error = true;
454 }
455 }
456 if (m_context.empty()) {
457 m_scope_qualified = std::string(m_basename);
458 } else {
459 m_scope_qualified = m_context;
460 m_scope_qualified += "::";
461 m_scope_qualified += m_basename;
462 }
463 m_parsed = true;
464 }
465 }
466
467 llvm::StringRef
GetBasenameNoTemplateParameters()468 CPlusPlusLanguage::CxxMethodName::GetBasenameNoTemplateParameters() {
469 llvm::StringRef basename = GetBasename();
470 size_t arg_start, arg_end;
471 llvm::StringRef parens("<>", 2);
472 if (ReverseFindMatchingChars(basename, parens, arg_start, arg_end))
473 return basename.substr(0, arg_start);
474
475 return basename;
476 }
477
ContainsPath(llvm::StringRef path)478 bool CPlusPlusLanguage::CxxMethodName::ContainsPath(llvm::StringRef path) {
479 if (!m_parsed)
480 Parse();
481
482 // If we can't parse the incoming name, then just check that it contains path.
483 if (m_parse_error)
484 return m_full.GetStringRef().contains(path);
485
486 llvm::StringRef identifier;
487 llvm::StringRef context;
488 std::string path_str = path.str();
489 bool success = CPlusPlusLanguage::ExtractContextAndIdentifier(
490 path_str.c_str(), context, identifier);
491 if (!success)
492 return m_full.GetStringRef().contains(path);
493
494 // Basename may include template arguments.
495 // E.g.,
496 // GetBaseName(): func<int>
497 // identifier : func
498 //
499 // ...but we still want to account for identifiers with template parameter
500 // lists, e.g., when users set breakpoints on template specializations.
501 //
502 // E.g.,
503 // GetBaseName(): func<uint32_t>
504 // identifier : func<int32_t*>
505 //
506 // Try to match the basename with or without template parameters.
507 if (GetBasename() != identifier &&
508 GetBasenameNoTemplateParameters() != identifier)
509 return false;
510
511 // Incoming path only had an identifier, so we match.
512 if (context.empty())
513 return true;
514 // Incoming path has context but this method does not, no match.
515 if (m_context.empty())
516 return false;
517
518 llvm::StringRef haystack = m_context;
519 if (!haystack.consume_back(context))
520 return false;
521 if (haystack.empty() || !isalnum(haystack.back()))
522 return true;
523
524 return false;
525 }
526
DemangledNameContainsPath(llvm::StringRef path,ConstString demangled) const527 bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path,
528 ConstString demangled) const {
529 CxxMethodName demangled_name(demangled);
530 return demangled_name.ContainsPath(path);
531 }
532
ExtractContextAndIdentifier(const char * name,llvm::StringRef & context,llvm::StringRef & identifier)533 bool CPlusPlusLanguage::ExtractContextAndIdentifier(
534 const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
535 if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
536 return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
537 identifier);
538
539 CPlusPlusNameParser parser(name);
540 if (auto full_name = parser.ParseAsFullName()) {
541 identifier = full_name->basename;
542 context = full_name->context;
543 return true;
544 }
545 return false;
546 }
547
548 namespace {
549 class NodeAllocator {
550 llvm::BumpPtrAllocator Alloc;
551
552 public:
reset()553 void reset() { Alloc.Reset(); }
554
makeNode(Args &&...args)555 template <typename T, typename... Args> T *makeNode(Args &&...args) {
556 return new (Alloc.Allocate(sizeof(T), alignof(T)))
557 T(std::forward<Args>(args)...);
558 }
559
allocateNodeArray(size_t sz)560 void *allocateNodeArray(size_t sz) {
561 return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
562 alignof(llvm::itanium_demangle::Node *));
563 }
564 };
565
566 template <typename Derived>
567 class ManglingSubstitutor
568 : public llvm::itanium_demangle::AbstractManglingParser<Derived,
569 NodeAllocator> {
570 using Base =
571 llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
572
573 public:
ManglingSubstitutor()574 ManglingSubstitutor() : Base(nullptr, nullptr) {}
575
576 template <typename... Ts>
substitute(llvm::StringRef Mangled,Ts &&...Vals)577 ConstString substitute(llvm::StringRef Mangled, Ts &&...Vals) {
578 this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
579 return substituteImpl(Mangled);
580 }
581
582 protected:
reset(llvm::StringRef Mangled)583 void reset(llvm::StringRef Mangled) {
584 Base::reset(Mangled.begin(), Mangled.end());
585 Written = Mangled.begin();
586 Result.clear();
587 Substituted = false;
588 }
589
substituteImpl(llvm::StringRef Mangled)590 ConstString substituteImpl(llvm::StringRef Mangled) {
591 Log *log = GetLog(LLDBLog::Language);
592 if (this->parse() == nullptr) {
593 LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
594 return ConstString();
595 }
596 if (!Substituted)
597 return ConstString();
598
599 // Append any trailing unmodified input.
600 appendUnchangedInput();
601 LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
602 return ConstString(Result);
603 }
604
trySubstitute(llvm::StringRef From,llvm::StringRef To)605 void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
606 if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
607 return;
608
609 // We found a match. Append unmodified input up to this point.
610 appendUnchangedInput();
611
612 // And then perform the replacement.
613 Result += To;
614 Written += From.size();
615 Substituted = true;
616 }
617
618 private:
619 /// Input character until which we have constructed the respective output
620 /// already.
621 const char *Written = "";
622
623 llvm::SmallString<128> Result;
624
625 /// Whether we have performed any substitutions.
626 bool Substituted = false;
627
currentParserPos() const628 const char *currentParserPos() const { return this->First; }
629
appendUnchangedInput()630 void appendUnchangedInput() {
631 Result +=
632 llvm::StringRef(Written, std::distance(Written, currentParserPos()));
633 Written = currentParserPos();
634 }
635 };
636
637 /// Given a mangled function `Mangled`, replace all the primitive function type
638 /// arguments of `Search` with type `Replace`.
639 class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
640 llvm::StringRef Search;
641 llvm::StringRef Replace;
642
643 public:
reset(llvm::StringRef Mangled,llvm::StringRef Search,llvm::StringRef Replace)644 void reset(llvm::StringRef Mangled, llvm::StringRef Search,
645 llvm::StringRef Replace) {
646 ManglingSubstitutor::reset(Mangled);
647 this->Search = Search;
648 this->Replace = Replace;
649 }
650
parseType()651 llvm::itanium_demangle::Node *parseType() {
652 trySubstitute(Search, Replace);
653 return ManglingSubstitutor::parseType();
654 }
655 };
656
657 class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
658 public:
659 llvm::itanium_demangle::Node *
parseCtorDtorName(llvm::itanium_demangle::Node * & SoFar,NameState * State)660 parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
661 trySubstitute("C1", "C2");
662 trySubstitute("D1", "D2");
663 return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
664 }
665 };
666 } // namespace
667
GenerateAlternateFunctionManglings(const ConstString mangled_name) const668 std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
669 const ConstString mangled_name) const {
670 std::vector<ConstString> alternates;
671
672 /// Get a basic set of alternative manglings for the given symbol `name`, by
673 /// making a few basic possible substitutions on basic types, storage duration
674 /// and `const`ness for the given symbol. The output parameter `alternates`
675 /// is filled with a best-guess, non-exhaustive set of different manglings
676 /// for the given name.
677
678 // Maybe we're looking for a const symbol but the debug info told us it was
679 // non-const...
680 if (!strncmp(mangled_name.GetCString(), "_ZN", 3) &&
681 strncmp(mangled_name.GetCString(), "_ZNK", 4)) {
682 std::string fixed_scratch("_ZNK");
683 fixed_scratch.append(mangled_name.GetCString() + 3);
684 alternates.push_back(ConstString(fixed_scratch));
685 }
686
687 // Maybe we're looking for a static symbol but we thought it was global...
688 if (!strncmp(mangled_name.GetCString(), "_Z", 2) &&
689 strncmp(mangled_name.GetCString(), "_ZL", 3)) {
690 std::string fixed_scratch("_ZL");
691 fixed_scratch.append(mangled_name.GetCString() + 2);
692 alternates.push_back(ConstString(fixed_scratch));
693 }
694
695 TypeSubstitutor TS;
696 // `char` is implementation defined as either `signed` or `unsigned`. As a
697 // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
698 // char, 'h'-unsigned char. If we're looking for symbols with a signed char
699 // parameter, try finding matches which have the general case 'c'.
700 if (ConstString char_fixup =
701 TS.substitute(mangled_name.GetStringRef(), "a", "c"))
702 alternates.push_back(char_fixup);
703
704 // long long parameter mangling 'x', may actually just be a long 'l' argument
705 if (ConstString long_fixup =
706 TS.substitute(mangled_name.GetStringRef(), "x", "l"))
707 alternates.push_back(long_fixup);
708
709 // unsigned long long parameter mangling 'y', may actually just be unsigned
710 // long 'm' argument
711 if (ConstString ulong_fixup =
712 TS.substitute(mangled_name.GetStringRef(), "y", "m"))
713 alternates.push_back(ulong_fixup);
714
715 if (ConstString ctor_fixup =
716 CtorDtorSubstitutor().substitute(mangled_name.GetStringRef()))
717 alternates.push_back(ctor_fixup);
718
719 return alternates;
720 }
721
FindBestAlternateFunctionMangledName(const Mangled mangled,const SymbolContext & sym_ctx) const722 ConstString CPlusPlusLanguage::FindBestAlternateFunctionMangledName(
723 const Mangled mangled, const SymbolContext &sym_ctx) const {
724 ConstString demangled = mangled.GetDemangledName();
725 if (!demangled)
726 return ConstString();
727
728 CxxMethodName cpp_name(demangled);
729 std::string scope_qualified_name = cpp_name.GetScopeQualifiedName();
730
731 if (!scope_qualified_name.size())
732 return ConstString();
733
734 if (!sym_ctx.module_sp)
735 return ConstString();
736
737 lldb_private::SymbolFile *sym_file = sym_ctx.module_sp->GetSymbolFile();
738 if (!sym_file)
739 return ConstString();
740
741 std::vector<ConstString> alternates;
742 sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates);
743
744 std::vector<ConstString> param_and_qual_matches;
745 std::vector<ConstString> param_matches;
746 for (size_t i = 0; i < alternates.size(); i++) {
747 ConstString alternate_mangled_name = alternates[i];
748 Mangled mangled(alternate_mangled_name);
749 ConstString demangled = mangled.GetDemangledName();
750
751 CxxMethodName alternate_cpp_name(demangled);
752 if (!cpp_name.IsValid())
753 continue;
754
755 if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments()) {
756 if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers())
757 param_and_qual_matches.push_back(alternate_mangled_name);
758 else
759 param_matches.push_back(alternate_mangled_name);
760 }
761 }
762
763 if (param_and_qual_matches.size())
764 return param_and_qual_matches[0]; // It is assumed that there will be only
765 // one!
766 else if (param_matches.size())
767 return param_matches[0]; // Return one of them as a best match
768 else
769 return ConstString();
770 }
771
LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp)772 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
773 if (!cpp_category_sp)
774 return;
775
776 TypeSummaryImpl::Flags stl_summary_flags;
777 stl_summary_flags.SetCascades(true)
778 .SetSkipPointers(false)
779 .SetSkipReferences(false)
780 .SetDontShowChildren(true)
781 .SetDontShowValue(false)
782 .SetShowMembersOneLiner(false)
783 .SetHideItemNames(false);
784
785 AddCXXSummary(cpp_category_sp,
786 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
787 "std::string summary provider", "^std::__[[:alnum:]]+::string$",
788 stl_summary_flags, true);
789 AddCXXSummary(cpp_category_sp,
790 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
791 "std::string summary provider",
792 "^std::__[[:alnum:]]+::basic_string<char, "
793 "std::__[[:alnum:]]+::char_traits<char>,.*>$",
794 stl_summary_flags, true);
795 AddCXXSummary(cpp_category_sp,
796 lldb_private::formatters::LibcxxStringSummaryProviderASCII,
797 "std::string summary provider",
798 "^std::__[[:alnum:]]+::basic_string<unsigned char, "
799 "std::__[[:alnum:]]+::char_traits<unsigned char>,.*>$",
800 stl_summary_flags, true);
801
802 AddCXXSummary(cpp_category_sp,
803 lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
804 "std::u16string summary provider",
805 "^std::__[[:alnum:]]+::basic_string<char16_t, "
806 "std::__[[:alnum:]]+::char_traits<char16_t>,.*>$",
807 stl_summary_flags, true);
808
809 AddCXXSummary(cpp_category_sp,
810 lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
811 "std::u32string summary provider",
812 "^std::__[[:alnum:]]+::basic_string<char32_t, "
813 "std::__[[:alnum:]]+::char_traits<char32_t>,.*>$",
814 stl_summary_flags, true);
815
816 AddCXXSummary(cpp_category_sp,
817 lldb_private::formatters::LibcxxWStringSummaryProvider,
818 "std::wstring summary provider",
819 "^std::__[[:alnum:]]+::wstring$", stl_summary_flags, true);
820 AddCXXSummary(cpp_category_sp,
821 lldb_private::formatters::LibcxxWStringSummaryProvider,
822 "std::wstring summary provider",
823 "^std::__[[:alnum:]]+::basic_string<wchar_t, "
824 "std::__[[:alnum:]]+::char_traits<wchar_t>,.*>$",
825 stl_summary_flags, true);
826
827 AddCXXSummary(cpp_category_sp,
828 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
829 "std::string_view summary provider",
830 "^std::__[[:alnum:]]+::string_view$", stl_summary_flags, true);
831 AddCXXSummary(cpp_category_sp,
832 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
833 "std::string_view summary provider",
834 "^std::__[[:alnum:]]+::basic_string_view<char, "
835 "std::__[[:alnum:]]+::char_traits<char> >$",
836 stl_summary_flags, true);
837 AddCXXSummary(cpp_category_sp,
838 lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
839 "std::string_view summary provider",
840 "^std::__[[:alnum:]]+::basic_string_view<unsigned char, "
841 "std::__[[:alnum:]]+::char_traits<unsigned char> >$",
842 stl_summary_flags, true);
843
844 AddCXXSummary(cpp_category_sp,
845 lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16,
846 "std::u16string_view summary provider",
847 "^std::__[[:alnum:]]+::basic_string_view<char16_t, "
848 "std::__[[:alnum:]]+::char_traits<char16_t> >$",
849 stl_summary_flags, true);
850
851 AddCXXSummary(cpp_category_sp,
852 lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32,
853 "std::u32string_view summary provider",
854 "^std::__[[:alnum:]]+::basic_string_view<char32_t, "
855 "std::__[[:alnum:]]+::char_traits<char32_t> >$",
856 stl_summary_flags, true);
857
858 AddCXXSummary(cpp_category_sp,
859 lldb_private::formatters::LibcxxWStringViewSummaryProvider,
860 "std::wstring_view summary provider",
861 "^std::__[[:alnum:]]+::wstring_view$", stl_summary_flags, true);
862 AddCXXSummary(cpp_category_sp,
863 lldb_private::formatters::LibcxxWStringViewSummaryProvider,
864 "std::wstring_view summary provider",
865 "^std::__[[:alnum:]]+::basic_string_view<wchar_t, "
866 "std::__[[:alnum:]]+::char_traits<wchar_t> >$",
867 stl_summary_flags, true);
868
869 SyntheticChildren::Flags stl_synth_flags;
870 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
871 false);
872 SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
873 stl_deref_flags.SetFrontEndWantsDereference();
874
875 AddCXXSynthetic(
876 cpp_category_sp,
877 lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator,
878 "libc++ std::bitset synthetic children",
879 "^std::__[[:alnum:]]+::bitset<.+>$", stl_deref_flags, true);
880 AddCXXSynthetic(
881 cpp_category_sp,
882 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
883 "libc++ std::vector synthetic children",
884 "^std::__[[:alnum:]]+::vector<.+>$", stl_deref_flags, true);
885 AddCXXSynthetic(
886 cpp_category_sp,
887 lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator,
888 "libc++ std::valarray synthetic children",
889 "^std::__[[:alnum:]]+::valarray<.+>$", stl_deref_flags, true);
890 AddCXXSynthetic(
891 cpp_category_sp,
892 lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator,
893 "libc++ std::slice_array synthetic children",
894 "^std::__[[:alnum:]]+::slice_array<.+>$", stl_deref_flags, true);
895 AddCXXSynthetic(
896 cpp_category_sp,
897 lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator,
898 "libc++ synthetic children for the valarray proxy arrays",
899 "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
900 stl_deref_flags, true);
901 AddCXXSynthetic(
902 cpp_category_sp,
903 lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
904 "libc++ std::forward_list synthetic children",
905 "^std::__[[:alnum:]]+::forward_list<.+>$", stl_synth_flags, true);
906 AddCXXSynthetic(
907 cpp_category_sp,
908 lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator,
909 "libc++ std::list synthetic children",
910 // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$"
911 // so that it does not clash with: "^std::(__cxx11::)?list<.+>$"
912 "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
913 "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$",
914 stl_deref_flags, true);
915 AddCXXSynthetic(
916 cpp_category_sp,
917 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
918 "libc++ std::map synthetic children", "^std::__[[:alnum:]]+::map<.+> >$",
919 stl_synth_flags, true);
920 AddCXXSynthetic(
921 cpp_category_sp,
922 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
923 "libc++ std::set synthetic children", "^std::__[[:alnum:]]+::set<.+> >$",
924 stl_deref_flags, true);
925 AddCXXSynthetic(
926 cpp_category_sp,
927 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
928 "libc++ std::multiset synthetic children",
929 "^std::__[[:alnum:]]+::multiset<.+> >$", stl_deref_flags, true);
930 AddCXXSynthetic(
931 cpp_category_sp,
932 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
933 "libc++ std::multimap synthetic children",
934 "^std::__[[:alnum:]]+::multimap<.+> >$", stl_synth_flags, true);
935 AddCXXSynthetic(
936 cpp_category_sp,
937 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator,
938 "libc++ std::unordered containers synthetic children",
939 "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
940 stl_synth_flags, true);
941 AddCXXSynthetic(
942 cpp_category_sp,
943 lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
944 "libc++ std::initializer_list synthetic children",
945 "^std::initializer_list<.+>$", stl_synth_flags, true);
946 AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator,
947 "libc++ std::queue synthetic children",
948 "^std::__[[:alnum:]]+::queue<.+>$", stl_synth_flags, true);
949 AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator,
950 "libc++ std::tuple synthetic children",
951 "^std::__[[:alnum:]]+::tuple<.*>$", stl_synth_flags, true);
952 AddCXXSynthetic(cpp_category_sp, LibcxxOptionalSyntheticFrontEndCreator,
953 "libc++ std::optional synthetic children",
954 "^std::__[[:alnum:]]+::optional<.+>$", stl_synth_flags, true);
955 AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator,
956 "libc++ std::variant synthetic children",
957 "^std::__[[:alnum:]]+::variant<.+>$", stl_synth_flags, true);
958 AddCXXSynthetic(
959 cpp_category_sp,
960 lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
961 "libc++ std::atomic synthetic children",
962 "^std::__[[:alnum:]]+::atomic<.+>$", stl_synth_flags, true);
963 AddCXXSynthetic(
964 cpp_category_sp,
965 lldb_private::formatters::LibcxxStdSpanSyntheticFrontEndCreator,
966 "libc++ std::span synthetic children", "^std::__[[:alnum:]]+::span<.+>$",
967 stl_deref_flags, true);
968 AddCXXSynthetic(
969 cpp_category_sp,
970 lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEndCreator,
971 "libc++ std::ranges::ref_view synthetic children",
972 "^std::__[[:alnum:]]+::ranges::ref_view<.+>$", stl_deref_flags, true);
973
974 cpp_category_sp->AddTypeSynthetic(
975 "^std::__[[:alnum:]]+::deque<.+>$", eFormatterMatchRegex,
976 SyntheticChildrenSP(new ScriptedSyntheticChildren(
977 stl_synth_flags,
978 "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
979
980 AddCXXSynthetic(
981 cpp_category_sp,
982 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
983 "shared_ptr synthetic children", "^std::__[[:alnum:]]+::shared_ptr<.+>$",
984 stl_synth_flags, true);
985
986 static constexpr const char *const libcxx_std_unique_ptr_regex =
987 "^std::__[[:alnum:]]+::unique_ptr<.+>$";
988 AddCXXSynthetic(
989 cpp_category_sp,
990 lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator,
991 "unique_ptr synthetic children", libcxx_std_unique_ptr_regex,
992 stl_synth_flags, true);
993
994 AddCXXSynthetic(
995 cpp_category_sp,
996 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
997 "weak_ptr synthetic children", "^std::__[[:alnum:]]+::weak_ptr<.+>$",
998 stl_synth_flags, true);
999 AddCXXSummary(cpp_category_sp,
1000 lldb_private::formatters::LibcxxFunctionSummaryProvider,
1001 "libc++ std::function summary provider",
1002 "^std::__[[:alnum:]]+::function<.+>$", stl_summary_flags, true);
1003
1004 static constexpr const char *const libcxx_std_coroutine_handle_regex =
1005 "^std::__[[:alnum:]]+::coroutine_handle<.+>$";
1006 AddCXXSynthetic(
1007 cpp_category_sp,
1008 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator,
1009 "coroutine_handle synthetic children", libcxx_std_coroutine_handle_regex,
1010 stl_deref_flags, true);
1011
1012 stl_summary_flags.SetDontShowChildren(false);
1013 stl_summary_flags.SetSkipPointers(false);
1014 AddCXXSummary(cpp_category_sp,
1015 lldb_private::formatters::ContainerSizeSummaryProvider,
1016 "libc++ std::bitset summary provider",
1017 "^std::__[[:alnum:]]+::bitset<.+>$", stl_summary_flags, true);
1018 AddCXXSummary(cpp_category_sp,
1019 lldb_private::formatters::ContainerSizeSummaryProvider,
1020 "libc++ std::vector summary provider",
1021 "^std::__[[:alnum:]]+::vector<.+>$", stl_summary_flags, true);
1022 AddCXXSummary(cpp_category_sp,
1023 lldb_private::formatters::ContainerSizeSummaryProvider,
1024 "libc++ std::valarray summary provider",
1025 "^std::__[[:alnum:]]+::valarray<.+>$", stl_summary_flags, true);
1026 AddCXXSummary(cpp_category_sp,
1027 lldb_private::formatters::LibcxxStdSliceArraySummaryProvider,
1028 "libc++ std::slice_array summary provider",
1029 "^std::__[[:alnum:]]+::slice_array<.+>$", stl_summary_flags,
1030 true);
1031 AddCXXSummary(cpp_category_sp,
1032 lldb_private::formatters::ContainerSizeSummaryProvider,
1033 "libc++ summary provider for the valarray proxy arrays",
1034 "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
1035 stl_summary_flags, true);
1036 AddCXXSummary(
1037 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1038 "libc++ std::list summary provider",
1039 "^std::__[[:alnum:]]+::forward_list<.+>$", stl_summary_flags, true);
1040 AddCXXSummary(
1041 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1042 "libc++ std::list summary provider",
1043 // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$"
1044 // so that it does not clash with: "^std::(__cxx11::)?list<.+>$"
1045 "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
1046 "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$",
1047 stl_summary_flags, true);
1048 AddCXXSummary(cpp_category_sp,
1049 lldb_private::formatters::ContainerSizeSummaryProvider,
1050 "libc++ std::map summary provider",
1051 "^std::__[[:alnum:]]+::map<.+>$", stl_summary_flags, true);
1052 AddCXXSummary(cpp_category_sp,
1053 lldb_private::formatters::ContainerSizeSummaryProvider,
1054 "libc++ std::deque summary provider",
1055 "^std::__[[:alnum:]]+::deque<.+>$", stl_summary_flags, true);
1056 AddCXXSummary(cpp_category_sp,
1057 lldb_private::formatters::ContainerSizeSummaryProvider,
1058 "libc++ std::queue summary provider",
1059 "^std::__[[:alnum:]]+::queue<.+>$", stl_summary_flags, true);
1060 AddCXXSummary(cpp_category_sp,
1061 lldb_private::formatters::ContainerSizeSummaryProvider,
1062 "libc++ std::set summary provider",
1063 "^std::__[[:alnum:]]+::set<.+>$", stl_summary_flags, true);
1064 AddCXXSummary(cpp_category_sp,
1065 lldb_private::formatters::ContainerSizeSummaryProvider,
1066 "libc++ std::multiset summary provider",
1067 "^std::__[[:alnum:]]+::multiset<.+>$", stl_summary_flags, true);
1068 AddCXXSummary(cpp_category_sp,
1069 lldb_private::formatters::ContainerSizeSummaryProvider,
1070 "libc++ std::multimap summary provider",
1071 "^std::__[[:alnum:]]+::multimap<.+>$", stl_summary_flags, true);
1072 AddCXXSummary(cpp_category_sp,
1073 lldb_private::formatters::ContainerSizeSummaryProvider,
1074 "libc++ std::unordered containers summary provider",
1075 "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
1076 stl_summary_flags, true);
1077 AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
1078 "libc++ std::tuple summary provider",
1079 "^std::__[[:alnum:]]+::tuple<.*>$", stl_summary_flags, true);
1080 AddCXXSummary(cpp_category_sp,
1081 lldb_private::formatters::LibCxxAtomicSummaryProvider,
1082 "libc++ std::atomic summary provider",
1083 "^std::__[[:alnum:]]+::atomic<.+>$", stl_summary_flags, true);
1084 AddCXXSummary(cpp_category_sp,
1085 lldb_private::formatters::GenericOptionalSummaryProvider,
1086 "libc++ std::optional summary provider",
1087 "^std::__[[:alnum:]]+::optional<.+>$", stl_summary_flags, true);
1088 AddCXXSummary(cpp_category_sp,
1089 lldb_private::formatters::LibcxxVariantSummaryProvider,
1090 "libc++ std::variant summary provider",
1091 "^std::__[[:alnum:]]+::variant<.+>$", stl_summary_flags, true);
1092 AddCXXSummary(cpp_category_sp,
1093 lldb_private::formatters::ContainerSizeSummaryProvider,
1094 "libc++ std::span summary provider",
1095 "^std::__[[:alnum:]]+::span<.+>$", stl_summary_flags, true);
1096
1097 stl_summary_flags.SetSkipPointers(true);
1098
1099 AddCXXSummary(cpp_category_sp,
1100 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
1101 "libc++ std::shared_ptr summary provider",
1102 "^std::__[[:alnum:]]+::shared_ptr<.+>$", stl_summary_flags,
1103 true);
1104 AddCXXSummary(cpp_category_sp,
1105 lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
1106 "libc++ std::weak_ptr summary provider",
1107 "^std::__[[:alnum:]]+::weak_ptr<.+>$", stl_summary_flags, true);
1108 AddCXXSummary(cpp_category_sp,
1109 lldb_private::formatters::LibcxxUniquePointerSummaryProvider,
1110 "libc++ std::unique_ptr summary provider",
1111 libcxx_std_unique_ptr_regex, stl_summary_flags, true);
1112
1113 AddCXXSummary(cpp_category_sp,
1114 lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
1115 "libc++ std::coroutine_handle summary provider",
1116 libcxx_std_coroutine_handle_regex, stl_summary_flags, true);
1117
1118 AddCXXSynthetic(
1119 cpp_category_sp,
1120 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator,
1121 "std::vector iterator synthetic children",
1122 "^std::__[[:alnum:]]+::__wrap_iter<.+>$", stl_synth_flags, true);
1123
1124 AddCXXSynthetic(
1125 cpp_category_sp,
1126 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
1127 "std::map iterator synthetic children",
1128 "^std::__[[:alnum:]]+::__map_(const_)?iterator<.+>$", stl_synth_flags,
1129 true);
1130
1131 AddCXXSynthetic(cpp_category_sp,
1132 lldb_private::formatters::
1133 LibCxxUnorderedMapIteratorSyntheticFrontEndCreator,
1134 "std::unordered_map iterator synthetic children",
1135 "^std::__[[:alnum:]]+::__hash_map_(const_)?iterator<.+>$",
1136 stl_synth_flags, true);
1137 // Chrono duration typedefs
1138 cpp_category_sp->AddTypeSummary(
1139 "^std::__[[:alnum:]]+::chrono::nanoseconds", eFormatterMatchRegex,
1140 TypeSummaryImplSP(new StringSummaryFormat(
1141 eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ns")));
1142 cpp_category_sp->AddTypeSummary(
1143 "^std::__[[:alnum:]]+::chrono::microseconds", eFormatterMatchRegex,
1144 TypeSummaryImplSP(new StringSummaryFormat(
1145 eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} µs")));
1146 cpp_category_sp->AddTypeSummary(
1147 "^std::__[[:alnum:]]+::chrono::milliseconds", eFormatterMatchRegex,
1148 TypeSummaryImplSP(new StringSummaryFormat(
1149 eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ms")));
1150 cpp_category_sp->AddTypeSummary(
1151 "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex,
1152 TypeSummaryImplSP(new StringSummaryFormat(
1153 eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s")));
1154 cpp_category_sp->AddTypeSummary(
1155 "^std::__[[:alnum:]]+::chrono::minutes", eFormatterMatchRegex,
1156 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1157 eTypeOptionHideValue,
1158 "${var.__rep_} min")));
1159 cpp_category_sp->AddTypeSummary(
1160 "^std::__[[:alnum:]]+::chrono::hours", eFormatterMatchRegex,
1161 TypeSummaryImplSP(new StringSummaryFormat(
1162 eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} h")));
1163
1164 cpp_category_sp->AddTypeSummary(
1165 "^std::__[[:alnum:]]+::chrono::days", eFormatterMatchRegex,
1166 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1167 eTypeOptionHideValue,
1168 "${var.__rep_} days")));
1169 cpp_category_sp->AddTypeSummary(
1170 "^std::__[[:alnum:]]+::chrono::weeks", eFormatterMatchRegex,
1171 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1172 eTypeOptionHideValue,
1173 "${var.__rep_} weeks")));
1174 cpp_category_sp->AddTypeSummary(
1175 "^std::__[[:alnum:]]+::chrono::months", eFormatterMatchRegex,
1176 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1177 eTypeOptionHideValue,
1178 "${var.__rep_} months")));
1179 cpp_category_sp->AddTypeSummary(
1180 "^std::__[[:alnum:]]+::chrono::years", eFormatterMatchRegex,
1181 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1182 eTypeOptionHideValue,
1183 "${var.__rep_} years")));
1184 cpp_category_sp->AddTypeSummary(
1185 "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex,
1186 TypeSummaryImplSP(new StringSummaryFormat(
1187 eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s")));
1188
1189 // Chrono time point types
1190
1191 AddCXXSummary(cpp_category_sp,
1192 lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider,
1193 "libc++ std::chrono::sys_seconds summary provider",
1194 "^std::__[[:alnum:]]+::chrono::time_point<"
1195 "std::__[[:alnum:]]+::chrono::system_clock, "
1196 "std::__[[:alnum:]]+::chrono::duration<.*, "
1197 "std::__[[:alnum:]]+::ratio<1, 1> "
1198 "> >$",
1199 eTypeOptionHideChildren | eTypeOptionHideValue |
1200 eTypeOptionCascade,
1201 true);
1202 AddCXXSummary(cpp_category_sp,
1203 lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider,
1204 "libc++ std::chrono::sys_seconds summary provider",
1205 "^std::__[[:alnum:]]+::chrono::time_point<"
1206 "std::__[[:alnum:]]+::chrono::system_clock, "
1207 "std::__[[:alnum:]]+::chrono::duration<int, "
1208 "std::__[[:alnum:]]+::ratio<86400, 1> "
1209 "> >$",
1210 eTypeOptionHideChildren | eTypeOptionHideValue |
1211 eTypeOptionCascade,
1212 true);
1213
1214 AddCXXSummary(
1215 cpp_category_sp,
1216 lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider,
1217 "libc++ std::chrono::local_seconds summary provider",
1218 "^std::__[[:alnum:]]+::chrono::time_point<"
1219 "std::__[[:alnum:]]+::chrono::local_t, "
1220 "std::__[[:alnum:]]+::chrono::duration<.*, "
1221 "std::__[[:alnum:]]+::ratio<1, 1> "
1222 "> >$",
1223 eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade,
1224 true);
1225 AddCXXSummary(cpp_category_sp,
1226 lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider,
1227 "libc++ std::chrono::local_seconds summary provider",
1228 "^std::__[[:alnum:]]+::chrono::time_point<"
1229 "std::__[[:alnum:]]+::chrono::local_t, "
1230 "std::__[[:alnum:]]+::chrono::duration<int, "
1231 "std::__[[:alnum:]]+::ratio<86400, 1> "
1232 "> >$",
1233 eTypeOptionHideChildren | eTypeOptionHideValue |
1234 eTypeOptionCascade,
1235 true);
1236
1237 // Chrono calendar types
1238
1239 cpp_category_sp->AddTypeSummary(
1240 "^std::__[[:alnum:]]+::chrono::day$", eFormatterMatchRegex,
1241 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1242 eTypeOptionHideValue,
1243 "day=${var.__d_%u}")));
1244
1245 AddCXXSummary(cpp_category_sp,
1246 lldb_private::formatters::LibcxxChronoMonthSummaryProvider,
1247 "libc++ std::chrono::month summary provider",
1248 "^std::__[[:alnum:]]+::chrono::month$",
1249 eTypeOptionHideChildren | eTypeOptionHideValue, true);
1250
1251 cpp_category_sp->AddTypeSummary(
1252 "^std::__[[:alnum:]]+::chrono::year$", eFormatterMatchRegex,
1253 TypeSummaryImplSP(new StringSummaryFormat(
1254 eTypeOptionHideChildren | eTypeOptionHideValue, "year=${var.__y_}")));
1255
1256 AddCXXSummary(cpp_category_sp,
1257 lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider,
1258 "libc++ std::chrono::weekday summary provider",
1259 "^std::__[[:alnum:]]+::chrono::weekday$",
1260 eTypeOptionHideChildren | eTypeOptionHideValue, true);
1261
1262 cpp_category_sp->AddTypeSummary(
1263 "^std::__[[:alnum:]]+::chrono::weekday_indexed$", eFormatterMatchRegex,
1264 TypeSummaryImplSP(new StringSummaryFormat(
1265 eTypeOptionHideChildren | eTypeOptionHideValue,
1266 "${var.__wd_} index=${var.__idx_%u}")));
1267
1268 cpp_category_sp->AddTypeSummary(
1269 "^std::__[[:alnum:]]+::chrono::weekday_last$", eFormatterMatchRegex,
1270 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1271 eTypeOptionHideValue,
1272 "${var.__wd_} index=last")));
1273 cpp_category_sp->AddTypeSummary(
1274 "^std::__[[:alnum:]]+::chrono::month_day$", eFormatterMatchRegex,
1275 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1276 eTypeOptionHideValue,
1277 "${var.__m_} ${var.__d_}")));
1278 cpp_category_sp->AddTypeSummary(
1279 "^std::__[[:alnum:]]+::chrono::month_day_last$", eFormatterMatchRegex,
1280 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1281 eTypeOptionHideValue,
1282 "${var.__m_} day=last")));
1283
1284 cpp_category_sp->AddTypeSummary(
1285 "^std::__[[:alnum:]]+::chrono::month_weekday$", eFormatterMatchRegex,
1286 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1287 eTypeOptionHideValue,
1288 "${var.__m_} ${var.__wdi_}")));
1289
1290 cpp_category_sp->AddTypeSummary(
1291 "^std::__[[:alnum:]]+::chrono::month_weekday_last$", eFormatterMatchRegex,
1292 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1293 eTypeOptionHideValue,
1294 "${var.__m_} ${var.__wdl_}")));
1295
1296 cpp_category_sp->AddTypeSummary(
1297 "^std::__[[:alnum:]]+::chrono::year_month$", eFormatterMatchRegex,
1298 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1299 eTypeOptionHideValue,
1300 "${var.__y_} ${var.__m_}")));
1301
1302 AddCXXSummary(
1303 cpp_category_sp,
1304 lldb_private::formatters::LibcxxChronoYearMonthDaySummaryProvider,
1305 "libc++ std::chrono::year_month_day summary provider",
1306 "^std::__[[:alnum:]]+::chrono::year_month_day$",
1307 eTypeOptionHideChildren | eTypeOptionHideValue, true);
1308
1309 cpp_category_sp->AddTypeSummary(
1310 "^std::__[[:alnum:]]+::chrono::year_month_day_last$",
1311 eFormatterMatchRegex,
1312 TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
1313 eTypeOptionHideValue,
1314 "${var.__y_} ${var.__mdl_}")));
1315
1316 cpp_category_sp->AddTypeSummary(
1317 "^std::__[[:alnum:]]+::chrono::year_month_weekday$", eFormatterMatchRegex,
1318 TypeSummaryImplSP(new StringSummaryFormat(
1319 eTypeOptionHideChildren | eTypeOptionHideValue,
1320 "${var.__y_} ${var.__m_} ${var.__wdi_}")));
1321
1322 cpp_category_sp->AddTypeSummary(
1323 "^std::__[[:alnum:]]+::chrono::year_month_weekday_last$",
1324 eFormatterMatchRegex,
1325 TypeSummaryImplSP(new StringSummaryFormat(
1326 eTypeOptionHideChildren | eTypeOptionHideValue,
1327 "${var.__y_} ${var.__m_} ${var.__wdl_}")));
1328 }
1329
RegisterStdStringSummaryProvider(const lldb::TypeCategoryImplSP & category_sp,llvm::StringRef string_ty,llvm::StringRef char_ty,lldb::TypeSummaryImplSP summary_sp)1330 static void RegisterStdStringSummaryProvider(
1331 const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty,
1332 llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) {
1333 auto makeSpecifier = [](llvm::StringRef name) {
1334 return std::make_shared<lldb_private::TypeNameSpecifierImpl>(
1335 name, eFormatterMatchExact);
1336 };
1337
1338 category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
1339
1340 category_sp->AddTypeSummary(
1341 makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
1342 summary_sp);
1343
1344 category_sp->AddTypeSummary(
1345 std::make_shared<lldb_private::TypeNameSpecifierImpl>(
1346 llvm::formatv("^std::basic_string<{0}, ?std::char_traits<{0}>,.*>$",
1347 char_ty)
1348 .str(),
1349 eFormatterMatchRegex),
1350 summary_sp);
1351 }
1352
LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1353 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1354 if (!cpp_category_sp)
1355 return;
1356
1357 TypeSummaryImpl::Flags stl_summary_flags;
1358 stl_summary_flags.SetCascades(true)
1359 .SetSkipPointers(false)
1360 .SetSkipReferences(false)
1361 .SetDontShowChildren(true)
1362 .SetDontShowValue(false)
1363 .SetShowMembersOneLiner(false)
1364 .SetHideItemNames(false);
1365
1366 lldb::TypeSummaryImplSP string_summary_sp(new CXXFunctionSummaryFormat(
1367 stl_summary_flags, LibStdcppStringSummaryProvider,
1368 "libstdc++ std::(w)string summary provider"));
1369 cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
1370 string_summary_sp);
1371 cpp_category_sp->AddTypeSummary(
1372 "^std::__cxx11::basic_string<char, std::char_traits<char>,.*>$",
1373 eFormatterMatchRegex, string_summary_sp);
1374 cpp_category_sp->AddTypeSummary("^std::__cxx11::basic_string<unsigned char, "
1375 "std::char_traits<unsigned char>,.*>$",
1376 eFormatterMatchRegex, string_summary_sp);
1377
1378 cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact,
1379 string_summary_sp);
1380 cpp_category_sp->AddTypeSummary(
1381 "^std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>,.*>$",
1382 eFormatterMatchRegex, string_summary_sp);
1383
1384 SyntheticChildren::Flags stl_synth_flags;
1385 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
1386 false);
1387 SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
1388 stl_deref_flags.SetFrontEndWantsDereference();
1389
1390 cpp_category_sp->AddTypeSynthetic(
1391 "^std::(__debug::)?vector<.+>(( )?&)?$", eFormatterMatchRegex,
1392 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1393 stl_synth_flags,
1394 "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
1395 cpp_category_sp->AddTypeSynthetic(
1396 "^std::(__debug::)?map<.+> >(( )?&)?$", eFormatterMatchRegex,
1397 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1398 stl_synth_flags,
1399 "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1400 cpp_category_sp->AddTypeSynthetic(
1401 "^std::(__debug)?deque<.+>(( )?&)?$", eFormatterMatchRegex,
1402 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1403 stl_deref_flags,
1404 "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider")));
1405 cpp_category_sp->AddTypeSynthetic(
1406 "^std::(__debug::)?set<.+> >(( )?&)?$", eFormatterMatchRegex,
1407 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1408 stl_deref_flags,
1409 "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1410 cpp_category_sp->AddTypeSynthetic(
1411 "^std::(__debug::)?multimap<.+> >(( )?&)?$", eFormatterMatchRegex,
1412 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1413 stl_deref_flags,
1414 "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1415 cpp_category_sp->AddTypeSynthetic(
1416 "^std::(__debug::)?multiset<.+> >(( )?&)?$", eFormatterMatchRegex,
1417 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1418 stl_deref_flags,
1419 "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
1420 cpp_category_sp->AddTypeSynthetic(
1421 "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
1422 eFormatterMatchRegex,
1423 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1424 stl_deref_flags,
1425 "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")));
1426 cpp_category_sp->AddTypeSynthetic(
1427 "^std::((__debug::)?|(__cxx11::)?)list<.+>(( )?&)?$",
1428 eFormatterMatchRegex,
1429 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1430 stl_deref_flags,
1431 "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
1432 cpp_category_sp->AddTypeSynthetic(
1433 "^std::((__debug::)?|(__cxx11::)?)forward_list<.+>(( )?&)?$",
1434 eFormatterMatchRegex,
1435 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1436 stl_synth_flags,
1437 "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
1438 cpp_category_sp->AddTypeSynthetic(
1439 "^std::variant<.+>$", eFormatterMatchRegex,
1440 SyntheticChildrenSP(new ScriptedSyntheticChildren(
1441 stl_synth_flags,
1442 "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider")));
1443
1444 stl_summary_flags.SetDontShowChildren(false);
1445 stl_summary_flags.SetSkipPointers(false);
1446
1447 AddCXXSummary(
1448 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1449 "libstdc++ std::bitset summary provider",
1450 "^std::(__debug::)?bitset<.+>(( )?&)?$", stl_summary_flags, true);
1451
1452 AddCXXSummary(
1453 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1454 "libstdc++ std::vector summary provider",
1455 "^std::(__debug::)?vector<.+>(( )?&)?$", stl_summary_flags, true);
1456
1457 AddCXXSummary(
1458 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1459 "libstdc++ std::map summary provider",
1460 "^std::(__debug::)?map<.+> >(( )?&)?$", stl_summary_flags, true);
1461
1462 AddCXXSummary(
1463 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1464 "libstdc++ std::set summary provider",
1465 "^std::(__debug::)?set<.+> >(( )?&)?$", stl_summary_flags, true);
1466
1467 AddCXXSummary(
1468 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1469 "libstdc++ std::deque summary provider",
1470 "^std::(__debug::)?deque<.+>(( )?&)?$", stl_summary_flags, true);
1471
1472 AddCXXSummary(
1473 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1474 "libstdc++ std::multimap summary provider",
1475 "^std::(__debug::)?multimap<.+> >(( )?&)?$", stl_summary_flags, true);
1476
1477 AddCXXSummary(
1478 cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider,
1479 "libstdc++ std::multiset summary provider",
1480 "^std::(__debug::)?multiset<.+> >(( )?&)?$", stl_summary_flags, true);
1481
1482 AddCXXSummary(cpp_category_sp,
1483 lldb_private::formatters::ContainerSizeSummaryProvider,
1484 "libstdc++ std unordered container summary provider",
1485 "^std::(__debug::)?unordered_(multi)?(map|set)<.+> >$",
1486 stl_summary_flags, true);
1487
1488 AddCXXSummary(cpp_category_sp,
1489 lldb_private::formatters::ContainerSizeSummaryProvider,
1490 "libstdc++ std::list summary provider",
1491 "^std::((__debug::)?|(__cxx11::)?)list<.+>(( )?&)?$",
1492 stl_summary_flags, true);
1493
1494 AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider,
1495 "libstdc++ std::tuple summary provider",
1496 "^std::tuple<.*>(( )?&)?$", stl_summary_flags, true);
1497
1498 cpp_category_sp->AddTypeSummary(
1499 "^std::((__debug::)?|(__cxx11::)?)forward_list<.+>(( )?&)?$",
1500 eFormatterMatchRegex,
1501 TypeSummaryImplSP(new ScriptSummaryFormat(
1502 stl_summary_flags,
1503 "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")));
1504 cpp_category_sp->AddTypeSummary(
1505 "^std::variant<.+>$", eFormatterMatchRegex,
1506 TypeSummaryImplSP(new ScriptSummaryFormat(
1507 stl_summary_flags,
1508 "lldb.formatters.cpp.gnu_libstdcpp.VariantSummaryProvider")));
1509
1510 AddCXXSynthetic(
1511 cpp_category_sp,
1512 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator,
1513 "std::vector iterator synthetic children",
1514 "^__gnu_cxx::__normal_iterator<.+>$", stl_synth_flags, true);
1515
1516 AddCXXSynthetic(
1517 cpp_category_sp,
1518 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator,
1519 "std::map iterator synthetic children",
1520 "^std::_Rb_tree_(const_)?iterator<.+>$", stl_synth_flags, true);
1521
1522 AddCXXSynthetic(
1523 cpp_category_sp,
1524 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
1525 "std::unique_ptr synthetic children", "^std::unique_ptr<.+>(( )?&)?$",
1526 stl_synth_flags, true);
1527 AddCXXSynthetic(
1528 cpp_category_sp,
1529 lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
1530 "std::tuple synthetic children", "^std::tuple<.*>(( )?&)?$",
1531 stl_synth_flags, true);
1532
1533 static constexpr const char *const libstdcpp_std_coroutine_handle_regex =
1534 "^std::coroutine_handle<.+>(( )?&)?$";
1535 AddCXXSynthetic(
1536 cpp_category_sp,
1537 lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator,
1538 "std::coroutine_handle synthetic children",
1539 libstdcpp_std_coroutine_handle_regex, stl_deref_flags, true);
1540
1541 AddCXXSynthetic(
1542 cpp_category_sp,
1543 lldb_private::formatters::LibStdcppBitsetSyntheticFrontEndCreator,
1544 "std::bitset synthetic child", "^std::(__debug::)?bitset<.+>(( )?&)?$",
1545 stl_deref_flags, true);
1546
1547 AddCXXSynthetic(
1548 cpp_category_sp,
1549 lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator,
1550 "std::optional synthetic child", "^std::optional<.+>(( )?&)?$",
1551 stl_deref_flags, true);
1552
1553 AddCXXSummary(cpp_category_sp,
1554 lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
1555 "libstdc++ std::coroutine_handle summary provider",
1556 libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
1557 AddCXXSummary(cpp_category_sp,
1558 lldb_private::formatters::GenericOptionalSummaryProvider,
1559 "libstd++ std::optional summary provider",
1560 "^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
1561 }
1562
1563 static lldb_private::SyntheticChildrenFrontEnd *
GenericSmartPointerSyntheticFrontEndCreator(CXXSyntheticChildren * children,lldb::ValueObjectSP valobj_sp)1564 GenericSmartPointerSyntheticFrontEndCreator(CXXSyntheticChildren *children,
1565 lldb::ValueObjectSP valobj_sp) {
1566 if (!valobj_sp)
1567 return nullptr;
1568
1569 if (IsMsvcStlSmartPointer(*valobj_sp))
1570 return MsvcStlSmartPointerSyntheticFrontEndCreator(valobj_sp);
1571 return LibStdcppSharedPtrSyntheticFrontEndCreator(children, valobj_sp);
1572 }
1573
1574 static bool
GenericSmartPointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)1575 GenericSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
1576 const TypeSummaryOptions &options) {
1577 if (IsMsvcStlSmartPointer(valobj))
1578 return MsvcStlSmartPointerSummaryProvider(valobj, stream, options);
1579 return LibStdcppSmartPointerSummaryProvider(valobj, stream, options);
1580 }
1581
1582 static lldb_private::SyntheticChildrenFrontEnd *
GenericUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren * children,lldb::ValueObjectSP valobj_sp)1583 GenericUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *children,
1584 lldb::ValueObjectSP valobj_sp) {
1585 if (!valobj_sp)
1586 return nullptr;
1587
1588 if (IsMsvcStlUniquePtr(*valobj_sp))
1589 return MsvcStlUniquePtrSyntheticFrontEndCreator(valobj_sp);
1590 return LibStdcppUniquePtrSyntheticFrontEndCreator(children, valobj_sp);
1591 }
1592
GenericUniquePtrSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)1593 static bool GenericUniquePtrSummaryProvider(ValueObject &valobj, Stream &stream,
1594 const TypeSummaryOptions &options) {
1595 if (IsMsvcStlUniquePtr(valobj))
1596 return MsvcStlUniquePtrSummaryProvider(valobj, stream, options);
1597 return LibStdcppUniquePointerSummaryProvider(valobj, stream, options);
1598 }
1599
1600 /// Load formatters that are formatting types from more than one STL
LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1601 static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1602 if (!cpp_category_sp)
1603 return;
1604
1605 TypeSummaryImpl::Flags stl_summary_flags;
1606 stl_summary_flags.SetCascades(true)
1607 .SetSkipPointers(false)
1608 .SetSkipReferences(false)
1609 .SetDontShowChildren(true)
1610 .SetDontShowValue(false)
1611 .SetShowMembersOneLiner(false)
1612 .SetHideItemNames(false);
1613 SyntheticChildren::Flags stl_synth_flags;
1614 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
1615 false);
1616
1617 using StringElementType = StringPrinter::StringElementType;
1618
1619 RegisterStdStringSummaryProvider(
1620 cpp_category_sp, "std::string", "char",
1621 std::make_shared<CXXFunctionSummaryFormat>(
1622 stl_summary_flags,
1623 [](ValueObject &valobj, Stream &stream,
1624 const TypeSummaryOptions &options) {
1625 if (IsMsvcStlStringType(valobj))
1626 return MsvcStlStringSummaryProvider<StringElementType::ASCII>(
1627 valobj, stream, options);
1628 return LibStdcppStringSummaryProvider(valobj, stream, options);
1629 },
1630 "MSVC STL/libstdc++ std::string summary provider"));
1631 RegisterStdStringSummaryProvider(
1632 cpp_category_sp, "std::wstring", "wchar_t",
1633 std::make_shared<CXXFunctionSummaryFormat>(
1634 stl_summary_flags,
1635 [](ValueObject &valobj, Stream &stream,
1636 const TypeSummaryOptions &options) {
1637 if (IsMsvcStlStringType(valobj))
1638 return MsvcStlWStringSummaryProvider(valobj, stream, options);
1639 return LibStdcppStringSummaryProvider(valobj, stream, options);
1640 },
1641 "MSVC STL/libstdc++ std::wstring summary provider"));
1642
1643 stl_summary_flags.SetDontShowChildren(false);
1644 stl_summary_flags.SetSkipPointers(false);
1645
1646 AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
1647 "std::shared_ptr synthetic children",
1648 "^std::shared_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1649 AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
1650 "std::weak_ptr synthetic children",
1651 "^std::weak_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1652 AddCXXSynthetic(cpp_category_sp, GenericUniquePtrSyntheticFrontEndCreator,
1653 "std::unique_ptr synthetic children",
1654 "^std::unique_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1655
1656 AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
1657 "MSVC STL/libstdc++ std::shared_ptr summary provider",
1658 "^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1659 AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
1660 "MSVC STL/libstdc++ std::weak_ptr summary provider",
1661 "^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1662 AddCXXSummary(cpp_category_sp, GenericUniquePtrSummaryProvider,
1663 "MSVC STL/libstdc++ std::unique_ptr summary provider",
1664 "^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1665 }
1666
LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1667 static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1668 if (!cpp_category_sp)
1669 return;
1670
1671 TypeSummaryImpl::Flags stl_summary_flags;
1672 stl_summary_flags.SetCascades(true)
1673 .SetSkipPointers(false)
1674 .SetSkipReferences(false)
1675 .SetDontShowChildren(true)
1676 .SetDontShowValue(false)
1677 .SetShowMembersOneLiner(false)
1678 .SetHideItemNames(false);
1679
1680 using StringElementType = StringPrinter::StringElementType;
1681
1682 RegisterStdStringSummaryProvider(
1683 cpp_category_sp, "std::u8string", "char8_t",
1684 std::make_shared<CXXFunctionSummaryFormat>(
1685 stl_summary_flags,
1686 MsvcStlStringSummaryProvider<StringElementType::UTF8>,
1687 "MSVC STL std::u8string summary provider"));
1688 RegisterStdStringSummaryProvider(
1689 cpp_category_sp, "std::u16string", "char16_t",
1690 std::make_shared<CXXFunctionSummaryFormat>(
1691 stl_summary_flags,
1692 MsvcStlStringSummaryProvider<StringElementType::UTF16>,
1693 "MSVC STL std::u16string summary provider"));
1694 RegisterStdStringSummaryProvider(
1695 cpp_category_sp, "std::u32string", "char32_t",
1696 std::make_shared<CXXFunctionSummaryFormat>(
1697 stl_summary_flags,
1698 MsvcStlStringSummaryProvider<StringElementType::UTF32>,
1699 "MSVC STL std::u32string summary provider"));
1700 }
1701
LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp)1702 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1703 if (!cpp_category_sp)
1704 return;
1705
1706 TypeSummaryImpl::Flags string_flags;
1707 string_flags.SetCascades(true)
1708 .SetSkipPointers(true)
1709 .SetSkipReferences(false)
1710 .SetDontShowChildren(true)
1711 .SetDontShowValue(false)
1712 .SetShowMembersOneLiner(false)
1713 .SetHideItemNames(false);
1714
1715 TypeSummaryImpl::Flags string_array_flags;
1716 string_array_flags.SetCascades(true)
1717 .SetSkipPointers(true)
1718 .SetSkipReferences(false)
1719 .SetDontShowChildren(true)
1720 .SetDontShowValue(true)
1721 .SetShowMembersOneLiner(false)
1722 .SetHideItemNames(false);
1723
1724 AddCXXSummary(cpp_category_sp,
1725 lldb_private::formatters::Char8StringSummaryProvider,
1726 "char8_t * summary provider", "char8_t *", string_flags);
1727 AddCXXSummary(cpp_category_sp,
1728 lldb_private::formatters::Char8StringSummaryProvider,
1729 "char8_t [] summary provider", "char8_t ?\\[[0-9]+\\]",
1730 string_array_flags, true);
1731
1732 AddCXXSummary(cpp_category_sp,
1733 lldb_private::formatters::Char16StringSummaryProvider,
1734 "char16_t * summary provider", "char16_t *", string_flags);
1735 AddCXXSummary(cpp_category_sp,
1736 lldb_private::formatters::Char16StringSummaryProvider,
1737 "char16_t [] summary provider", "char16_t ?\\[[0-9]+\\]",
1738 string_array_flags, true);
1739
1740 AddCXXSummary(cpp_category_sp,
1741 lldb_private::formatters::Char32StringSummaryProvider,
1742 "char32_t * summary provider", "char32_t *", string_flags);
1743 AddCXXSummary(cpp_category_sp,
1744 lldb_private::formatters::Char32StringSummaryProvider,
1745 "char32_t [] summary provider", "char32_t ?\\[[0-9]+\\]",
1746 string_array_flags, true);
1747
1748 AddCXXSummary(cpp_category_sp,
1749 lldb_private::formatters::WCharStringSummaryProvider,
1750 "wchar_t * summary provider", "wchar_t *", string_flags);
1751 AddCXXSummary(cpp_category_sp,
1752 lldb_private::formatters::WCharStringSummaryProvider,
1753 "wchar_t * summary provider", "wchar_t ?\\[[0-9]+\\]",
1754 string_array_flags, true);
1755
1756 AddCXXSummary(cpp_category_sp,
1757 lldb_private::formatters::Char16StringSummaryProvider,
1758 "unichar * summary provider", "unichar *", string_flags);
1759
1760 TypeSummaryImpl::Flags widechar_flags;
1761 widechar_flags.SetDontShowValue(true)
1762 .SetSkipPointers(true)
1763 .SetSkipReferences(false)
1764 .SetCascades(true)
1765 .SetDontShowChildren(true)
1766 .SetHideItemNames(true)
1767 .SetShowMembersOneLiner(false);
1768
1769 AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char8SummaryProvider,
1770 "char8_t summary provider", "char8_t", widechar_flags);
1771 AddCXXSummary(cpp_category_sp,
1772 lldb_private::formatters::Char16SummaryProvider,
1773 "char16_t summary provider", "char16_t", widechar_flags);
1774 AddCXXSummary(cpp_category_sp,
1775 lldb_private::formatters::Char32SummaryProvider,
1776 "char32_t summary provider", "char32_t", widechar_flags);
1777 AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider,
1778 "wchar_t summary provider", "wchar_t", widechar_flags);
1779
1780 AddCXXSummary(cpp_category_sp,
1781 lldb_private::formatters::Char16SummaryProvider,
1782 "unichar summary provider", "unichar", widechar_flags);
1783 }
1784
GetTypeScavenger()1785 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() {
1786 class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger {
1787 public:
1788 CompilerType AdjustForInclusion(CompilerType &candidate) override {
1789 LanguageType lang_type(candidate.GetMinimumLanguage());
1790 if (!Language::LanguageIsC(lang_type) &&
1791 !Language::LanguageIsCPlusPlus(lang_type))
1792 return CompilerType();
1793 if (candidate.IsTypedefType())
1794 return candidate.GetTypedefedType();
1795 return candidate;
1796 }
1797 };
1798
1799 return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
1800 }
1801
GetFormatters()1802 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
1803 static llvm::once_flag g_initialize;
1804 static TypeCategoryImplSP g_category;
1805
1806 llvm::call_once(g_initialize, [this]() -> void {
1807 DataVisualization::Categories::GetCategory(ConstString(GetPluginName()),
1808 g_category);
1809 if (g_category) {
1810 // NOTE: the libstdcpp formatters are loaded after libcxx formatters
1811 // because we don't want to the libcxx formatters to match the potential
1812 // `__debug` inline namespace that libstdcpp may use.
1813 // LLDB prioritizes the last loaded matching formatter.
1814 LoadLibCxxFormatters(g_category);
1815 LoadLibStdcppFormatters(g_category);
1816 LoadMsvcStlFormatters(g_category);
1817 LoadCommonStlFormatters(g_category);
1818 LoadSystemFormatters(g_category);
1819 }
1820 });
1821 return g_category;
1822 }
1823
1824 HardcodedFormatters::HardcodedSummaryFinder
GetHardcodedSummaries()1825 CPlusPlusLanguage::GetHardcodedSummaries() {
1826 static llvm::once_flag g_initialize;
1827 static ConstString g_vectortypes("VectorTypes");
1828 static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
1829
1830 llvm::call_once(g_initialize, []() -> void {
1831 g_formatters.push_back(
1832 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1833 FormatManager &) -> TypeSummaryImpl::SharedPointer {
1834 static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1835 new CXXFunctionSummaryFormat(
1836 TypeSummaryImpl::Flags(),
1837 lldb_private::formatters::CXXFunctionPointerSummaryProvider,
1838 "Function pointer summary provider"));
1839 if (CompilerType CT = valobj.GetCompilerType();
1840 CT.IsFunctionPointerType() || CT.IsMemberFunctionPointerType() ||
1841 valobj.GetValueType() == lldb::eValueTypeVTableEntry) {
1842 return formatter_sp;
1843 }
1844 return nullptr;
1845 });
1846 g_formatters.push_back(
1847 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1848 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1849 static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1850 new CXXFunctionSummaryFormat(
1851 TypeSummaryImpl::Flags()
1852 .SetCascades(true)
1853 .SetDontShowChildren(true)
1854 .SetHideItemNames(true)
1855 .SetShowMembersOneLiner(true)
1856 .SetSkipPointers(true)
1857 .SetSkipReferences(false),
1858 lldb_private::formatters::VectorTypeSummaryProvider,
1859 "vector_type pointer summary provider"));
1860 if (valobj.GetCompilerType().IsVectorType()) {
1861 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1862 return formatter_sp;
1863 }
1864 return nullptr;
1865 });
1866 g_formatters.push_back(
1867 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
1868 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1869 static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
1870 new CXXFunctionSummaryFormat(
1871 TypeSummaryImpl::Flags()
1872 .SetCascades(true)
1873 .SetDontShowChildren(true)
1874 .SetHideItemNames(true)
1875 .SetShowMembersOneLiner(true)
1876 .SetSkipPointers(true)
1877 .SetSkipReferences(false),
1878 lldb_private::formatters::BlockPointerSummaryProvider,
1879 "block pointer summary provider"));
1880 if (valobj.GetCompilerType().IsBlockPointerType()) {
1881 return formatter_sp;
1882 }
1883 return nullptr;
1884 });
1885 });
1886
1887 return g_formatters;
1888 }
1889
1890 HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics()1891 CPlusPlusLanguage::GetHardcodedSynthetics() {
1892 static llvm::once_flag g_initialize;
1893 static ConstString g_vectortypes("VectorTypes");
1894 static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
1895
1896 llvm::call_once(g_initialize, []() -> void {
1897 g_formatters.push_back([](lldb_private::ValueObject &valobj,
1898 lldb::DynamicValueType, FormatManager &fmt_mgr)
1899 -> SyntheticChildren::SharedPointer {
1900 static CXXSyntheticChildren::SharedPointer formatter_sp(
1901 new CXXSyntheticChildren(
1902 SyntheticChildren::Flags()
1903 .SetCascades(true)
1904 .SetSkipPointers(true)
1905 .SetSkipReferences(true)
1906 .SetNonCacheable(true),
1907 "vector_type synthetic children",
1908 lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
1909 if (valobj.GetCompilerType().IsVectorType()) {
1910 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
1911 return formatter_sp;
1912 }
1913 return nullptr;
1914 });
1915 g_formatters.push_back([](lldb_private::ValueObject &valobj,
1916 lldb::DynamicValueType, FormatManager &fmt_mgr)
1917 -> SyntheticChildren::SharedPointer {
1918 static CXXSyntheticChildren::SharedPointer formatter_sp(
1919 new CXXSyntheticChildren(
1920 SyntheticChildren::Flags()
1921 .SetCascades(true)
1922 .SetSkipPointers(true)
1923 .SetSkipReferences(true)
1924 .SetNonCacheable(true),
1925 "block pointer synthetic children",
1926 lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
1927 if (valobj.GetCompilerType().IsBlockPointerType()) {
1928 return formatter_sp;
1929 }
1930 return nullptr;
1931 });
1932 });
1933
1934 return g_formatters;
1935 }
1936
IsNilReference(ValueObject & valobj)1937 bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) {
1938 if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) ||
1939 !valobj.IsPointerType())
1940 return false;
1941 bool canReadValue = true;
1942 bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
1943 return canReadValue && isZero;
1944 }
1945
IsSourceFile(llvm::StringRef file_path) const1946 bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
1947 const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c",
1948 ".h", ".hh", ".hpp", ".hxx", ".h++"};
1949 for (auto suffix : suffixes) {
1950 if (file_path.ends_with_insensitive(suffix))
1951 return true;
1952 }
1953
1954 // Check if we're in a STL path (where the files usually have no extension
1955 // that we could check for.
1956 return file_path.contains("/usr/include/c++/");
1957 }
1958
GetFunctionVariableList(const SymbolContext & sc)1959 static VariableListSP GetFunctionVariableList(const SymbolContext &sc) {
1960 assert(sc.function);
1961
1962 if (sc.block)
1963 if (Block *inline_block = sc.block->GetContainingInlinedBlock())
1964 return inline_block->GetBlockVariableList(true);
1965
1966 return sc.function->GetBlock(true).GetBlockVariableList(true);
1967 }
1968
PrintFunctionNameWithArgs(Stream & s,const ExecutionContext * exe_ctx,const SymbolContext & sc)1969 static bool PrintFunctionNameWithArgs(Stream &s,
1970 const ExecutionContext *exe_ctx,
1971 const SymbolContext &sc) {
1972 assert(sc.function);
1973
1974 ExecutionContextScope *exe_scope =
1975 exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
1976
1977 const char *cstr = sc.GetPossiblyInlinedFunctionName()
1978 .GetName(Mangled::NamePreference::ePreferDemangled)
1979 .AsCString();
1980 if (!cstr)
1981 return false;
1982
1983 VariableList args;
1984 if (auto variable_list_sp = GetFunctionVariableList(sc))
1985 variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
1986 args);
1987
1988 if (args.GetSize() > 0)
1989 return PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args);
1990
1991 // FIXME: can we just unconditionally call PrettyPrintFunctionNameWithArgs?
1992 // It should be able to handle the "no arguments" case.
1993 s.PutCString(cstr);
1994
1995 return true;
1996 }
1997
GetFunctionDisplayName(const SymbolContext & sc,const ExecutionContext * exe_ctx,FunctionNameRepresentation representation,Stream & s)1998 bool CPlusPlusLanguage::GetFunctionDisplayName(
1999 const SymbolContext &sc, const ExecutionContext *exe_ctx,
2000 FunctionNameRepresentation representation, Stream &s) {
2001 switch (representation) {
2002 case FunctionNameRepresentation::eNameWithArgs: {
2003 // Print the function name with arguments in it
2004 if (sc.function)
2005 return PrintFunctionNameWithArgs(s, exe_ctx, sc);
2006
2007 if (!sc.symbol)
2008 return false;
2009
2010 const char *cstr = sc.symbol->GetName().AsCString(nullptr);
2011 if (!cstr)
2012 return false;
2013
2014 s.PutCString(cstr);
2015
2016 return true;
2017 }
2018 case FunctionNameRepresentation::eNameWithNoArgs:
2019 case FunctionNameRepresentation::eName:
2020 return false;
2021 }
2022 }
2023
HandleFrameFormatVariable(const SymbolContext & sc,const ExecutionContext * exe_ctx,FormatEntity::Entry::Type type,Stream & s)2024 bool CPlusPlusLanguage::HandleFrameFormatVariable(
2025 const SymbolContext &sc, const ExecutionContext *exe_ctx,
2026 FormatEntity::Entry::Type type, Stream &s) {
2027 switch (type) {
2028 case FormatEntity::Entry::Type::FunctionScope: {
2029 auto scope_or_err = GetDemangledScope(sc);
2030 if (!scope_or_err) {
2031 LLDB_LOG_ERROR(
2032 GetLog(LLDBLog::Language), scope_or_err.takeError(),
2033 "Failed to handle ${{function.scope}} frame-format variable: {0}");
2034 return false;
2035 }
2036
2037 s << *scope_or_err;
2038
2039 return true;
2040 }
2041
2042 case FormatEntity::Entry::Type::FunctionBasename: {
2043 auto name_or_err = GetDemangledBasename(sc);
2044 if (!name_or_err) {
2045 LLDB_LOG_ERROR(
2046 GetLog(LLDBLog::Language), name_or_err.takeError(),
2047 "Failed to handle ${{function.basename}} frame-format variable: {0}");
2048 return false;
2049 }
2050
2051 s << *name_or_err;
2052
2053 return true;
2054 }
2055
2056 case FormatEntity::Entry::Type::FunctionTemplateArguments: {
2057 auto template_args_or_err = GetDemangledTemplateArguments(sc);
2058 if (!template_args_or_err) {
2059 LLDB_LOG_ERROR(GetLog(LLDBLog::Language),
2060 template_args_or_err.takeError(),
2061 "Failed to handle ${{function.template-arguments}} "
2062 "frame-format variable: {0}");
2063 return false;
2064 }
2065
2066 s << *template_args_or_err;
2067
2068 return true;
2069 }
2070
2071 case FormatEntity::Entry::Type::FunctionFormattedArguments: {
2072 // This ensures we print the arguments even when no debug-info is available.
2073 //
2074 // FIXME: we should have a Entry::Type::FunctionArguments and
2075 // use it in the plugin.cplusplus.display.function-name-format
2076 // once we have a "fallback operator" in the frame-format language.
2077 if (!sc.function && sc.symbol)
2078 return PrintDemangledArgumentList(s, sc);
2079
2080 VariableList args;
2081 if (auto variable_list_sp = GetFunctionVariableList(sc))
2082 variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
2083 args);
2084
2085 ExecutionContextScope *exe_scope =
2086 exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
2087
2088 s << '(';
2089 FormatEntity::PrettyPrintFunctionArguments(s, args, exe_scope);
2090 s << ')';
2091
2092 return true;
2093 }
2094 case FormatEntity::Entry::Type::FunctionReturnRight: {
2095 auto return_rhs_or_err = GetDemangledReturnTypeRHS(sc);
2096 if (!return_rhs_or_err) {
2097 LLDB_LOG_ERROR(GetLog(LLDBLog::Language), return_rhs_or_err.takeError(),
2098 "Failed to handle ${{function.return-right}} frame-format "
2099 "variable: {0}");
2100 return false;
2101 }
2102
2103 s << *return_rhs_or_err;
2104
2105 return true;
2106 }
2107 case FormatEntity::Entry::Type::FunctionReturnLeft: {
2108 auto return_lhs_or_err = GetDemangledReturnTypeLHS(sc);
2109 if (!return_lhs_or_err) {
2110 LLDB_LOG_ERROR(GetLog(LLDBLog::Language), return_lhs_or_err.takeError(),
2111 "Failed to handle ${{function.return-left}} frame-format "
2112 "variable: {0}");
2113 return false;
2114 }
2115
2116 s << *return_lhs_or_err;
2117
2118 return true;
2119 }
2120 case FormatEntity::Entry::Type::FunctionQualifiers: {
2121 auto quals_or_err = GetDemangledFunctionQualifiers(sc);
2122 if (!quals_or_err) {
2123 LLDB_LOG_ERROR(GetLog(LLDBLog::Language), quals_or_err.takeError(),
2124 "Failed to handle ${{function.qualifiers}} frame-format "
2125 "variable: {0}");
2126 return false;
2127 }
2128
2129 s << *quals_or_err;
2130
2131 return true;
2132 }
2133 case FormatEntity::Entry::Type::FunctionSuffix: {
2134 auto suffix_or_err = GetDemangledFunctionSuffix(sc);
2135 if (!suffix_or_err) {
2136 LLDB_LOG_ERROR(
2137 GetLog(LLDBLog::Language), suffix_or_err.takeError(),
2138 "Failed to handle ${{function.suffix}} frame-format variable: {0}");
2139 return false;
2140 }
2141
2142 s << *suffix_or_err;
2143
2144 return true;
2145 }
2146 default:
2147 return false;
2148 }
2149 }
2150
2151 #define LLDB_PROPERTIES_language_cplusplus
2152 #include "LanguageCPlusPlusProperties.inc"
2153
2154 enum {
2155 #define LLDB_PROPERTIES_language_cplusplus
2156 #include "LanguageCPlusPlusPropertiesEnum.inc"
2157 };
2158
2159 namespace {
2160 class PluginProperties : public Properties {
2161 public:
GetSettingName()2162 static llvm::StringRef GetSettingName() { return "display"; }
2163
PluginProperties()2164 PluginProperties() {
2165 m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
2166 m_collection_sp->Initialize(g_language_cplusplus_properties);
2167 }
2168
GetFunctionNameFormat() const2169 FormatEntity::Entry GetFunctionNameFormat() const {
2170 return GetPropertyAtIndexAs<FormatEntity::Entry>(
2171 ePropertyFunctionNameFormat, {});
2172 }
2173 };
2174 } // namespace
2175
GetGlobalPluginProperties()2176 static PluginProperties &GetGlobalPluginProperties() {
2177 static PluginProperties g_settings;
2178 return g_settings;
2179 }
2180
GetFunctionNameFormat() const2181 FormatEntity::Entry CPlusPlusLanguage::GetFunctionNameFormat() const {
2182 return GetGlobalPluginProperties().GetFunctionNameFormat();
2183 }
2184
DebuggerInitialize(Debugger & debugger)2185 void CPlusPlusLanguage::DebuggerInitialize(Debugger &debugger) {
2186 if (!PluginManager::GetSettingForCPlusPlusLanguagePlugin(
2187 debugger, PluginProperties::GetSettingName())) {
2188 PluginManager::CreateSettingForCPlusPlusLanguagePlugin(
2189 debugger, GetGlobalPluginProperties().GetValueProperties(),
2190 "Properties for the CPlusPlus language plug-in.",
2191 /*is_global_property=*/true);
2192 }
2193 }
2194