aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp203
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp1761
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h178
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp785
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h188
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp227
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h60
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp214
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h49
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Generic.h25
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp154
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp138
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp939
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h244
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp151
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h33
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp119
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp426
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp499
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp194
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp65
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp88
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp166
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp153
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp95
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp388
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp145
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp281
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h29
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp279
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp472
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h67
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp112
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp183
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp105
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h50
37 files changed, 9290 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
new file mode 100644
index 000000000000..2c9b3c425397
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp
@@ -0,0 +1,203 @@
+//===-- BlockPointer.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "BlockPointer.h"
+
+#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h"
+#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Symbol/TypeSystem.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+
+class BlockPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ BlockPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_block_struct_type() {
+ CompilerType block_pointer_type(m_backend.GetCompilerType());
+ CompilerType function_pointer_type;
+ block_pointer_type.IsBlockPointerType(&function_pointer_type);
+
+ TargetSP target_sp(m_backend.GetTargetSP());
+
+ if (!target_sp) {
+ return;
+ }
+
+ auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(
+ lldb::eLanguageTypeC_plus_plus);
+ if (auto err = type_system_or_err.takeError()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), std::move(err),
+ "Failed to get scratch TypeSystemClang: {0}");
+ return;
+ }
+
+ auto ts = block_pointer_type.GetTypeSystem();
+ auto clang_ast_context = ts.dyn_cast_or_null<TypeSystemClang>();
+ if (!clang_ast_context)
+ return;
+
+ const char *const isa_name("__isa");
+ const CompilerType isa_type =
+ clang_ast_context->GetBasicType(lldb::eBasicTypeObjCClass);
+ const char *const flags_name("__flags");
+ const CompilerType flags_type =
+ clang_ast_context->GetBasicType(lldb::eBasicTypeInt);
+ const char *const reserved_name("__reserved");
+ const CompilerType reserved_type =
+ clang_ast_context->GetBasicType(lldb::eBasicTypeInt);
+ const char *const FuncPtr_name("__FuncPtr");
+
+ m_block_struct_type = clang_ast_context->CreateStructForIdentifier(
+ llvm::StringRef(), {{isa_name, isa_type},
+ {flags_name, flags_type},
+ {reserved_name, reserved_type},
+ {FuncPtr_name, function_pointer_type}});
+ }
+
+ ~BlockPointerSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ const bool omit_empty_base_classes = false;
+ return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr);
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ if (!m_block_struct_type.IsValid()) {
+ return lldb::ValueObjectSP();
+ }
+
+ if (idx >= CalculateNumChildrenIgnoringErrors()) {
+ return lldb::ValueObjectSP();
+ }
+
+ const bool thread_and_frame_only_if_stopped = true;
+ ExecutionContext exe_ctx = m_backend.GetExecutionContextRef().Lock(
+ thread_and_frame_only_if_stopped);
+ const bool transparent_pointers = false;
+ const bool omit_empty_base_classes = false;
+ const bool ignore_array_bounds = false;
+ ValueObject *value_object = nullptr;
+
+ std::string child_name;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
+ uint64_t language_flags = 0;
+
+ auto child_type_or_err = m_block_struct_type.GetChildCompilerTypeAtIndex(
+ &exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
+ ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
+ child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class,
+ child_is_deref_of_parent, value_object, language_flags);
+ if (!child_type_or_err)
+ return ValueObjectConstResult::Create(
+ exe_ctx.GetBestExecutionContextScope(),
+ Status(child_type_or_err.takeError()));
+ CompilerType child_type = *child_type_or_err;
+
+ ValueObjectSP struct_pointer_sp =
+ m_backend.Cast(m_block_struct_type.GetPointerType());
+
+ if (!struct_pointer_sp) {
+ return lldb::ValueObjectSP();
+ }
+
+ Status err;
+ ValueObjectSP struct_sp = struct_pointer_sp->Dereference(err);
+
+ if (!struct_sp || !err.Success()) {
+ return lldb::ValueObjectSP();
+ }
+
+ ValueObjectSP child_sp(struct_sp->GetSyntheticChildAtOffset(
+ child_byte_offset, child_type, true,
+ ConstString(child_name.c_str(), child_name.size())));
+
+ return child_sp;
+ }
+
+ // return true if this object is now safe to use forever without ever
+ // updating again; the typical (and tested) answer here is 'false'
+ lldb::ChildCacheState Update() override {
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ // maybe return false if the block pointer is, say, null
+ bool MightHaveChildren() override { return true; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ if (!m_block_struct_type.IsValid())
+ return UINT32_MAX;
+
+ const bool omit_empty_base_classes = false;
+ return m_block_struct_type.GetIndexOfChildWithName(name.AsCString(),
+ omit_empty_base_classes);
+ }
+
+private:
+ CompilerType m_block_struct_type;
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+bool lldb_private::formatters::BlockPointerSummaryProvider(
+ ValueObject &valobj, Stream &s, const TypeSummaryOptions &) {
+ lldb_private::SyntheticChildrenFrontEnd *synthetic_children =
+ BlockPointerSyntheticFrontEndCreator(nullptr, valobj.GetSP());
+ if (!synthetic_children) {
+ return false;
+ }
+
+ synthetic_children->Update();
+
+ static const ConstString s_FuncPtr_name("__FuncPtr");
+
+ lldb::ValueObjectSP child_sp = synthetic_children->GetChildAtIndex(
+ synthetic_children->GetIndexOfChildWithName(s_FuncPtr_name));
+
+ if (!child_sp) {
+ return false;
+ }
+
+ lldb::ValueObjectSP qualified_child_representation_sp =
+ child_sp->GetQualifiedRepresentationIfAvailable(
+ lldb::eDynamicDontRunTarget, true);
+
+ const char *child_value =
+ qualified_child_representation_sp->GetValueAsCString();
+
+ s.Printf("%s", child_value);
+
+ return true;
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::BlockPointerSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ return new BlockPointerSyntheticFrontEnd(valobj_sp);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h
new file mode 100644
index 000000000000..23f3f7b34b4f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.h
@@ -0,0 +1,25 @@
+//===-- BlockPointer.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_BLOCKPOINTER_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_BLOCKPOINTER_H
+
+#include "lldb/lldb-forward.h"
+
+namespace lldb_private {
+namespace formatters {
+bool BlockPointerSummaryProvider(ValueObject &, Stream &,
+ const TypeSummaryOptions &);
+
+SyntheticChildrenFrontEnd *
+BlockPointerSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_BLOCKPOINTER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
new file mode 100644
index 000000000000..06c827c2543f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -0,0 +1,1761 @@
+//===-- CPlusPlusLanguage.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CPlusPlusLanguage.h"
+
+#include <cctype>
+#include <cstring>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Demangle/ItaniumDemangle.h"
+
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/DataFormatters/CXXFunctionPointer.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/VectorType.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegularExpression.h"
+
+#include "BlockPointer.h"
+#include "CPlusPlusNameParser.h"
+#include "Coroutines.h"
+#include "CxxStringTypes.h"
+#include "Generic.h"
+#include "LibCxx.h"
+#include "LibCxxAtomic.h"
+#include "LibCxxVariant.h"
+#include "LibStdcpp.h"
+#include "MSVCUndecoratedNameParser.h"
+#include "lldb/lldb-enumerations.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+LLDB_PLUGIN_DEFINE(CPlusPlusLanguage)
+
+void CPlusPlusLanguage::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language",
+ CreateInstance);
+}
+
+void CPlusPlusLanguage::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const {
+ const char *mangled_name = mangled.GetMangledName().GetCString();
+ return mangled_name && CPlusPlusLanguage::IsCPPMangledName(mangled_name);
+}
+
+ConstString CPlusPlusLanguage::GetDemangledFunctionNameWithoutArguments(
+ Mangled mangled) const {
+ const char *mangled_name_cstr = mangled.GetMangledName().GetCString();
+ ConstString demangled_name = mangled.GetDemangledName();
+ if (demangled_name && mangled_name_cstr && mangled_name_cstr[0]) {
+ if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
+ (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure,
+ // typeinfo structure, and typeinfo
+ // mangled_name
+ mangled_name_cstr[2] != 'G' && // avoid guard variables
+ mangled_name_cstr[2] != 'Z')) // named local entities (if we
+ // eventually handle eSymbolTypeData,
+ // we will want this back)
+ {
+ CPlusPlusLanguage::MethodName cxx_method(demangled_name);
+ if (!cxx_method.GetBasename().empty()) {
+ std::string shortname;
+ if (!cxx_method.GetContext().empty())
+ shortname = cxx_method.GetContext().str() + "::";
+ shortname += cxx_method.GetBasename().str();
+ return ConstString(shortname);
+ }
+ }
+ }
+ if (demangled_name)
+ return demangled_name;
+ return mangled.GetMangledName();
+}
+
+// Static Functions
+
+Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) {
+ // Use plugin for C++ but not for Objective-C++ (which has its own plugin).
+ if (Language::LanguageIsCPlusPlus(language) &&
+ language != eLanguageTypeObjC_plus_plus)
+ return new CPlusPlusLanguage();
+ return nullptr;
+}
+
+void CPlusPlusLanguage::MethodName::Clear() {
+ m_full.Clear();
+ m_basename = llvm::StringRef();
+ m_context = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_return_type = llvm::StringRef();
+ m_parsed = false;
+ m_parse_error = false;
+}
+
+static bool 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) {
+ assert(left_right_chars.size() == 2);
+ left_pos = llvm::StringRef::npos;
+ const char left_char = left_right_chars[0];
+ const char right_char = left_right_chars[1];
+ pos = s.find_last_of(left_right_chars, pos);
+ if (pos == llvm::StringRef::npos || s[pos] == left_char)
+ return false;
+ right_pos = pos;
+ uint32_t depth = 1;
+ while (pos > 0 && depth > 0) {
+ pos = s.find_last_of(left_right_chars, pos);
+ if (pos == llvm::StringRef::npos)
+ return false;
+ if (s[pos] == left_char) {
+ if (--depth == 0) {
+ left_pos = pos;
+ return left_pos < right_pos;
+ }
+ } else if (s[pos] == right_char) {
+ ++depth;
+ }
+ }
+ return false;
+}
+
+static bool IsTrivialBasename(const llvm::StringRef &basename) {
+ // Check that the basename matches with the following regular expression
+ // "^~?([A-Za-z_][A-Za-z_0-9]*)$" We are using a hand written implementation
+ // because it is significantly more efficient then using the general purpose
+ // regular expression library.
+ size_t idx = 0;
+ if (basename.starts_with('~'))
+ idx = 1;
+
+ if (basename.size() <= idx)
+ return false; // Empty string or "~"
+
+ if (!std::isalpha(basename[idx]) && basename[idx] != '_')
+ return false; // First character (after removing the possible '~'') isn't in
+ // [A-Za-z_]
+
+ // Read all characters matching [A-Za-z_0-9]
+ ++idx;
+ while (idx < basename.size()) {
+ if (!std::isalnum(basename[idx]) && basename[idx] != '_')
+ break;
+ ++idx;
+ }
+
+ // We processed all characters. It is a vaild basename.
+ return idx == basename.size();
+}
+
+/// Writes out the function name in 'full_name' to 'out_stream'
+/// but replaces each argument type with the variable name
+/// and the corresponding pretty-printed value
+static bool PrettyPrintFunctionNameWithArgs(Stream &out_stream,
+ char const *full_name,
+ ExecutionContextScope *exe_scope,
+ VariableList const &args) {
+ CPlusPlusLanguage::MethodName cpp_method{ConstString(full_name)};
+
+ if (!cpp_method.IsValid())
+ return false;
+
+ llvm::StringRef return_type = cpp_method.GetReturnType();
+ if (!return_type.empty()) {
+ out_stream.PutCString(return_type);
+ out_stream.PutChar(' ');
+ }
+
+ out_stream.PutCString(cpp_method.GetScopeQualifiedName());
+ out_stream.PutChar('(');
+
+ FormatEntity::PrettyPrintFunctionArguments(out_stream, args, exe_scope);
+
+ out_stream.PutChar(')');
+
+ llvm::StringRef qualifiers = cpp_method.GetQualifiers();
+ if (!qualifiers.empty()) {
+ out_stream.PutChar(' ');
+ out_stream.PutCString(qualifiers);
+ }
+
+ return true;
+}
+
+bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
+ // This method tries to parse simple method definitions which are presumably
+ // most comman in user programs. Definitions that can be parsed by this
+ // function don't have return types and templates in the name.
+ // A::B::C::fun(std::vector<T> &) const
+ size_t arg_start, arg_end;
+ llvm::StringRef full(m_full.GetCString());
+ llvm::StringRef parens("()", 2);
+ if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
+ m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
+ if (arg_end + 1 < full.size())
+ m_qualifiers = full.substr(arg_end + 1).ltrim();
+
+ if (arg_start == 0)
+ return false;
+ size_t basename_end = arg_start;
+ size_t context_start = 0;
+ size_t context_end = full.rfind(':', basename_end);
+ if (context_end == llvm::StringRef::npos)
+ m_basename = full.substr(0, basename_end);
+ else {
+ if (context_start < context_end)
+ m_context = full.substr(context_start, context_end - 1 - context_start);
+ const size_t basename_begin = context_end + 1;
+ m_basename = full.substr(basename_begin, basename_end - basename_begin);
+ }
+
+ if (IsTrivialBasename(m_basename)) {
+ return true;
+ } else {
+ // The C++ basename doesn't match our regular expressions so this can't
+ // be a valid C++ method, clear everything out and indicate an error
+ m_context = llvm::StringRef();
+ m_basename = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_return_type = llvm::StringRef();
+ return false;
+ }
+ }
+ return false;
+}
+
+void CPlusPlusLanguage::MethodName::Parse() {
+ if (!m_parsed && m_full) {
+ if (TrySimplifiedParse()) {
+ m_parse_error = false;
+ } else {
+ CPlusPlusNameParser parser(m_full.GetStringRef());
+ if (auto function = parser.ParseAsFunctionDefinition()) {
+ m_basename = function->name.basename;
+ m_context = function->name.context;
+ m_arguments = function->arguments;
+ m_qualifiers = function->qualifiers;
+ m_return_type = function->return_type;
+ m_parse_error = false;
+ } else {
+ m_parse_error = true;
+ }
+ }
+ m_parsed = true;
+ }
+}
+
+llvm::StringRef CPlusPlusLanguage::MethodName::GetBasename() {
+ if (!m_parsed)
+ Parse();
+ return m_basename;
+}
+
+llvm::StringRef CPlusPlusLanguage::MethodName::GetContext() {
+ if (!m_parsed)
+ Parse();
+ return m_context;
+}
+
+llvm::StringRef CPlusPlusLanguage::MethodName::GetArguments() {
+ if (!m_parsed)
+ Parse();
+ return m_arguments;
+}
+
+llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
+ if (!m_parsed)
+ Parse();
+ return m_qualifiers;
+}
+
+llvm::StringRef CPlusPlusLanguage::MethodName::GetReturnType() {
+ if (!m_parsed)
+ Parse();
+ return m_return_type;
+}
+
+std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
+ if (!m_parsed)
+ Parse();
+ if (m_context.empty())
+ return std::string(m_basename);
+
+ std::string res;
+ res += m_context;
+ res += "::";
+ res += m_basename;
+ return res;
+}
+
+llvm::StringRef
+CPlusPlusLanguage::MethodName::GetBasenameNoTemplateParameters() {
+ llvm::StringRef basename = GetBasename();
+ size_t arg_start, arg_end;
+ llvm::StringRef parens("<>", 2);
+ if (ReverseFindMatchingChars(basename, parens, arg_start, arg_end))
+ return basename.substr(0, arg_start);
+
+ return basename;
+}
+
+bool CPlusPlusLanguage::MethodName::ContainsPath(llvm::StringRef path) {
+ if (!m_parsed)
+ Parse();
+
+ // If we can't parse the incoming name, then just check that it contains path.
+ if (m_parse_error)
+ return m_full.GetStringRef().contains(path);
+
+ llvm::StringRef identifier;
+ llvm::StringRef context;
+ std::string path_str = path.str();
+ bool success = CPlusPlusLanguage::ExtractContextAndIdentifier(
+ path_str.c_str(), context, identifier);
+ if (!success)
+ return m_full.GetStringRef().contains(path);
+
+ // Basename may include template arguments.
+ // E.g.,
+ // GetBaseName(): func<int>
+ // identifier : func
+ //
+ // ...but we still want to account for identifiers with template parameter
+ // lists, e.g., when users set breakpoints on template specializations.
+ //
+ // E.g.,
+ // GetBaseName(): func<uint32_t>
+ // identifier : func<int32_t*>
+ //
+ // Try to match the basename with or without template parameters.
+ if (GetBasename() != identifier &&
+ GetBasenameNoTemplateParameters() != identifier)
+ return false;
+
+ // Incoming path only had an identifier, so we match.
+ if (context.empty())
+ return true;
+ // Incoming path has context but this method does not, no match.
+ if (m_context.empty())
+ return false;
+
+ llvm::StringRef haystack = m_context;
+ if (!haystack.consume_back(context))
+ return false;
+ if (haystack.empty() || !isalnum(haystack.back()))
+ return true;
+
+ return false;
+}
+
+bool CPlusPlusLanguage::IsCPPMangledName(llvm::StringRef name) {
+ // FIXME!! we should really run through all the known C++ Language plugins
+ // and ask each one if this is a C++ mangled name
+
+ Mangled::ManglingScheme scheme = Mangled::GetManglingScheme(name);
+
+ if (scheme == Mangled::eManglingSchemeNone)
+ return false;
+
+ return true;
+}
+
+bool CPlusPlusLanguage::DemangledNameContainsPath(llvm::StringRef path,
+ ConstString demangled) const {
+ MethodName demangled_name(demangled);
+ return demangled_name.ContainsPath(path);
+}
+
+bool CPlusPlusLanguage::ExtractContextAndIdentifier(
+ const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
+ if (MSVCUndecoratedNameParser::IsMSVCUndecoratedName(name))
+ return MSVCUndecoratedNameParser::ExtractContextAndIdentifier(name, context,
+ identifier);
+
+ CPlusPlusNameParser parser(name);
+ if (auto full_name = parser.ParseAsFullName()) {
+ identifier = full_name->basename;
+ context = full_name->context;
+ return true;
+ }
+ return false;
+}
+
+namespace {
+class NodeAllocator {
+ llvm::BumpPtrAllocator Alloc;
+
+public:
+ void reset() { Alloc.Reset(); }
+
+ template <typename T, typename... Args> T *makeNode(Args &&... args) {
+ return new (Alloc.Allocate(sizeof(T), alignof(T)))
+ T(std::forward<Args>(args)...);
+ }
+
+ void *allocateNodeArray(size_t sz) {
+ return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
+ alignof(llvm::itanium_demangle::Node *));
+ }
+};
+
+template <typename Derived>
+class ManglingSubstitutor
+ : public llvm::itanium_demangle::AbstractManglingParser<Derived,
+ NodeAllocator> {
+ using Base =
+ llvm::itanium_demangle::AbstractManglingParser<Derived, NodeAllocator>;
+
+public:
+ ManglingSubstitutor() : Base(nullptr, nullptr) {}
+
+ template <typename... Ts>
+ ConstString substitute(llvm::StringRef Mangled, Ts &&... Vals) {
+ this->getDerived().reset(Mangled, std::forward<Ts>(Vals)...);
+ return substituteImpl(Mangled);
+ }
+
+protected:
+ void reset(llvm::StringRef Mangled) {
+ Base::reset(Mangled.begin(), Mangled.end());
+ Written = Mangled.begin();
+ Result.clear();
+ Substituted = false;
+ }
+
+ ConstString substituteImpl(llvm::StringRef Mangled) {
+ Log *log = GetLog(LLDBLog::Language);
+ if (this->parse() == nullptr) {
+ LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
+ return ConstString();
+ }
+ if (!Substituted)
+ return ConstString();
+
+ // Append any trailing unmodified input.
+ appendUnchangedInput();
+ LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
+ return ConstString(Result);
+ }
+
+ void trySubstitute(llvm::StringRef From, llvm::StringRef To) {
+ if (!llvm::StringRef(currentParserPos(), this->numLeft()).starts_with(From))
+ return;
+
+ // We found a match. Append unmodified input up to this point.
+ appendUnchangedInput();
+
+ // And then perform the replacement.
+ Result += To;
+ Written += From.size();
+ Substituted = true;
+ }
+
+private:
+ /// Input character until which we have constructed the respective output
+ /// already.
+ const char *Written = "";
+
+ llvm::SmallString<128> Result;
+
+ /// Whether we have performed any substitutions.
+ bool Substituted = false;
+
+ const char *currentParserPos() const { return this->First; }
+
+ void appendUnchangedInput() {
+ Result +=
+ llvm::StringRef(Written, std::distance(Written, currentParserPos()));
+ Written = currentParserPos();
+ }
+};
+
+/// Given a mangled function `Mangled`, replace all the primitive function type
+/// arguments of `Search` with type `Replace`.
+class TypeSubstitutor : public ManglingSubstitutor<TypeSubstitutor> {
+ llvm::StringRef Search;
+ llvm::StringRef Replace;
+
+public:
+ void reset(llvm::StringRef Mangled, llvm::StringRef Search,
+ llvm::StringRef Replace) {
+ ManglingSubstitutor::reset(Mangled);
+ this->Search = Search;
+ this->Replace = Replace;
+ }
+
+ llvm::itanium_demangle::Node *parseType() {
+ trySubstitute(Search, Replace);
+ return ManglingSubstitutor::parseType();
+ }
+};
+
+class CtorDtorSubstitutor : public ManglingSubstitutor<CtorDtorSubstitutor> {
+public:
+ llvm::itanium_demangle::Node *
+ parseCtorDtorName(llvm::itanium_demangle::Node *&SoFar, NameState *State) {
+ trySubstitute("C1", "C2");
+ trySubstitute("D1", "D2");
+ return ManglingSubstitutor::parseCtorDtorName(SoFar, State);
+ }
+};
+} // namespace
+
+std::vector<ConstString> CPlusPlusLanguage::GenerateAlternateFunctionManglings(
+ const ConstString mangled_name) const {
+ std::vector<ConstString> alternates;
+
+ /// Get a basic set of alternative manglings for the given symbol `name`, by
+ /// making a few basic possible substitutions on basic types, storage duration
+ /// and `const`ness for the given symbol. The output parameter `alternates`
+ /// is filled with a best-guess, non-exhaustive set of different manglings
+ /// for the given name.
+
+ // Maybe we're looking for a const symbol but the debug info told us it was
+ // non-const...
+ if (!strncmp(mangled_name.GetCString(), "_ZN", 3) &&
+ strncmp(mangled_name.GetCString(), "_ZNK", 4)) {
+ std::string fixed_scratch("_ZNK");
+ fixed_scratch.append(mangled_name.GetCString() + 3);
+ alternates.push_back(ConstString(fixed_scratch));
+ }
+
+ // Maybe we're looking for a static symbol but we thought it was global...
+ if (!strncmp(mangled_name.GetCString(), "_Z", 2) &&
+ strncmp(mangled_name.GetCString(), "_ZL", 3)) {
+ std::string fixed_scratch("_ZL");
+ fixed_scratch.append(mangled_name.GetCString() + 2);
+ alternates.push_back(ConstString(fixed_scratch));
+ }
+
+ TypeSubstitutor TS;
+ // `char` is implementation defined as either `signed` or `unsigned`. As a
+ // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
+ // char, 'h'-unsigned char. If we're looking for symbols with a signed char
+ // parameter, try finding matches which have the general case 'c'.
+ if (ConstString char_fixup =
+ TS.substitute(mangled_name.GetStringRef(), "a", "c"))
+ alternates.push_back(char_fixup);
+
+ // long long parameter mangling 'x', may actually just be a long 'l' argument
+ if (ConstString long_fixup =
+ TS.substitute(mangled_name.GetStringRef(), "x", "l"))
+ alternates.push_back(long_fixup);
+
+ // unsigned long long parameter mangling 'y', may actually just be unsigned
+ // long 'm' argument
+ if (ConstString ulong_fixup =
+ TS.substitute(mangled_name.GetStringRef(), "y", "m"))
+ alternates.push_back(ulong_fixup);
+
+ if (ConstString ctor_fixup =
+ CtorDtorSubstitutor().substitute(mangled_name.GetStringRef()))
+ alternates.push_back(ctor_fixup);
+
+ return alternates;
+}
+
+ConstString CPlusPlusLanguage::FindBestAlternateFunctionMangledName(
+ const Mangled mangled, const SymbolContext &sym_ctx) const {
+ ConstString demangled = mangled.GetDemangledName();
+ if (!demangled)
+ return ConstString();
+
+ CPlusPlusLanguage::MethodName cpp_name(demangled);
+ std::string scope_qualified_name = cpp_name.GetScopeQualifiedName();
+
+ if (!scope_qualified_name.size())
+ return ConstString();
+
+ if (!sym_ctx.module_sp)
+ return ConstString();
+
+ lldb_private::SymbolFile *sym_file = sym_ctx.module_sp->GetSymbolFile();
+ if (!sym_file)
+ return ConstString();
+
+ std::vector<ConstString> alternates;
+ sym_file->GetMangledNamesForFunction(scope_qualified_name, alternates);
+
+ std::vector<ConstString> param_and_qual_matches;
+ std::vector<ConstString> param_matches;
+ for (size_t i = 0; i < alternates.size(); i++) {
+ ConstString alternate_mangled_name = alternates[i];
+ Mangled mangled(alternate_mangled_name);
+ ConstString demangled = mangled.GetDemangledName();
+
+ CPlusPlusLanguage::MethodName alternate_cpp_name(demangled);
+ if (!cpp_name.IsValid())
+ continue;
+
+ if (alternate_cpp_name.GetArguments() == cpp_name.GetArguments()) {
+ if (alternate_cpp_name.GetQualifiers() == cpp_name.GetQualifiers())
+ param_and_qual_matches.push_back(alternate_mangled_name);
+ else
+ param_matches.push_back(alternate_mangled_name);
+ }
+ }
+
+ if (param_and_qual_matches.size())
+ return param_and_qual_matches[0]; // It is assumed that there will be only
+ // one!
+ else if (param_matches.size())
+ return param_matches[0]; // Return one of them as a best match
+ else
+ return ConstString();
+}
+
+static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
+ if (!cpp_category_sp)
+ return;
+
+ TypeSummaryImpl::Flags stl_summary_flags;
+ stl_summary_flags.SetCascades(true)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringSummaryProviderASCII,
+ "std::string summary provider", "^std::__[[:alnum:]]+::string$",
+ stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringSummaryProviderASCII,
+ "std::string summary provider",
+ "^std::__[[:alnum:]]+::basic_string<char, "
+ "std::__[[:alnum:]]+::char_traits<char>, "
+ "std::__[[:alnum:]]+::allocator<char> >$",
+ stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringSummaryProviderASCII,
+ "std::string summary provider",
+ "^std::__[[:alnum:]]+::basic_string<unsigned char, "
+ "std::__[[:alnum:]]+::char_traits<unsigned char>, "
+ "std::__[[:alnum:]]+::allocator<unsigned char> >$",
+ stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringSummaryProviderUTF16,
+ "std::u16string summary provider",
+ "^std::__[[:alnum:]]+::basic_string<char16_t, "
+ "std::__[[:alnum:]]+::char_traits<char16_t>, "
+ "std::__[[:alnum:]]+::allocator<char16_t> >$",
+ stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringSummaryProviderUTF32,
+ "std::u32string summary provider",
+ "^std::__[[:alnum:]]+::basic_string<char32_t, "
+ "std::__[[:alnum:]]+::char_traits<char32_t>, "
+ "std::__[[:alnum:]]+::allocator<char32_t> >$",
+ stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxWStringSummaryProvider,
+ "std::wstring summary provider",
+ "^std::__[[:alnum:]]+::wstring$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxWStringSummaryProvider,
+ "std::wstring summary provider",
+ "^std::__[[:alnum:]]+::basic_string<wchar_t, "
+ "std::__[[:alnum:]]+::char_traits<wchar_t>, "
+ "std::__[[:alnum:]]+::allocator<wchar_t> >$",
+ stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
+ "std::string_view summary provider",
+ "^std::__[[:alnum:]]+::string_view$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
+ "std::string_view summary provider",
+ "^std::__[[:alnum:]]+::basic_string_view<char, "
+ "std::__[[:alnum:]]+::char_traits<char> >$",
+ stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringViewSummaryProviderASCII,
+ "std::string_view summary provider",
+ "^std::__[[:alnum:]]+::basic_string_view<unsigned char, "
+ "std::__[[:alnum:]]+::char_traits<unsigned char> >$",
+ stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16,
+ "std::u16string_view summary provider",
+ "^std::__[[:alnum:]]+::basic_string_view<char16_t, "
+ "std::__[[:alnum:]]+::char_traits<char16_t> >$",
+ stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32,
+ "std::u32string_view summary provider",
+ "^std::__[[:alnum:]]+::basic_string_view<char32_t, "
+ "std::__[[:alnum:]]+::char_traits<char32_t> >$",
+ stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxWStringViewSummaryProvider,
+ "std::wstring_view summary provider",
+ "^std::__[[:alnum:]]+::wstring_view$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxWStringViewSummaryProvider,
+ "std::wstring_view summary provider",
+ "^std::__[[:alnum:]]+::basic_string_view<wchar_t, "
+ "std::__[[:alnum:]]+::char_traits<wchar_t> >$",
+ stl_summary_flags, true);
+
+ SyntheticChildren::Flags stl_synth_flags;
+ stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
+ false);
+ SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
+ stl_deref_flags.SetFrontEndWantsDereference();
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator,
+ "libc++ std::bitset synthetic children",
+ "^std::__[[:alnum:]]+::bitset<.+>$", stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
+ "libc++ std::vector synthetic children",
+ "^std::__[[:alnum:]]+::vector<.+>$", stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator,
+ "libc++ std::valarray synthetic children",
+ "^std::__[[:alnum:]]+::valarray<.+>$", stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator,
+ "libc++ std::slice_array synthetic children",
+ "^std::__[[:alnum:]]+::slice_array<.+>$", stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator,
+ "libc++ synthetic children for the valarray proxy arrays",
+ "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
+ stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator,
+ "libc++ std::forward_list synthetic children",
+ "^std::__[[:alnum:]]+::forward_list<.+>$", stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator,
+ "libc++ std::list synthetic children",
+ // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$"
+ // so that it does not clash with: "^std::(__cxx11::)?list<.+>$"
+ "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
+ "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$",
+ stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
+ "libc++ std::map synthetic children", "^std::__[[:alnum:]]+::map<.+> >$",
+ stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
+ "libc++ std::set synthetic children", "^std::__[[:alnum:]]+::set<.+> >$",
+ stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
+ "libc++ std::multiset synthetic children",
+ "^std::__[[:alnum:]]+::multiset<.+> >$", stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator,
+ "libc++ std::multimap synthetic children",
+ "^std::__[[:alnum:]]+::multimap<.+> >$", stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator,
+ "libc++ std::unordered containers synthetic children",
+ "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
+ stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator,
+ "libc++ std::initializer_list synthetic children",
+ "^std::initializer_list<.+>$", stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator,
+ "libc++ std::queue synthetic children",
+ "^std::__[[:alnum:]]+::queue<.+>$", stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator,
+ "libc++ std::tuple synthetic children",
+ "^std::__[[:alnum:]]+::tuple<.*>$", stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, LibcxxOptionalSyntheticFrontEndCreator,
+ "libc++ std::optional synthetic children",
+ "^std::__[[:alnum:]]+::optional<.+>$", stl_synth_flags, true);
+ AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator,
+ "libc++ std::variant synthetic children",
+ "^std::__[[:alnum:]]+::variant<.+>$", stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator,
+ "libc++ std::atomic synthetic children",
+ "^std::__[[:alnum:]]+::atomic<.+>$", stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdSpanSyntheticFrontEndCreator,
+ "libc++ std::span synthetic children", "^std::__[[:alnum:]]+::span<.+>$",
+ stl_deref_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEndCreator,
+ "libc++ std::ranges::ref_view synthetic children",
+ "^std::__[[:alnum:]]+::ranges::ref_view<.+>$", stl_deref_flags, true);
+
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::__[[:alnum:]]+::deque<.+>$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_synth_flags,
+ "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
+ "shared_ptr synthetic children", "^std::__[[:alnum:]]+::shared_ptr<.+>$",
+ stl_synth_flags, true);
+
+ static constexpr const char *const libcxx_std_unique_ptr_regex =
+ "^std::__[[:alnum:]]+::unique_ptr<.+>$";
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator,
+ "unique_ptr synthetic children", libcxx_std_unique_ptr_regex,
+ stl_synth_flags, true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator,
+ "weak_ptr synthetic children", "^std::__[[:alnum:]]+::weak_ptr<.+>$",
+ stl_synth_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxFunctionSummaryProvider,
+ "libc++ std::function summary provider",
+ "^std::__[[:alnum:]]+::function<.+>$", stl_summary_flags, true);
+
+ static constexpr const char *const libcxx_std_coroutine_handle_regex =
+ "^std::__[[:alnum:]]+::coroutine_handle<.+>$";
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator,
+ "coroutine_handle synthetic children", libcxx_std_coroutine_handle_regex,
+ stl_deref_flags, true);
+
+ stl_summary_flags.SetDontShowChildren(false);
+ stl_summary_flags.SetSkipPointers(false);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::bitset summary provider",
+ "^std::__[[:alnum:]]+::bitset<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::vector summary provider",
+ "^std::__[[:alnum:]]+::vector<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::valarray summary provider",
+ "^std::__[[:alnum:]]+::valarray<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxStdSliceArraySummaryProvider,
+ "libc++ std::slice_array summary provider",
+ "^std::__[[:alnum:]]+::slice_array<.+>$", stl_summary_flags,
+ true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ summary provider for the valarray proxy arrays",
+ "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$",
+ stl_summary_flags, true);
+ AddCXXSummary(
+ cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::list summary provider",
+ "^std::__[[:alnum:]]+::forward_list<.+>$", stl_summary_flags, true);
+ AddCXXSummary(
+ cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::list summary provider",
+ // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$"
+ // so that it does not clash with: "^std::(__cxx11::)?list<.+>$"
+ "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|"
+ "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$",
+ stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::map summary provider",
+ "^std::__[[:alnum:]]+::map<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::deque summary provider",
+ "^std::__[[:alnum:]]+::deque<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::queue summary provider",
+ "^std::__[[:alnum:]]+::queue<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::set summary provider",
+ "^std::__[[:alnum:]]+::set<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::multiset summary provider",
+ "^std::__[[:alnum:]]+::multiset<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::multimap summary provider",
+ "^std::__[[:alnum:]]+::multimap<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::unordered containers summary provider",
+ "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$",
+ stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp, LibcxxContainerSummaryProvider,
+ "libc++ std::tuple summary provider",
+ "^std::__[[:alnum:]]+::tuple<.*>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibCxxAtomicSummaryProvider,
+ "libc++ std::atomic summary provider",
+ "^std::__[[:alnum:]]+::atomic<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::GenericOptionalSummaryProvider,
+ "libc++ std::optional summary provider",
+ "^std::__[[:alnum:]]+::optional<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxVariantSummaryProvider,
+ "libc++ std::variant summary provider",
+ "^std::__[[:alnum:]]+::variant<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxContainerSummaryProvider,
+ "libc++ std::span summary provider",
+ "^std::__[[:alnum:]]+::span<.+>$", stl_summary_flags, true);
+
+ stl_summary_flags.SetSkipPointers(true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
+ "libc++ std::shared_ptr summary provider",
+ "^std::__[[:alnum:]]+::shared_ptr<.+>$", stl_summary_flags,
+ true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxSmartPointerSummaryProvider,
+ "libc++ std::weak_ptr summary provider",
+ "^std::__[[:alnum:]]+::weak_ptr<.+>$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxUniquePointerSummaryProvider,
+ "libc++ std::unique_ptr summary provider",
+ libcxx_std_unique_ptr_regex, stl_summary_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
+ "libc++ std::coroutine_handle summary provider",
+ libcxx_std_coroutine_handle_regex, stl_summary_flags, true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator,
+ "std::vector iterator synthetic children",
+ "^std::__[[:alnum:]]+::__wrap_iter<.+>$", stl_synth_flags, true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator,
+ "std::map iterator synthetic children",
+ "^std::__[[:alnum:]]+::__map_(const_)?iterator<.+>$", stl_synth_flags,
+ true);
+
+ AddCXXSynthetic(cpp_category_sp,
+ lldb_private::formatters::
+ LibCxxUnorderedMapIteratorSyntheticFrontEndCreator,
+ "std::unordered_map iterator synthetic children",
+ "^std::__[[:alnum:]]+::__hash_map_(const_)?iterator<.+>$",
+ stl_synth_flags, true);
+ // Chrono duration typedefs
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::nanoseconds", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ns")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::microseconds", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} µs")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::milliseconds", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} ms")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::minutes", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__rep_} min")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::hours", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} h")));
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::days", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__rep_} days")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::weeks", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__rep_} weeks")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::months", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__rep_} months")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::years", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__rep_} years")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::seconds", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s")));
+
+ // Chrono time point types
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider,
+ "libc++ std::chrono::sys_seconds summary provider",
+ "^std::__[[:alnum:]]+::chrono::time_point<"
+ "std::__[[:alnum:]]+::chrono::system_clock, "
+ "std::__[[:alnum:]]+::chrono::duration<.*, "
+ "std::__[[:alnum:]]+::ratio<1, 1> "
+ "> >$",
+ eTypeOptionHideChildren | eTypeOptionHideValue |
+ eTypeOptionCascade,
+ true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider,
+ "libc++ std::chrono::sys_seconds summary provider",
+ "^std::__[[:alnum:]]+::chrono::time_point<"
+ "std::__[[:alnum:]]+::chrono::system_clock, "
+ "std::__[[:alnum:]]+::chrono::duration<int, "
+ "std::__[[:alnum:]]+::ratio<86400, 1> "
+ "> >$",
+ eTypeOptionHideChildren | eTypeOptionHideValue |
+ eTypeOptionCascade,
+ true);
+
+ AddCXXSummary(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider,
+ "libc++ std::chrono::local_seconds summary provider",
+ "^std::__[[:alnum:]]+::chrono::time_point<"
+ "std::__[[:alnum:]]+::chrono::local_t, "
+ "std::__[[:alnum:]]+::chrono::duration<.*, "
+ "std::__[[:alnum:]]+::ratio<1, 1> "
+ "> >$",
+ eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade,
+ true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider,
+ "libc++ std::chrono::local_seconds summary provider",
+ "^std::__[[:alnum:]]+::chrono::time_point<"
+ "std::__[[:alnum:]]+::chrono::local_t, "
+ "std::__[[:alnum:]]+::chrono::duration<int, "
+ "std::__[[:alnum:]]+::ratio<86400, 1> "
+ "> >$",
+ eTypeOptionHideChildren | eTypeOptionHideValue |
+ eTypeOptionCascade,
+ true);
+
+ // Chrono calendar types
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::day$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "day=${var.__d_%u}")));
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxChronoMonthSummaryProvider,
+ "libc++ std::chrono::month summary provider",
+ "^std::__[[:alnum:]]+::chrono::month$",
+ eTypeOptionHideChildren | eTypeOptionHideValue, true);
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::year$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue, "year=${var.__y_}")));
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider,
+ "libc++ std::chrono::weekday summary provider",
+ "^std::__[[:alnum:]]+::chrono::weekday$",
+ eTypeOptionHideChildren | eTypeOptionHideValue, true);
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::weekday_indexed$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue,
+ "${var.__wd_} index=${var.__idx_%u}")));
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::weekday_last$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__wd_} index=last")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::month_day$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__m_} ${var.__d_}")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::month_day_last$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__m_} day=last")));
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::month_weekday$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__m_} ${var.__wdi_}")));
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::month_weekday_last$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__m_} ${var.__wdl_}")));
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::year_month$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__y_} ${var.__m_}")));
+
+ AddCXXSummary(
+ cpp_category_sp,
+ lldb_private::formatters::LibcxxChronoYearMonthDaySummaryProvider,
+ "libc++ std::chrono::year_month_day summary provider",
+ "^std::__[[:alnum:]]+::chrono::year_month_day$",
+ eTypeOptionHideChildren | eTypeOptionHideValue, true);
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::year_month_day_last$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(eTypeOptionHideChildren |
+ eTypeOptionHideValue,
+ "${var.__y_} ${var.__mdl_}")));
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::year_month_weekday$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue,
+ "${var.__y_} ${var.__m_} ${var.__wdi_}")));
+
+ cpp_category_sp->AddTypeSummary(
+ "^std::__[[:alnum:]]+::chrono::year_month_weekday_last$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ eTypeOptionHideChildren | eTypeOptionHideValue,
+ "${var.__y_} ${var.__m_} ${var.__wdl_}")));
+}
+
+static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
+ if (!cpp_category_sp)
+ return;
+
+ TypeSummaryImpl::Flags stl_summary_flags;
+ stl_summary_flags.SetCascades(true)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ lldb::TypeSummaryImplSP std_string_summary_sp(
+ new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}"));
+
+ lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(
+ stl_summary_flags, LibStdcppStringSummaryProvider,
+ "libstdc++ c++11 std::string summary provider"));
+ lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(
+ stl_summary_flags, LibStdcppWStringSummaryProvider,
+ "libstdc++ c++11 std::wstring summary provider"));
+
+ cpp_category_sp->AddTypeSummary("std::string", eFormatterMatchExact,
+ std_string_summary_sp);
+ cpp_category_sp->AddTypeSummary("std::basic_string<char>",
+ eFormatterMatchExact, std_string_summary_sp);
+ cpp_category_sp->AddTypeSummary(
+ "std::basic_string<char,std::char_traits<char>,std::allocator<char> >",
+ eFormatterMatchExact, std_string_summary_sp);
+ cpp_category_sp->AddTypeSummary(
+ "std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
+ eFormatterMatchExact, std_string_summary_sp);
+
+ cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
+ cxx11_string_summary_sp);
+ cpp_category_sp->AddTypeSummary(
+ "std::__cxx11::basic_string<char, std::char_traits<char>, "
+ "std::allocator<char> >",
+ eFormatterMatchExact, cxx11_string_summary_sp);
+ cpp_category_sp->AddTypeSummary("std::__cxx11::basic_string<unsigned char, "
+ "std::char_traits<unsigned char>, "
+ "std::allocator<unsigned char> >",
+ eFormatterMatchExact,
+ cxx11_string_summary_sp);
+
+ // making sure we force-pick the summary for printing wstring (_M_p is a
+ // wchar_t*)
+ lldb::TypeSummaryImplSP std_wstring_summary_sp(
+ new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
+
+ cpp_category_sp->AddTypeSummary("std::wstring", eFormatterMatchExact,
+ std_wstring_summary_sp);
+ cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t>",
+ eFormatterMatchExact, std_wstring_summary_sp);
+ cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t,std::char_traits<"
+ "wchar_t>,std::allocator<wchar_t> >",
+ eFormatterMatchExact, std_wstring_summary_sp);
+ cpp_category_sp->AddTypeSummary(
+ "std::basic_string<wchar_t, std::char_traits<wchar_t>, "
+ "std::allocator<wchar_t> >",
+ eFormatterMatchExact, std_wstring_summary_sp);
+
+ cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact,
+ cxx11_wstring_summary_sp);
+ cpp_category_sp->AddTypeSummary(
+ "std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, "
+ "std::allocator<wchar_t> >",
+ eFormatterMatchExact, cxx11_wstring_summary_sp);
+
+ SyntheticChildren::Flags stl_synth_flags;
+ stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
+ false);
+ SyntheticChildren::Flags stl_deref_flags = stl_synth_flags;
+ stl_deref_flags.SetFrontEndWantsDereference();
+
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::vector<.+>(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_synth_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::map<.+> >(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_synth_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::deque<.+>(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_deref_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::set<.+> >(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_deref_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::multimap<.+> >(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_deref_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::multiset<.+> >(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_deref_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::unordered_(multi)?(map|set)<.+> >$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_deref_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdUnorderedMapSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::(__cxx11::)?list<.+>(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_deref_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::(__cxx11::)?forward_list<.+>(( )?&)?$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_synth_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider")));
+ cpp_category_sp->AddTypeSynthetic(
+ "^std::variant<.+>$", eFormatterMatchRegex,
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(
+ stl_synth_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider")));
+
+ stl_summary_flags.SetDontShowChildren(false);
+ stl_summary_flags.SetSkipPointers(false);
+ cpp_category_sp->AddTypeSummary("^std::bitset<.+>(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::vector<.+>(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::map<.+> >(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::set<.+> >(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::deque<.+>(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::multimap<.+> >(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::multiset<.+> >(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::unordered_(multi)?(map|set)<.+> >$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary("^std::(__cxx11::)?list<.+>(( )?&)?$",
+ eFormatterMatchRegex,
+ TypeSummaryImplSP(new StringSummaryFormat(
+ stl_summary_flags, "size=${svar%#}")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::(__cxx11::)?forward_list<.+>(( )?&)?$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new ScriptSummaryFormat(
+ stl_summary_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider")));
+ cpp_category_sp->AddTypeSummary(
+ "^std::variant<.+>$", eFormatterMatchRegex,
+ TypeSummaryImplSP(new ScriptSummaryFormat(
+ stl_summary_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.VariantSummaryProvider")));
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator,
+ "std::vector iterator synthetic children",
+ "^__gnu_cxx::__normal_iterator<.+>$", stl_synth_flags, true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator,
+ "std::map iterator synthetic children", "^std::_Rb_tree_iterator<.+>$",
+ stl_synth_flags, true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
+ "std::unique_ptr synthetic children", "^std::unique_ptr<.+>(( )?&)?$",
+ stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
+ "std::shared_ptr synthetic children", "^std::shared_ptr<.+>(( )?&)?$",
+ stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
+ "std::weak_ptr synthetic children", "^std::weak_ptr<.+>(( )?&)?$",
+ stl_synth_flags, true);
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
+ "std::tuple synthetic children", "^std::tuple<.+>(( )?&)?$",
+ stl_synth_flags, true);
+
+ static constexpr const char *const libstdcpp_std_coroutine_handle_regex =
+ "^std::coroutine_handle<.+>(( )?&)?$";
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator,
+ "std::coroutine_handle synthetic children",
+ libstdcpp_std_coroutine_handle_regex, stl_deref_flags, true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibStdcppBitsetSyntheticFrontEndCreator,
+ "std::bitset synthetic child", "^std::bitset<.+>(( )?&)?$",
+ stl_deref_flags, true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator,
+ "std::optional synthetic child", "^std::optional<.+>(( )?&)?$",
+ stl_deref_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
+ "libstdc++ std::unique_ptr summary provider",
+ "^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
+ "libstdc++ std::shared_ptr summary provider",
+ "^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
+ "libstdc++ std::weak_ptr summary provider",
+ "^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
+ "libstdc++ std::coroutine_handle summary provider",
+ libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::GenericOptionalSummaryProvider,
+ "libstd++ std::optional summary provider",
+ "^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
+}
+
+static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
+ if (!cpp_category_sp)
+ return;
+
+ TypeSummaryImpl::Flags string_flags;
+ string_flags.SetCascades(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ TypeSummaryImpl::Flags string_array_flags;
+ string_array_flags.SetCascades(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char8StringSummaryProvider,
+ "char8_t * summary provider", "char8_t *", string_flags);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char8StringSummaryProvider,
+ "char8_t [] summary provider", "char8_t ?\\[[0-9]+\\]",
+ string_array_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char16StringSummaryProvider,
+ "char16_t * summary provider", "char16_t *", string_flags);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char16StringSummaryProvider,
+ "char16_t [] summary provider", "char16_t ?\\[[0-9]+\\]",
+ string_array_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char32StringSummaryProvider,
+ "char32_t * summary provider", "char32_t *", string_flags);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char32StringSummaryProvider,
+ "char32_t [] summary provider", "char32_t ?\\[[0-9]+\\]",
+ string_array_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::WCharStringSummaryProvider,
+ "wchar_t * summary provider", "wchar_t *", string_flags);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::WCharStringSummaryProvider,
+ "wchar_t * summary provider", "wchar_t ?\\[[0-9]+\\]",
+ string_array_flags, true);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char16StringSummaryProvider,
+ "unichar * summary provider", "unichar *", string_flags);
+
+ TypeSummaryImpl::Flags widechar_flags;
+ widechar_flags.SetDontShowValue(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetCascades(true)
+ .SetDontShowChildren(true)
+ .SetHideItemNames(true)
+ .SetShowMembersOneLiner(false);
+
+ AddCXXSummary(cpp_category_sp, lldb_private::formatters::Char8SummaryProvider,
+ "char8_t summary provider", "char8_t", widechar_flags);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char16SummaryProvider,
+ "char16_t summary provider", "char16_t", widechar_flags);
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char32SummaryProvider,
+ "char32_t summary provider", "char32_t", widechar_flags);
+ AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider,
+ "wchar_t summary provider", "wchar_t", widechar_flags);
+
+ AddCXXSummary(cpp_category_sp,
+ lldb_private::formatters::Char16SummaryProvider,
+ "unichar summary provider", "unichar", widechar_flags);
+}
+
+std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() {
+ class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger {
+ public:
+ CompilerType AdjustForInclusion(CompilerType &candidate) override {
+ LanguageType lang_type(candidate.GetMinimumLanguage());
+ if (!Language::LanguageIsC(lang_type) &&
+ !Language::LanguageIsCPlusPlus(lang_type))
+ return CompilerType();
+ if (candidate.IsTypedefType())
+ return candidate.GetTypedefedType();
+ return candidate;
+ }
+ };
+
+ return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
+}
+
+lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
+ static llvm::once_flag g_initialize;
+ static TypeCategoryImplSP g_category;
+
+ llvm::call_once(g_initialize, [this]() -> void {
+ DataVisualization::Categories::GetCategory(ConstString(GetPluginName()),
+ g_category);
+ if (g_category) {
+ LoadLibStdcppFormatters(g_category);
+ LoadLibCxxFormatters(g_category);
+ LoadSystemFormatters(g_category);
+ }
+ });
+ return g_category;
+}
+
+HardcodedFormatters::HardcodedSummaryFinder
+CPlusPlusLanguage::GetHardcodedSummaries() {
+ static llvm::once_flag g_initialize;
+ static ConstString g_vectortypes("VectorTypes");
+ static HardcodedFormatters::HardcodedSummaryFinder g_formatters;
+
+ llvm::call_once(g_initialize, []() -> void {
+ g_formatters.push_back(
+ [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
+ FormatManager &) -> TypeSummaryImpl::SharedPointer {
+ static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
+ new CXXFunctionSummaryFormat(
+ TypeSummaryImpl::Flags(),
+ lldb_private::formatters::CXXFunctionPointerSummaryProvider,
+ "Function pointer summary provider"));
+ if (CompilerType CT = valobj.GetCompilerType();
+ CT.IsFunctionPointerType() || CT.IsMemberFunctionPointerType() ||
+ valobj.GetValueType() == lldb::eValueTypeVTableEntry) {
+ return formatter_sp;
+ }
+ return nullptr;
+ });
+ g_formatters.push_back(
+ [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
+ FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
+ static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
+ new CXXFunctionSummaryFormat(
+ TypeSummaryImpl::Flags()
+ .SetCascades(true)
+ .SetDontShowChildren(true)
+ .SetHideItemNames(true)
+ .SetShowMembersOneLiner(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false),
+ lldb_private::formatters::VectorTypeSummaryProvider,
+ "vector_type pointer summary provider"));
+ if (valobj.GetCompilerType().IsVectorType()) {
+ if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
+ return formatter_sp;
+ }
+ return nullptr;
+ });
+ g_formatters.push_back(
+ [](lldb_private::ValueObject &valobj, lldb::DynamicValueType,
+ FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer {
+ static CXXFunctionSummaryFormat::SharedPointer formatter_sp(
+ new CXXFunctionSummaryFormat(
+ TypeSummaryImpl::Flags()
+ .SetCascades(true)
+ .SetDontShowChildren(true)
+ .SetHideItemNames(true)
+ .SetShowMembersOneLiner(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false),
+ lldb_private::formatters::BlockPointerSummaryProvider,
+ "block pointer summary provider"));
+ if (valobj.GetCompilerType().IsBlockPointerType()) {
+ return formatter_sp;
+ }
+ return nullptr;
+ });
+ });
+
+ return g_formatters;
+}
+
+HardcodedFormatters::HardcodedSyntheticFinder
+CPlusPlusLanguage::GetHardcodedSynthetics() {
+ static llvm::once_flag g_initialize;
+ static ConstString g_vectortypes("VectorTypes");
+ static HardcodedFormatters::HardcodedSyntheticFinder g_formatters;
+
+ llvm::call_once(g_initialize, []() -> void {
+ g_formatters.push_back([](lldb_private::ValueObject &valobj,
+ lldb::DynamicValueType, FormatManager &fmt_mgr)
+ -> SyntheticChildren::SharedPointer {
+ static CXXSyntheticChildren::SharedPointer formatter_sp(
+ new CXXSyntheticChildren(
+ SyntheticChildren::Flags()
+ .SetCascades(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(true)
+ .SetNonCacheable(true),
+ "vector_type synthetic children",
+ lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
+ if (valobj.GetCompilerType().IsVectorType()) {
+ if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled())
+ return formatter_sp;
+ }
+ return nullptr;
+ });
+ g_formatters.push_back([](lldb_private::ValueObject &valobj,
+ lldb::DynamicValueType, FormatManager &fmt_mgr)
+ -> SyntheticChildren::SharedPointer {
+ static CXXSyntheticChildren::SharedPointer formatter_sp(
+ new CXXSyntheticChildren(
+ SyntheticChildren::Flags()
+ .SetCascades(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(true)
+ .SetNonCacheable(true),
+ "block pointer synthetic children",
+ lldb_private::formatters::BlockPointerSyntheticFrontEndCreator));
+ if (valobj.GetCompilerType().IsBlockPointerType()) {
+ return formatter_sp;
+ }
+ return nullptr;
+ });
+ });
+
+ return g_formatters;
+}
+
+bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) {
+ if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) ||
+ !valobj.IsPointerType())
+ return false;
+ bool canReadValue = true;
+ bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
+ return canReadValue && isZero;
+}
+
+bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c",
+ ".h", ".hh", ".hpp", ".hxx", ".h++"};
+ for (auto suffix : suffixes) {
+ if (file_path.ends_with_insensitive(suffix))
+ return true;
+ }
+
+ // Check if we're in a STL path (where the files usually have no extension
+ // that we could check for.
+ return file_path.contains("/usr/include/c++/");
+}
+
+bool CPlusPlusLanguage::GetFunctionDisplayName(
+ const SymbolContext *sc, const ExecutionContext *exe_ctx,
+ FunctionNameRepresentation representation, Stream &s) {
+ switch (representation) {
+ case FunctionNameRepresentation::eNameWithArgs: {
+ // Print the function name with arguments in it
+ if (sc->function) {
+ ExecutionContextScope *exe_scope =
+ exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr;
+ const char *cstr = sc->function->GetName().AsCString(nullptr);
+ if (cstr) {
+ const InlineFunctionInfo *inline_info = nullptr;
+ VariableListSP variable_list_sp;
+ bool get_function_vars = true;
+ if (sc->block) {
+ Block *inline_block = sc->block->GetContainingInlinedBlock();
+
+ if (inline_block) {
+ get_function_vars = false;
+ inline_info = inline_block->GetInlinedFunctionInfo();
+ if (inline_info)
+ variable_list_sp = inline_block->GetBlockVariableList(true);
+ }
+ }
+
+ if (get_function_vars) {
+ variable_list_sp =
+ sc->function->GetBlock(true).GetBlockVariableList(true);
+ }
+
+ if (inline_info) {
+ s.PutCString(cstr);
+ s.PutCString(" [inlined] ");
+ cstr = inline_info->GetName().GetCString();
+ }
+
+ VariableList args;
+ if (variable_list_sp)
+ variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument,
+ args);
+ if (args.GetSize() > 0) {
+ if (!PrettyPrintFunctionNameWithArgs(s, cstr, exe_scope, args))
+ return false;
+ } else {
+ s.PutCString(cstr);
+ }
+ return true;
+ }
+ } else if (sc->symbol) {
+ const char *cstr = sc->symbol->GetName().AsCString(nullptr);
+ if (cstr) {
+ s.PutCString(cstr);
+ return true;
+ }
+ }
+ } break;
+ default:
+ return false;
+ }
+
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
new file mode 100644
index 000000000000..623d481bf117
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -0,0 +1,178 @@
+//===-- CPlusPlusLanguage.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSLANGUAGE_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSLANGUAGE_H
+
+#include <set>
+#include <vector>
+
+#include "llvm/ADT/StringRef.h"
+
+#include "Plugins/Language/ClangCommon/ClangHighlighter.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class CPlusPlusLanguage : public Language {
+ ClangHighlighter m_highlighter;
+
+public:
+ class MethodName {
+ public:
+ MethodName()
+ : m_full(), m_basename(), m_context(), m_arguments(), m_qualifiers() {}
+
+ MethodName(ConstString s)
+ : m_full(s), m_basename(), m_context(), m_arguments(), m_qualifiers(),
+ m_parsed(false), m_parse_error(false) {}
+
+ void Clear();
+
+ bool IsValid() {
+ if (!m_parsed)
+ Parse();
+ if (m_parse_error)
+ return false;
+ return (bool)m_full;
+ }
+
+ ConstString GetFullName() const { return m_full; }
+
+ std::string GetScopeQualifiedName();
+
+ llvm::StringRef GetBasename();
+
+ llvm::StringRef GetContext();
+
+ llvm::StringRef GetArguments();
+
+ llvm::StringRef GetQualifiers();
+
+ /// Returns the methods return-type.
+ ///
+ /// Currently returns an empty llvm::StringRef
+ /// if the return-type is a function pointer.
+ llvm::StringRef GetReturnType();
+
+ bool ContainsPath(llvm::StringRef path);
+
+ private:
+ /// Returns the Basename of this method without a template parameter
+ /// list, if any.
+ ///
+ // Examples:
+ //
+ // +--------------------------------+---------+
+ // | MethodName | Returns |
+ // +--------------------------------+---------+
+ // | void func() | func |
+ // | void func<int>() | func |
+ // | void func<std::vector<int>>() | func |
+ // +--------------------------------+---------+
+ llvm::StringRef GetBasenameNoTemplateParameters();
+
+ protected:
+ void Parse();
+ bool TrySimplifiedParse();
+
+ ConstString m_full; // Full name:
+ // "size_t lldb::SBTarget::GetBreakpointAtIndex(unsigned
+ // int) const"
+ llvm::StringRef m_basename; // Basename: "GetBreakpointAtIndex"
+ llvm::StringRef m_context; // Decl context: "lldb::SBTarget"
+ llvm::StringRef m_arguments; // Arguments: "(unsigned int)"
+ llvm::StringRef m_qualifiers; // Qualifiers: "const"
+ llvm::StringRef m_return_type; // Return type: "size_t"
+ bool m_parsed = false;
+ bool m_parse_error = false;
+ };
+
+ CPlusPlusLanguage() = default;
+
+ ~CPlusPlusLanguage() override = default;
+
+ lldb::LanguageType GetLanguageType() const override {
+ return lldb::eLanguageTypeC_plus_plus;
+ }
+
+ llvm::StringRef GetUserEntryPointName() const override { return "main"; }
+
+ std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
+ lldb::TypeCategoryImplSP GetFormatters() override;
+
+ HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries() override;
+
+ HardcodedFormatters::HardcodedSyntheticFinder
+ GetHardcodedSynthetics() override;
+
+ bool IsNilReference(ValueObject &valobj) override;
+
+ llvm::StringRef GetNilReferenceSummaryString() override { return "nullptr"; }
+
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
+ const Highlighter *GetHighlighter() const override { return &m_highlighter; }
+
+ // Static Functions
+ static void Initialize();
+
+ static void Terminate();
+
+ static lldb_private::Language *CreateInstance(lldb::LanguageType language);
+
+ static llvm::StringRef GetPluginNameStatic() { return "cplusplus"; }
+
+ bool SymbolNameFitsToLanguage(Mangled mangled) const override;
+
+ bool DemangledNameContainsPath(llvm::StringRef path,
+ ConstString demangled) const override;
+
+ ConstString
+ GetDemangledFunctionNameWithoutArguments(Mangled mangled) const override;
+
+ bool GetFunctionDisplayName(const SymbolContext *sc,
+ const ExecutionContext *exe_ctx,
+ FunctionNameRepresentation representation,
+ Stream &s) override;
+
+ static bool IsCPPMangledName(llvm::StringRef name);
+
+ // Extract C++ context and identifier from a string using heuristic matching
+ // (as opposed to
+ // CPlusPlusLanguage::MethodName which has to have a fully qualified C++ name
+ // with parens and arguments.
+ // If the name is a lone C identifier (e.g. C) or a qualified C identifier
+ // (e.g. A::B::C) it will return true,
+ // and identifier will be the identifier (C and C respectively) and the
+ // context will be "" and "A::B" respectively.
+ // If the name fails the heuristic matching for a qualified or unqualified
+ // C/C++ identifier, then it will return false
+ // and identifier and context will be unchanged.
+
+ static bool ExtractContextAndIdentifier(const char *name,
+ llvm::StringRef &context,
+ llvm::StringRef &identifier);
+
+ std::vector<ConstString>
+ GenerateAlternateFunctionManglings(const ConstString mangled) const override;
+
+ ConstString FindBestAlternateFunctionMangledName(
+ const Mangled mangled, const SymbolContext &sym_ctx) const override;
+
+ llvm::StringRef GetInstanceVariableName() override { return "this"; }
+
+ // PluginInterface protocol
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSLANGUAGE_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
new file mode 100644
index 000000000000..d8c095d6edeb
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
@@ -0,0 +1,785 @@
+//===-- CPlusPlusNameParser.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CPlusPlusNameParser.h"
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/TokenKinds.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Threading.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction;
+using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName;
+namespace tok = clang::tok;
+
+std::optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() {
+ m_next_token_index = 0;
+ std::optional<ParsedFunction> result(std::nullopt);
+
+ // Try to parse the name as function without a return type specified e.g.
+ // main(int, char*[])
+ {
+ Bookmark start_position = SetBookmark();
+ result = ParseFunctionImpl(false);
+ if (result && !HasMoreTokens())
+ return result;
+ }
+
+ // Try to parse the name as function with function pointer return type e.g.
+ // void (*get_func(const char*))()
+ result = ParseFuncPtr(true);
+ if (result)
+ return result;
+
+ // Finally try to parse the name as a function with non-function return type
+ // e.g. int main(int, char*[])
+ result = ParseFunctionImpl(true);
+ if (HasMoreTokens())
+ return std::nullopt;
+ return result;
+}
+
+std::optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() {
+ m_next_token_index = 0;
+ std::optional<ParsedNameRanges> name_ranges = ParseFullNameImpl();
+ if (!name_ranges)
+ return std::nullopt;
+ if (HasMoreTokens())
+ return std::nullopt;
+ ParsedName result;
+ result.basename = GetTextForRange(name_ranges->basename_range);
+ result.context = GetTextForRange(name_ranges->context_range);
+ return result;
+}
+
+bool CPlusPlusNameParser::HasMoreTokens() {
+ return m_next_token_index < m_tokens.size();
+}
+
+void CPlusPlusNameParser::Advance() { ++m_next_token_index; }
+
+void CPlusPlusNameParser::TakeBack() { --m_next_token_index; }
+
+bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) {
+ if (!HasMoreTokens())
+ return false;
+
+ if (!Peek().is(kind))
+ return false;
+
+ Advance();
+ return true;
+}
+
+template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
+ if (!HasMoreTokens())
+ return false;
+
+ if (!Peek().isOneOf(kinds...))
+ return false;
+
+ Advance();
+ return true;
+}
+
+CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() {
+ return Bookmark(m_next_token_index);
+}
+
+size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; }
+
+clang::Token &CPlusPlusNameParser::Peek() {
+ assert(HasMoreTokens());
+ return m_tokens[m_next_token_index];
+}
+
+std::optional<ParsedFunction>
+CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
+ Bookmark start_position = SetBookmark();
+
+ ParsedFunction result;
+ if (expect_return_type) {
+ size_t return_start = GetCurrentPosition();
+ // Consume return type if it's expected.
+ if (!ConsumeToken(tok::kw_auto) && !ConsumeTypename())
+ return std::nullopt;
+
+ size_t return_end = GetCurrentPosition();
+ result.return_type = GetTextForRange(Range(return_start, return_end));
+ }
+
+ auto maybe_name = ParseFullNameImpl();
+ if (!maybe_name) {
+ return std::nullopt;
+ }
+
+ size_t argument_start = GetCurrentPosition();
+ if (!ConsumeArguments()) {
+ return std::nullopt;
+ }
+
+ size_t qualifiers_start = GetCurrentPosition();
+ SkipFunctionQualifiers();
+ size_t end_position = GetCurrentPosition();
+
+ result.name.basename = GetTextForRange(maybe_name->basename_range);
+ result.name.context = GetTextForRange(maybe_name->context_range);
+ result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
+ result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position));
+ start_position.Remove();
+ return result;
+}
+
+std::optional<ParsedFunction>
+CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
+ // This function parses a function definition
+ // that returns a pointer type.
+ // E.g., double (*(*func(long))(int))(float)
+
+ // Step 1:
+ // Remove the return type of the innermost
+ // function pointer type.
+ //
+ // Leaves us with:
+ // (*(*func(long))(int))(float)
+ Bookmark start_position = SetBookmark();
+ if (expect_return_type) {
+ // Consume return type.
+ if (!ConsumeTypename())
+ return std::nullopt;
+ }
+
+ // Step 2:
+ //
+ // Skip a pointer and parenthesis pair.
+ //
+ // Leaves us with:
+ // (*func(long))(int))(float)
+ if (!ConsumeToken(tok::l_paren))
+ return std::nullopt;
+ if (!ConsumePtrsAndRefs())
+ return std::nullopt;
+
+ // Step 3:
+ //
+ // Consume inner function name. This will fail unless
+ // we stripped all the pointers on the left hand side
+ // of the function name.
+ {
+ Bookmark before_inner_function_pos = SetBookmark();
+ auto maybe_inner_function_name = ParseFunctionImpl(false);
+ if (maybe_inner_function_name)
+ if (ConsumeToken(tok::r_paren))
+ if (ConsumeArguments()) {
+ SkipFunctionQualifiers();
+ start_position.Remove();
+ before_inner_function_pos.Remove();
+ return maybe_inner_function_name;
+ }
+ }
+
+ // Step 4:
+ //
+ // Parse the remaining string as a function pointer again.
+ // This time don't consume the inner-most typename since
+ // we're left with pointers only. This will strip another
+ // layer of pointers until we're left with the innermost
+ // function name/argument. I.e., func(long))(int))(float)
+ //
+ // Once we successfully stripped all pointers and gotten
+ // the innermost function name from ParseFunctionImpl above,
+ // we consume a single ')' and the arguments '(...)' that follows.
+ //
+ // Leaves us with:
+ // )(float)
+ //
+ // This is the remnant of the outer function pointers' arguments.
+ // Unwinding the recursive calls will remove the remaining
+ // arguments.
+ auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
+ if (maybe_inner_function_ptr_name)
+ if (ConsumeToken(tok::r_paren))
+ if (ConsumeArguments()) {
+ SkipFunctionQualifiers();
+ start_position.Remove();
+ return maybe_inner_function_ptr_name;
+ }
+
+ return std::nullopt;
+}
+
+bool CPlusPlusNameParser::ConsumeArguments() {
+ return ConsumeBrackets(tok::l_paren, tok::r_paren);
+}
+
+bool CPlusPlusNameParser::ConsumeTemplateArgs() {
+ Bookmark start_position = SetBookmark();
+ if (!HasMoreTokens() || Peek().getKind() != tok::less)
+ return false;
+ Advance();
+
+ // Consuming template arguments is a bit trickier than consuming function
+ // arguments, because '<' '>' brackets are not always trivially balanced. In
+ // some rare cases tokens '<' and '>' can appear inside template arguments as
+ // arithmetic or shift operators not as template brackets. Examples:
+ // std::enable_if<(10u)<(64), bool>
+ // f<A<operator<(X,Y)::Subclass>>
+ // Good thing that compiler makes sure that really ambiguous cases of '>'
+ // usage should be enclosed within '()' brackets.
+ int template_counter = 1;
+ bool can_open_template = false;
+ while (HasMoreTokens() && template_counter > 0) {
+ tok::TokenKind kind = Peek().getKind();
+ switch (kind) {
+ case tok::greatergreater:
+ template_counter -= 2;
+ can_open_template = false;
+ Advance();
+ break;
+ case tok::greater:
+ --template_counter;
+ can_open_template = false;
+ Advance();
+ break;
+ case tok::less:
+ // '<' is an attempt to open a subteamplte
+ // check if parser is at the point where it's actually possible,
+ // otherwise it's just a part of an expression like 'sizeof(T)<(10)'. No
+ // need to do the same for '>' because compiler actually makes sure that
+ // '>' always surrounded by brackets to avoid ambiguity.
+ if (can_open_template)
+ ++template_counter;
+ can_open_template = false;
+ Advance();
+ break;
+ case tok::kw_operator: // C++ operator overloading.
+ if (!ConsumeOperator())
+ return false;
+ can_open_template = true;
+ break;
+ case tok::raw_identifier:
+ can_open_template = true;
+ Advance();
+ break;
+ case tok::l_square:
+ // Handle templates tagged with an ABI tag.
+ // An example demangled/prettified version is:
+ // func[abi:tag1][abi:tag2]<type[abi:tag3]>(int)
+ if (ConsumeAbiTag())
+ can_open_template = true;
+ else if (ConsumeBrackets(tok::l_square, tok::r_square))
+ can_open_template = false;
+ else
+ return false;
+ break;
+ case tok::l_paren:
+ if (!ConsumeArguments())
+ return false;
+ can_open_template = false;
+ break;
+ default:
+ can_open_template = false;
+ Advance();
+ break;
+ }
+ }
+
+ if (template_counter != 0) {
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeAbiTag() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::l_square))
+ return false;
+
+ if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
+ Peek().getRawIdentifier() == "abi")
+ Advance();
+ else
+ return false;
+
+ if (!ConsumeToken(tok::colon))
+ return false;
+
+ // Consume the actual tag string (and allow some special characters)
+ while (ConsumeToken(tok::raw_identifier, tok::comma, tok::period,
+ tok::numeric_constant))
+ ;
+
+ if (!ConsumeToken(tok::r_square))
+ return false;
+
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeAnonymousNamespace() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::l_paren)) {
+ return false;
+ }
+ constexpr llvm::StringLiteral g_anonymous("anonymous");
+ if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
+ Peek().getRawIdentifier() == g_anonymous) {
+ Advance();
+ } else {
+ return false;
+ }
+
+ if (!ConsumeToken(tok::kw_namespace)) {
+ return false;
+ }
+
+ if (!ConsumeToken(tok::r_paren)) {
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeLambda() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::l_brace)) {
+ return false;
+ }
+ constexpr llvm::StringLiteral g_lambda("lambda");
+ if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
+ Peek().getRawIdentifier() == g_lambda) {
+ // Put the matched brace back so we can use ConsumeBrackets
+ TakeBack();
+ } else {
+ return false;
+ }
+
+ if (!ConsumeBrackets(tok::l_brace, tok::r_brace)) {
+ return false;
+ }
+
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left,
+ tok::TokenKind right) {
+ Bookmark start_position = SetBookmark();
+ if (!HasMoreTokens() || Peek().getKind() != left)
+ return false;
+ Advance();
+
+ int counter = 1;
+ while (HasMoreTokens() && counter > 0) {
+ tok::TokenKind kind = Peek().getKind();
+ if (kind == right)
+ --counter;
+ else if (kind == left)
+ ++counter;
+ Advance();
+ }
+
+ assert(counter >= 0);
+ if (counter > 0) {
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeOperator() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::kw_operator))
+ return false;
+
+ if (!HasMoreTokens()) {
+ return false;
+ }
+
+ const auto &token = Peek();
+
+ // When clang generates debug info it adds template parameters to names.
+ // Since clang doesn't add a space between the name and the template parameter
+ // in some cases we are not generating valid C++ names e.g.:
+ //
+ // operator<<A::B>
+ //
+ // In some of these cases we will not parse them correctly. This fixes the
+ // issue by detecting this case and inserting tok::less in place of
+ // tok::lessless and returning successfully that we consumed the operator.
+ if (token.getKind() == tok::lessless) {
+ // Make sure we have more tokens before attempting to look ahead one more.
+ if (m_next_token_index + 1 < m_tokens.size()) {
+ // Look ahead two tokens.
+ clang::Token n_token = m_tokens[m_next_token_index + 1];
+ // If we find ( or < then this is indeed operator<< no need for fix.
+ if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) {
+ clang::Token tmp_tok;
+ tmp_tok.startToken();
+ tmp_tok.setLength(1);
+ tmp_tok.setLocation(token.getLocation().getLocWithOffset(1));
+ tmp_tok.setKind(tok::less);
+
+ m_tokens[m_next_token_index] = tmp_tok;
+
+ start_position.Remove();
+ return true;
+ }
+ }
+ }
+
+ switch (token.getKind()) {
+ case tok::kw_new:
+ case tok::kw_delete:
+ // This is 'new' or 'delete' operators.
+ Advance();
+ // Check for array new/delete.
+ if (HasMoreTokens() && Peek().is(tok::l_square)) {
+ // Consume the '[' and ']'.
+ if (!ConsumeBrackets(tok::l_square, tok::r_square))
+ return false;
+ }
+ break;
+
+#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
+ case tok::Token: \
+ Advance(); \
+ break;
+#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+#undef OVERLOADED_OPERATOR
+#undef OVERLOADED_OPERATOR_MULTI
+
+ case tok::l_paren:
+ // Call operator consume '(' ... ')'.
+ if (ConsumeBrackets(tok::l_paren, tok::r_paren))
+ break;
+ return false;
+
+ case tok::l_square:
+ // This is a [] operator.
+ // Consume the '[' and ']'.
+ if (ConsumeBrackets(tok::l_square, tok::r_square))
+ break;
+ return false;
+
+ default:
+ // This might be a cast operator.
+ if (ConsumeTypename())
+ break;
+ return false;
+ }
+ start_position.Remove();
+ return true;
+}
+
+void CPlusPlusNameParser::SkipTypeQualifiers() {
+ while (ConsumeToken(tok::kw_const, tok::kw_volatile))
+ ;
+}
+
+void CPlusPlusNameParser::SkipFunctionQualifiers() {
+ while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp))
+ ;
+}
+
+bool CPlusPlusNameParser::ConsumeBuiltinType() {
+ bool result = false;
+ bool continue_parsing = true;
+ // Built-in types can be made of a few keywords like 'unsigned long long
+ // int'. This function consumes all built-in type keywords without checking
+ // if they make sense like 'unsigned char void'.
+ while (continue_parsing && HasMoreTokens()) {
+ switch (Peek().getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw___float128:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ result = true;
+ Advance();
+ break;
+ default:
+ continue_parsing = false;
+ break;
+ }
+ }
+ return result;
+}
+
+void CPlusPlusNameParser::SkipPtrsAndRefs() {
+ // Ignoring result.
+ ConsumePtrsAndRefs();
+}
+
+bool CPlusPlusNameParser::ConsumePtrsAndRefs() {
+ bool found = false;
+ SkipTypeQualifiers();
+ while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const,
+ tok::kw_volatile)) {
+ found = true;
+ SkipTypeQualifiers();
+ }
+ return found;
+}
+
+bool CPlusPlusNameParser::ConsumeDecltype() {
+ Bookmark start_position = SetBookmark();
+ if (!ConsumeToken(tok::kw_decltype))
+ return false;
+
+ if (!ConsumeArguments())
+ return false;
+
+ start_position.Remove();
+ return true;
+}
+
+bool CPlusPlusNameParser::ConsumeTypename() {
+ Bookmark start_position = SetBookmark();
+ SkipTypeQualifiers();
+ if (!ConsumeBuiltinType() && !ConsumeDecltype()) {
+ if (!ParseFullNameImpl())
+ return false;
+ }
+ SkipPtrsAndRefs();
+ start_position.Remove();
+ return true;
+}
+
+std::optional<CPlusPlusNameParser::ParsedNameRanges>
+CPlusPlusNameParser::ParseFullNameImpl() {
+ // Name parsing state machine.
+ enum class State {
+ Beginning, // start of the name
+ AfterTwoColons, // right after ::
+ AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+)
+ AfterTemplate, // right after template brackets (<something>)
+ AfterOperator, // right after name of C++ operator
+ };
+
+ Bookmark start_position = SetBookmark();
+ State state = State::Beginning;
+ bool continue_parsing = true;
+ std::optional<size_t> last_coloncolon_position;
+
+ while (continue_parsing && HasMoreTokens()) {
+ const auto &token = Peek();
+ switch (token.getKind()) {
+ case tok::raw_identifier: // Just a name.
+ if (state != State::Beginning && state != State::AfterTwoColons) {
+ continue_parsing = false;
+ break;
+ }
+ Advance();
+ state = State::AfterIdentifier;
+ break;
+ case tok::l_square: {
+ // Handles types or functions that were tagged
+ // with, e.g.,
+ // [[gnu::abi_tag("tag1","tag2")]] func()
+ // and demangled/prettified into:
+ // func[abi:tag1][abi:tag2]()
+
+ // ABI tags only appear after a method or type name
+ const bool valid_state =
+ state == State::AfterIdentifier || state == State::AfterOperator;
+ if (!valid_state || !ConsumeAbiTag()) {
+ continue_parsing = false;
+ }
+
+ break;
+ }
+ case tok::l_paren: {
+ if (state == State::Beginning || state == State::AfterTwoColons) {
+ // (anonymous namespace)
+ if (ConsumeAnonymousNamespace()) {
+ state = State::AfterIdentifier;
+ break;
+ }
+ }
+
+ // Type declared inside a function 'func()::Type'
+ if (state != State::AfterIdentifier && state != State::AfterTemplate &&
+ state != State::AfterOperator) {
+ continue_parsing = false;
+ break;
+ }
+ Bookmark l_paren_position = SetBookmark();
+ // Consume the '(' ... ') [const]'.
+ if (!ConsumeArguments()) {
+ continue_parsing = false;
+ break;
+ }
+ SkipFunctionQualifiers();
+
+ // Consume '::'
+ size_t coloncolon_position = GetCurrentPosition();
+ if (!ConsumeToken(tok::coloncolon)) {
+ continue_parsing = false;
+ break;
+ }
+ l_paren_position.Remove();
+ last_coloncolon_position = coloncolon_position;
+ state = State::AfterTwoColons;
+ break;
+ }
+ case tok::l_brace:
+ if (state == State::Beginning || state == State::AfterTwoColons) {
+ if (ConsumeLambda()) {
+ state = State::AfterIdentifier;
+ break;
+ }
+ }
+ continue_parsing = false;
+ break;
+ case tok::coloncolon: // Type nesting delimiter.
+ if (state != State::Beginning && state != State::AfterIdentifier &&
+ state != State::AfterTemplate) {
+ continue_parsing = false;
+ break;
+ }
+ last_coloncolon_position = GetCurrentPosition();
+ Advance();
+ state = State::AfterTwoColons;
+ break;
+ case tok::less: // Template brackets.
+ if (state != State::AfterIdentifier && state != State::AfterOperator) {
+ continue_parsing = false;
+ break;
+ }
+ if (!ConsumeTemplateArgs()) {
+ continue_parsing = false;
+ break;
+ }
+ state = State::AfterTemplate;
+ break;
+ case tok::kw_operator: // C++ operator overloading.
+ if (state != State::Beginning && state != State::AfterTwoColons) {
+ continue_parsing = false;
+ break;
+ }
+ if (!ConsumeOperator()) {
+ continue_parsing = false;
+ break;
+ }
+ state = State::AfterOperator;
+ break;
+ case tok::tilde: // Destructor.
+ if (state != State::Beginning && state != State::AfterTwoColons) {
+ continue_parsing = false;
+ break;
+ }
+ Advance();
+ if (ConsumeToken(tok::raw_identifier)) {
+ state = State::AfterIdentifier;
+ } else {
+ TakeBack();
+ continue_parsing = false;
+ }
+ break;
+ default:
+ continue_parsing = false;
+ break;
+ }
+ }
+
+ if (state == State::AfterIdentifier || state == State::AfterOperator ||
+ state == State::AfterTemplate) {
+ ParsedNameRanges result;
+ if (last_coloncolon_position) {
+ result.context_range =
+ Range(start_position.GetSavedPosition(), *last_coloncolon_position);
+ result.basename_range =
+ Range(*last_coloncolon_position + 1, GetCurrentPosition());
+ } else {
+ result.basename_range =
+ Range(start_position.GetSavedPosition(), GetCurrentPosition());
+ }
+ start_position.Remove();
+ return result;
+ } else {
+ return std::nullopt;
+ }
+}
+
+llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
+ if (range.empty())
+ return llvm::StringRef();
+ assert(range.begin_index < range.end_index);
+ assert(range.begin_index < m_tokens.size());
+ assert(range.end_index <= m_tokens.size());
+ clang::Token &first_token = m_tokens[range.begin_index];
+ clang::Token &last_token = m_tokens[range.end_index - 1];
+ clang::SourceLocation start_loc = first_token.getLocation();
+ clang::SourceLocation end_loc = last_token.getLocation();
+ unsigned start_pos = start_loc.getRawEncoding();
+ unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength();
+ return m_text.take_front(end_pos).drop_front(start_pos);
+}
+
+static const clang::LangOptions &GetLangOptions() {
+ static clang::LangOptions g_options;
+ static llvm::once_flag g_once_flag;
+ llvm::call_once(g_once_flag, []() {
+ g_options.LineComment = true;
+ g_options.C99 = true;
+ g_options.C11 = true;
+ g_options.CPlusPlus = true;
+ g_options.CPlusPlus11 = true;
+ g_options.CPlusPlus14 = true;
+ g_options.CPlusPlus17 = true;
+ g_options.CPlusPlus20 = true;
+ });
+ return g_options;
+}
+
+static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
+ static llvm::StringMap<tok::TokenKind> g_map{
+#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
+#include "clang/Basic/TokenKinds.def"
+#undef KEYWORD
+ };
+ return g_map;
+}
+
+void CPlusPlusNameParser::ExtractTokens() {
+ if (m_text.empty())
+ return;
+ clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
+ m_text.data(), m_text.data() + m_text.size());
+ const auto &kw_map = GetKeywordsMap();
+ clang::Token token;
+ for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
+ lexer.LexFromRawLexer(token)) {
+ if (token.is(clang::tok::raw_identifier)) {
+ auto it = kw_map.find(token.getRawIdentifier());
+ if (it != kw_map.end()) {
+ token.setKind(it->getValue());
+ }
+ }
+
+ m_tokens.push_back(token);
+ }
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
new file mode 100644
index 000000000000..326efb7a8be0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
@@ -0,0 +1,188 @@
+//===-- CPlusPlusNameParser.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H
+
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-private.h"
+#include <optional>
+
+namespace lldb_private {
+
+// Helps to validate and obtain various parts of C++ definitions.
+class CPlusPlusNameParser {
+public:
+ CPlusPlusNameParser(llvm::StringRef text) : m_text(text) { ExtractTokens(); }
+
+ struct ParsedName {
+ llvm::StringRef basename;
+ llvm::StringRef context;
+ };
+
+ struct ParsedFunction {
+ ParsedName name;
+ llvm::StringRef arguments;
+ llvm::StringRef qualifiers;
+ llvm::StringRef return_type;
+ };
+
+ // Treats given text as a function definition and parses it.
+ // Function definition might or might not have a return type and this should
+ // change parsing result.
+ // Examples:
+ // main(int, chat const*)
+ // T fun(int, bool)
+ // std::vector<int>::push_back(int)
+ // int& map<int, pair<short, int>>::operator[](short) const
+ // int (*get_function(const chat *))()
+ std::optional<ParsedFunction> ParseAsFunctionDefinition();
+
+ // Treats given text as a potentially nested name of C++ entity (function,
+ // class, field) and parses it.
+ // Examples:
+ // main
+ // fun
+ // std::vector<int>::push_back
+ // map<int, pair<short, int>>::operator[]
+ // func<C>(int, C&)::nested_class::method
+ std::optional<ParsedName> ParseAsFullName();
+
+private:
+ // A C++ definition to parse.
+ llvm::StringRef m_text;
+ // Tokens extracted from m_text.
+ llvm::SmallVector<clang::Token, 30> m_tokens;
+ // Index of the next token to look at from m_tokens.
+ size_t m_next_token_index = 0;
+
+ // Range of tokens saved in m_next_token_index.
+ struct Range {
+ size_t begin_index = 0;
+ size_t end_index = 0;
+
+ Range() = default;
+ Range(size_t begin, size_t end) : begin_index(begin), end_index(end) {
+ assert(end >= begin);
+ }
+
+ size_t size() const { return end_index - begin_index; }
+
+ bool empty() const { return size() == 0; }
+ };
+
+ struct ParsedNameRanges {
+ Range basename_range;
+ Range context_range;
+ };
+
+ // Bookmark automatically restores parsing position (m_next_token_index)
+ // when destructed unless it's manually removed with Remove().
+ class Bookmark {
+ public:
+ Bookmark(size_t &position)
+ : m_position(position), m_position_value(position) {}
+ Bookmark(const Bookmark &) = delete;
+ Bookmark(Bookmark &&b)
+ : m_position(b.m_position), m_position_value(b.m_position_value),
+ m_restore(b.m_restore) {
+ b.Remove();
+ }
+ Bookmark &operator=(Bookmark &&) = delete;
+ Bookmark &operator=(const Bookmark &) = delete;
+
+ void Remove() { m_restore = false; }
+ size_t GetSavedPosition() { return m_position_value; }
+ ~Bookmark() {
+ if (m_restore) {
+ m_position = m_position_value;
+ }
+ }
+
+ private:
+ size_t &m_position;
+ size_t m_position_value;
+ bool m_restore = true;
+ };
+
+ bool HasMoreTokens();
+ void Advance();
+ void TakeBack();
+ bool ConsumeToken(clang::tok::TokenKind kind);
+
+ template <typename... Ts> bool ConsumeToken(Ts... kinds);
+ Bookmark SetBookmark();
+ size_t GetCurrentPosition();
+ clang::Token &Peek();
+ bool ConsumeBrackets(clang::tok::TokenKind left, clang::tok::TokenKind right);
+
+ std::optional<ParsedFunction> ParseFunctionImpl(bool expect_return_type);
+
+ // Parses functions returning function pointers 'string (*f(int x))(float y)'
+ std::optional<ParsedFunction> ParseFuncPtr(bool expect_return_type);
+
+ // Consumes function arguments enclosed within '(' ... ')'
+ bool ConsumeArguments();
+
+ // Consumes template arguments enclosed within '<' ... '>'
+ bool ConsumeTemplateArgs();
+
+ // Consumes '(anonymous namespace)'
+ bool ConsumeAnonymousNamespace();
+
+ // Consumes '{lambda ...}'
+ bool ConsumeLambda();
+
+ // Consumes operator declaration like 'operator *' or 'operator delete []'
+ bool ConsumeOperator();
+
+ // Skips 'const' and 'volatile'
+ void SkipTypeQualifiers();
+
+ // Skips 'const', 'volatile', '&', '&&' in the end of the function.
+ void SkipFunctionQualifiers();
+
+ // Consumes built-in types like 'int' or 'unsigned long long int'
+ bool ConsumeBuiltinType();
+
+ // Consumes types defined via decltype keyword.
+ bool ConsumeDecltype();
+
+ // Skips 'const' and 'volatile'
+ void SkipPtrsAndRefs();
+
+ // Consumes things like 'const * const &'
+ bool ConsumePtrsAndRefs();
+
+ // Consumes full type name like 'Namespace::Class<int>::Method()::InnerClass'
+ bool ConsumeTypename();
+
+ /// Consumes ABI tags enclosed within '[abi:' ... ']'
+ ///
+ /// Since there is no restriction on what the ABI tag
+ /// string may contain, this API supports parsing a small
+ /// set of special characters.
+ ///
+ /// The following regex describes the set of supported characters:
+ /// [A-Za-z,.\s\d]+
+ bool ConsumeAbiTag();
+
+ std::optional<ParsedNameRanges> ParseFullNameImpl();
+ llvm::StringRef GetTextForRange(const Range &range);
+
+ // Populate m_tokens by calling clang lexer on m_text.
+ void ExtractTokens();
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp
new file mode 100644
index 000000000000..5e63d1d7b214
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp
@@ -0,0 +1,227 @@
+//===-- Coroutines.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Coroutines.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+static lldb::addr_t GetCoroFramePtrFromHandle(ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return LLDB_INVALID_ADDRESS;
+
+ // We expect a single pointer in the `coroutine_handle` class.
+ // We don't care about its name.
+ if (valobj_sp->GetNumChildrenIgnoringErrors() != 1)
+ return LLDB_INVALID_ADDRESS;
+ ValueObjectSP ptr_sp(valobj_sp->GetChildAtIndex(0));
+ if (!ptr_sp)
+ return LLDB_INVALID_ADDRESS;
+ if (!ptr_sp->GetCompilerType().IsPointerType())
+ return LLDB_INVALID_ADDRESS;
+
+ AddressType addr_type;
+ lldb::addr_t frame_ptr_addr = ptr_sp->GetPointerValue(&addr_type);
+ if (!frame_ptr_addr || frame_ptr_addr == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+ lldbassert(addr_type == AddressType::eAddressTypeLoad);
+ if (addr_type != AddressType::eAddressTypeLoad)
+ return LLDB_INVALID_ADDRESS;
+
+ return frame_ptr_addr;
+}
+
+static Function *ExtractDestroyFunction(lldb::TargetSP target_sp,
+ lldb::addr_t frame_ptr_addr) {
+ lldb::ProcessSP process_sp = target_sp->GetProcessSP();
+ auto ptr_size = process_sp->GetAddressByteSize();
+
+ Status error;
+ auto destroy_func_ptr_addr = frame_ptr_addr + ptr_size;
+ lldb::addr_t destroy_func_addr =
+ process_sp->ReadPointerFromMemory(destroy_func_ptr_addr, error);
+ if (error.Fail())
+ return nullptr;
+
+ Address destroy_func_address;
+ if (!target_sp->ResolveLoadAddress(destroy_func_addr, destroy_func_address))
+ return nullptr;
+
+ return destroy_func_address.CalculateSymbolContextFunction();
+}
+
+static CompilerType InferPromiseType(Function &destroy_func) {
+ Block &block = destroy_func.GetBlock(true);
+ auto variable_list = block.GetBlockVariableList(true);
+
+ // clang generates an artificial `__promise` variable inside the
+ // `destroy` function. Look for it.
+ auto promise_var = variable_list->FindVariable(ConstString("__promise"));
+ if (!promise_var)
+ return {};
+ if (!promise_var->IsArtificial())
+ return {};
+
+ Type *promise_type = promise_var->GetType();
+ if (!promise_type)
+ return {};
+ return promise_type->GetForwardCompilerType();
+}
+
+bool lldb_private::formatters::StdlibCoroutineHandleSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ lldb::addr_t frame_ptr_addr =
+ GetCoroFramePtrFromHandle(valobj.GetNonSyntheticValue());
+ if (frame_ptr_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (frame_ptr_addr == 0) {
+ stream << "nullptr";
+ } else {
+ stream.Printf("coro frame = 0x%" PRIx64, frame_ptr_addr);
+ }
+
+ return true;
+}
+
+lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
+ StdlibCoroutineHandleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
+ ~StdlibCoroutineHandleSyntheticFrontEnd() = default;
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ StdlibCoroutineHandleSyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
+ return 0;
+
+ return m_promise_ptr_sp ? 3 : 2;
+}
+
+lldb::ValueObjectSP lldb_private::formatters::
+ StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ switch (idx) {
+ case 0:
+ return m_resume_ptr_sp;
+ case 1:
+ return m_destroy_ptr_sp;
+ case 2:
+ return m_promise_ptr_sp;
+ }
+ return lldb::ValueObjectSP();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() {
+ m_resume_ptr_sp.reset();
+ m_destroy_ptr_sp.reset();
+ m_promise_ptr_sp.reset();
+
+ ValueObjectSP valobj_sp = m_backend.GetNonSyntheticValue();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ lldb::addr_t frame_ptr_addr = GetCoroFramePtrFromHandle(valobj_sp);
+ if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS)
+ return lldb::ChildCacheState::eRefetch;
+
+ auto ts = valobj_sp->GetCompilerType().GetTypeSystem();
+ auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>();
+ if (!ast_ctx)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Create the `resume` and `destroy` children.
+ lldb::TargetSP target_sp = m_backend.GetTargetSP();
+ auto &exe_ctx = m_backend.GetExecutionContextRef();
+ lldb::ProcessSP process_sp = target_sp->GetProcessSP();
+ auto ptr_size = process_sp->GetAddressByteSize();
+ CompilerType void_type = ast_ctx->GetBasicType(lldb::eBasicTypeVoid);
+ CompilerType coro_func_type = ast_ctx->CreateFunctionType(
+ /*result_type=*/void_type, /*args=*/&void_type, /*num_args=*/1,
+ /*is_variadic=*/false, /*qualifiers=*/0);
+ CompilerType coro_func_ptr_type = coro_func_type.GetPointerType();
+ m_resume_ptr_sp = CreateValueObjectFromAddress(
+ "resume", frame_ptr_addr + 0 * ptr_size, exe_ctx, coro_func_ptr_type);
+ lldbassert(m_resume_ptr_sp);
+ m_destroy_ptr_sp = CreateValueObjectFromAddress(
+ "destroy", frame_ptr_addr + 1 * ptr_size, exe_ctx, coro_func_ptr_type);
+ lldbassert(m_destroy_ptr_sp);
+
+ // Get the `promise_type` from the template argument
+ CompilerType promise_type(
+ valobj_sp->GetCompilerType().GetTypeTemplateArgument(0));
+ if (!promise_type)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Try to infer the promise_type if it was type-erased
+ if (promise_type.IsVoidType()) {
+ if (Function *destroy_func =
+ ExtractDestroyFunction(target_sp, frame_ptr_addr)) {
+ if (CompilerType inferred_type = InferPromiseType(*destroy_func)) {
+ promise_type = inferred_type;
+ }
+ }
+ }
+
+ // If we don't know the promise type, we don't display the `promise` member.
+ // `CreateValueObjectFromAddress` below would fail for `void` types.
+ if (promise_type.IsVoidType()) {
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ // Add the `promise` member. We intentionally add `promise` as a pointer type
+ // instead of a value type, and don't automatically dereference this pointer.
+ // We do so to avoid potential very deep recursion in case there is a cycle
+ // formed between `std::coroutine_handle`s and their promises.
+ lldb::ValueObjectSP promise = CreateValueObjectFromAddress(
+ "promise", frame_ptr_addr + 2 * ptr_size, exe_ctx, promise_type);
+ Status error;
+ lldb::ValueObjectSP promisePtr = promise->AddressOf(error);
+ if (error.Success())
+ m_promise_ptr_sp = promisePtr->Clone(ConstString("promise"));
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t StdlibCoroutineHandleSyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ if (!m_resume_ptr_sp || !m_destroy_ptr_sp)
+ return UINT32_MAX;
+
+ if (name == ConstString("resume"))
+ return 0;
+ if (name == ConstString("destroy"))
+ return 1;
+ if (name == ConstString("promise_ptr") && m_promise_ptr_sp)
+ return 2;
+
+ return UINT32_MAX;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new StdlibCoroutineHandleSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h
new file mode 100644
index 000000000000..1d4bc65e2637
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h
@@ -0,0 +1,60 @@
+//===-- Coroutines.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_COROUTINES_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_COROUTINES_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+
+namespace formatters {
+
+/// Summary provider for `std::coroutine_handle<T>` from libc++, libstdc++ and
+/// MSVC STL.
+bool StdlibCoroutineHandleSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+/// Synthetic children frontend for `std::coroutine_handle<promise_type>` from
+/// libc++, libstdc++ and MSVC STL. Shows the compiler-generated `resume` and
+/// `destroy` function pointers as well as the `promise`, if the promise type
+/// is `promise_type != void`.
+class StdlibCoroutineHandleSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ StdlibCoroutineHandleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~StdlibCoroutineHandleSyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ lldb::ValueObjectSP m_resume_ptr_sp;
+ lldb::ValueObjectSP m_destroy_ptr_sp;
+ lldb::ValueObjectSP m_promise_ptr_sp;
+};
+
+SyntheticChildrenFrontEnd *
+StdlibCoroutineHandleSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_COROUTINES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
new file mode 100644
index 000000000000..6781c96210a4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp
@@ -0,0 +1,214 @@
+//===-- CxxStringTypes.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CxxStringTypes.h"
+
+#include "llvm/Support/ConvertUTF.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Host/Time.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include <algorithm>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+using StringElementType = StringPrinter::StringElementType;
+
+static constexpr std::pair<const char *, Format>
+getElementTraits(StringElementType ElemType) {
+ switch (ElemType) {
+ case StringElementType::UTF8:
+ return std::make_pair("u8", lldb::eFormatUnicode8);
+ case StringElementType::UTF16:
+ return std::make_pair("u", lldb::eFormatUnicode16);
+ case StringElementType::UTF32:
+ return std::make_pair("U", lldb::eFormatUnicode32);
+ default:
+ return std::make_pair(nullptr, lldb::eFormatInvalid);
+ }
+}
+
+template <StringElementType ElemType>
+static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) {
+ Address valobj_addr = GetArrayAddressOrPointerValue(valobj);
+ if (!valobj_addr.IsValid())
+ return false;
+
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
+ options.SetLocation(valobj_addr);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetPrefixToken(getElementTraits(ElemType).first);
+
+ if (!StringPrinter::ReadStringAndDumpToStream<ElemType>(options))
+ stream.Printf("Summary Unavailable");
+
+ return true;
+}
+
+template <StringElementType ElemType>
+static bool CharSummaryProvider(ValueObject &valobj, Stream &stream) {
+ DataExtractor data;
+ Status error;
+ valobj.GetData(data, error);
+
+ if (error.Fail())
+ return false;
+
+ std::string value;
+ StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
+
+ constexpr auto ElemTraits = getElementTraits(ElemType);
+ valobj.GetValueAsCString(ElemTraits.second, value);
+
+ if (!value.empty())
+ stream.Printf("%s ", value.c_str());
+
+ options.SetData(std::move(data));
+ options.SetStream(&stream);
+ options.SetPrefixToken(ElemTraits.first);
+ options.SetQuote('\'');
+ options.SetSourceSize(1);
+ options.SetBinaryZeroIsTerminator(false);
+
+ return StringPrinter::ReadBufferAndDumpToStream<ElemType>(options);
+}
+
+bool lldb_private::formatters::Char8StringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ return CharStringSummaryProvider<StringElementType::UTF8>(valobj, stream);
+}
+
+bool lldb_private::formatters::Char16StringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ return CharStringSummaryProvider<StringElementType::UTF16>(valobj, stream);
+}
+
+bool lldb_private::formatters::Char32StringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ return CharStringSummaryProvider<StringElementType::UTF32>(valobj, stream);
+}
+
+bool lldb_private::formatters::WCharStringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ Address valobj_addr = GetArrayAddressOrPointerValue(valobj);
+ if (!valobj_addr.IsValid())
+ return false;
+
+ // Get a wchar_t basic type from the current type system
+ CompilerType wchar_compiler_type =
+ valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
+
+ if (!wchar_compiler_type)
+ return false;
+
+ // Safe to pass nullptr for exe_scope here.
+ std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
+ if (!size)
+ return false;
+ const uint32_t wchar_size = *size;
+
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
+ options.SetLocation(valobj_addr);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetPrefixToken("L");
+
+ switch (wchar_size) {
+ case 8:
+ return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(
+ options);
+ case 16:
+ return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16>(
+ options);
+ case 32:
+ return StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32>(
+ options);
+ default:
+ stream.Printf("size for wchar_t is not valid");
+ return true;
+ }
+ return true;
+}
+
+bool lldb_private::formatters::Char8SummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ return CharSummaryProvider<StringElementType::UTF8>(valobj, stream);
+}
+
+bool lldb_private::formatters::Char16SummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ return CharSummaryProvider<StringElementType::UTF16>(valobj, stream);
+}
+
+bool lldb_private::formatters::Char32SummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ return CharSummaryProvider<StringElementType::UTF32>(valobj, stream);
+}
+
+bool lldb_private::formatters::WCharSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) {
+ DataExtractor data;
+ Status error;
+ valobj.GetData(data, error);
+
+ if (error.Fail())
+ return false;
+
+ // Get a wchar_t basic type from the current type system
+ CompilerType wchar_compiler_type =
+ valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
+
+ if (!wchar_compiler_type)
+ return false;
+
+ // Safe to pass nullptr for exe_scope here.
+ std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
+ if (!size)
+ return false;
+ const uint32_t wchar_size = *size;
+
+ StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
+ options.SetData(std::move(data));
+ options.SetStream(&stream);
+ options.SetPrefixToken("L");
+ options.SetQuote('\'');
+ options.SetSourceSize(1);
+ options.SetBinaryZeroIsTerminator(false);
+
+ switch (wchar_size) {
+ case 8:
+ return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8>(
+ options);
+ case 16:
+ return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16>(
+ options);
+ case 32:
+ return StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32>(
+ options);
+ default:
+ stream.Printf("size for wchar_t is not valid");
+ return true;
+ }
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
new file mode 100644
index 000000000000..2713ded45929
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h
@@ -0,0 +1,49 @@
+//===-- CxxStringTypes.h ----------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+bool Char8StringSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // char8_t*
+
+bool Char16StringSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // char16_t* and unichar*
+
+bool Char32StringSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // char32_t*
+
+bool WCharStringSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // wchar_t*
+
+bool Char8SummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // char8_t
+
+bool Char16SummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // char16_t and unichar
+
+bool Char32SummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // char32_t
+
+bool WCharSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // wchar_t
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Generic.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Generic.h
new file mode 100644
index 000000000000..bfb28bebf90b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Generic.h
@@ -0,0 +1,25 @@
+//===-- LibCxx.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_GENERIC_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_GENERIC_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+
+bool GenericOptionalSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_GENERIC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
new file mode 100644
index 000000000000..33955dccb6cc
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
@@ -0,0 +1,154 @@
+//===-- GenericBitset.cpp //-----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+#include "LibStdcpp.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Target.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+/// This class can be used for handling bitsets from both libcxx and libstdcpp.
+class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ enum class StdLib {
+ LibCxx,
+ LibStdcpp,
+ };
+
+ GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ return formatters::ExtractIndexFromString(name.GetCString());
+ }
+
+ bool MightHaveChildren() override { return true; }
+ lldb::ChildCacheState Update() override;
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_elements.size();
+ }
+ ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+private:
+ llvm::StringRef GetDataContainerMemberName();
+
+ // The lifetime of a ValueObject and all its derivative ValueObjects
+ // (children, clones, etc.) is managed by a ClusterManager. These
+ // objects are only destroyed when every shared pointer to any of them
+ // is destroyed, so we must not store a shared pointer to any ValueObject
+ // derived from our backend ValueObject (since we're in the same cluster).
+ // Value objects created from raw data (i.e. in a different cluster) must
+ // be referenced via shared pointer to keep them alive, however.
+ std::vector<ValueObjectSP> m_elements;
+ ValueObject *m_first = nullptr;
+ CompilerType m_bool_type;
+ ByteOrder m_byte_order = eByteOrderInvalid;
+ uint8_t m_byte_size = 0;
+ StdLib m_stdlib;
+};
+} // namespace
+
+GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)
+ : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
+ m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
+ if (auto target_sp = m_backend.GetTargetSP()) {
+ m_byte_order = target_sp->GetArchitecture().GetByteOrder();
+ m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
+ Update();
+ }
+}
+
+llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() {
+ static constexpr llvm::StringLiteral s_libcxx_case("__first_");
+ static constexpr llvm::StringLiteral s_libstdcpp_case("_M_w");
+ switch (m_stdlib) {
+ case StdLib::LibCxx:
+ return s_libcxx_case;
+ case StdLib::LibStdcpp:
+ return s_libstdcpp_case;
+ }
+ llvm_unreachable("Unknown StdLib enum");
+}
+
+lldb::ChildCacheState GenericBitsetFrontEnd::Update() {
+ m_elements.clear();
+ m_first = nullptr;
+
+ TargetSP target_sp = m_backend.GetTargetSP();
+ if (!target_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ size_t size = 0;
+
+ if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
+ size = arg->value.getLimitedValue();
+
+ m_elements.assign(size, ValueObjectSP());
+ m_first =
+ m_backend.GetChildMemberWithName(GetDataContainerMemberName()).get();
+ return lldb::ChildCacheState::eRefetch;
+}
+
+ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx >= m_elements.size() || !m_first)
+ return ValueObjectSP();
+
+ if (m_elements[idx])
+ return m_elements[idx];
+
+ ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
+ CompilerType type;
+ ValueObjectSP chunk;
+ // For small bitsets __first_ is not an array, but a plain size_t.
+ if (m_first->GetCompilerType().IsArrayType(&type)) {
+ std::optional<uint64_t> bit_size =
+ type.GetBitSize(ctx.GetBestExecutionContextScope());
+ if (!bit_size || *bit_size == 0)
+ return {};
+ chunk = m_first->GetChildAtIndex(idx / *bit_size);
+ } else {
+ type = m_first->GetCompilerType();
+ chunk = m_first->GetSP();
+ }
+ if (!type || !chunk)
+ return {};
+
+ std::optional<uint64_t> bit_size =
+ type.GetBitSize(ctx.GetBestExecutionContextScope());
+ if (!bit_size || *bit_size == 0)
+ return {};
+ size_t chunk_idx = idx % *bit_size;
+ uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
+ DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
+
+ m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
+ data, ctx, m_bool_type);
+
+ return m_elements[idx];
+}
+
+SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new GenericBitsetFrontEnd(*valobj_sp,
+ GenericBitsetFrontEnd::StdLib::LibStdcpp);
+ return nullptr;
+}
+
+SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new GenericBitsetFrontEnd(*valobj_sp,
+ GenericBitsetFrontEnd::StdLib::LibCxx);
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
new file mode 100644
index 000000000000..23756de7f1e6
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
@@ -0,0 +1,138 @@
+//===-- GenericOptional.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "Generic.h"
+#include "LibCxx.h"
+#include "LibStdcpp.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool lldb_private::formatters::GenericOptionalSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ stream.Printf(" Has Value=%s ",
+ valobj.GetNumChildrenIgnoringErrors() == 0 ? "false" : "true");
+
+ return true;
+}
+
+// Synthetic Children Provider
+namespace {
+
+class GenericOptionalFrontend : public SyntheticChildrenFrontEnd {
+public:
+ enum class StdLib {
+ LibCxx,
+ LibStdcpp,
+ };
+
+ GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib);
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ return formatters::ExtractIndexFromString(name.GetCString());
+ }
+
+ bool MightHaveChildren() override { return true; }
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_has_value ? 1U : 0U;
+ }
+
+ ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+ lldb::ChildCacheState Update() override;
+
+private:
+ bool m_has_value = false;
+ StdLib m_stdlib;
+};
+
+} // namespace
+
+GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj,
+ StdLib stdlib)
+ : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
+ if (auto target_sp = m_backend.GetTargetSP()) {
+ Update();
+ }
+}
+
+lldb::ChildCacheState GenericOptionalFrontend::Update() {
+ ValueObjectSP engaged_sp;
+
+ if (m_stdlib == StdLib::LibCxx)
+ engaged_sp = m_backend.GetChildMemberWithName("__engaged_");
+ else if (m_stdlib == StdLib::LibStdcpp)
+ engaged_sp = m_backend.GetChildMemberWithName("_M_payload")
+ ->GetChildMemberWithName("_M_engaged");
+
+ if (!engaged_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // _M_engaged/__engaged is a bool flag and is true if the optional contains a
+ // value. Converting it to unsigned gives us a size of 1 if it contains a
+ // value and 0 if not.
+ m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0;
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) {
+ if (!m_has_value)
+ return ValueObjectSP();
+
+ ValueObjectSP val_sp;
+
+ if (m_stdlib == StdLib::LibCxx)
+ // __val_ contains the underlying value of an optional if it has one.
+ // Currently because it is part of an anonymous union
+ // GetChildMemberWithName() does not peer through and find it unless we are
+ // at the parent itself. We can obtain the parent through __engaged_.
+ val_sp = m_backend.GetChildMemberWithName("__engaged_")
+ ->GetParent()
+ ->GetChildAtIndex(0)
+ ->GetChildMemberWithName("__val_");
+ else if (m_stdlib == StdLib::LibStdcpp) {
+ val_sp = m_backend.GetChildMemberWithName("_M_payload")
+ ->GetChildMemberWithName("_M_payload");
+
+ // In some implementations, _M_value contains the underlying value of an
+ // optional, and in other versions, it's in the payload member.
+ ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value");
+ if (candidate)
+ val_sp = candidate;
+ }
+
+ if (!val_sp)
+ return ValueObjectSP();
+
+ CompilerType holder_type = val_sp->GetCompilerType();
+
+ if (!holder_type)
+ return ValueObjectSP();
+
+ return val_sp->Clone(ConstString("Value"));
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibStdcppOptionalSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new GenericOptionalFrontend(
+ *valobj_sp, GenericOptionalFrontend::StdLib::LibStdcpp);
+ return nullptr;
+}
+
+SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new GenericOptionalFrontend(*valobj_sp,
+ GenericOptionalFrontend::StdLib::LibCxx);
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
new file mode 100644
index 000000000000..feaa51a96843
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -0,0 +1,939 @@
+//===-- LibCxx.cpp --------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FormatEntity.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/VectorIterator.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/lldb-enumerations.h"
+#include <optional>
+#include <tuple>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(
+ ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {
+ for (ConstString name : alternative_names) {
+ lldb::ValueObjectSP child_sp = obj.GetChildMemberWithName(name);
+
+ if (child_sp)
+ return child_sp;
+ }
+ return {};
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::GetFirstValueOfLibCXXCompressedPair(
+ ValueObject &pair) {
+ ValueObjectSP value;
+ ValueObjectSP first_child = pair.GetChildAtIndex(0);
+ if (first_child)
+ value = first_child->GetChildMemberWithName("__value_");
+ if (!value) {
+ // pre-r300140 member name
+ value = pair.GetChildMemberWithName("__first_");
+ }
+ return value;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
+ ValueObject &pair) {
+ ValueObjectSP value;
+ if (pair.GetNumChildrenIgnoringErrors() > 1) {
+ ValueObjectSP second_child = pair.GetChildAtIndex(1);
+ if (second_child) {
+ value = second_child->GetChildMemberWithName("__value_");
+ }
+ }
+ if (!value) {
+ // pre-r300140 member name
+ value = pair.GetChildMemberWithName("__second_");
+ }
+ return value;
+}
+
+bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+
+ if (!valobj_sp)
+ return false;
+
+ ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == nullptr)
+ return false;
+
+ CPPLanguageRuntime *cpp_runtime = CPPLanguageRuntime::Get(*process);
+
+ if (!cpp_runtime)
+ return false;
+
+ CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =
+ cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);
+
+ switch (callable_info.callable_case) {
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:
+ stream.Printf(" __f_ = %" PRIu64, callable_info.member_f_pointer_value);
+ return false;
+ break;
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:
+ stream.Printf(
+ " Lambda in File %s at Line %u",
+ callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),
+ callable_info.callable_line_entry.line);
+ break;
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:
+ stream.Printf(
+ " Function in File %s at Line %u",
+ callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),
+ callable_info.callable_line_entry.line);
+ break;
+ case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:
+ stream.Printf(" Function = %s ",
+ callable_info.callable_symbol.GetName().GetCString());
+ break;
+ }
+
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+ ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ ValueObjectSP count_sp(
+ valobj_sp->GetChildAtNamePath({"__cntrl_", "__shared_owners_"}));
+ ValueObjectSP weakcount_sp(
+ valobj_sp->GetChildAtNamePath({"__cntrl_", "__shared_weak_owners_"}));
+
+ if (!ptr_sp)
+ return false;
+
+ if (ptr_sp->GetValueAsUnsigned(0) == 0) {
+ stream.Printf("nullptr");
+ return true;
+ } else {
+ bool print_pointee = false;
+ Status error;
+ ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
+ if (pointee_sp && error.Success()) {
+ if (pointee_sp->DumpPrintableRepresentation(
+ stream, ValueObject::eValueObjectRepresentationStyleSummary,
+ lldb::eFormatInvalid,
+ ValueObject::PrintableRepresentationSpecialCases::eDisable,
+ false))
+ print_pointee = true;
+ }
+ if (!print_pointee)
+ stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
+ }
+
+ if (count_sp)
+ stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));
+
+ if (weakcount_sp)
+ stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));
+
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+
+ ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ if (!ptr_sp)
+ return false;
+
+ ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
+ if (!ptr_sp)
+ return false;
+
+ if (ptr_sp->GetValueAsUnsigned(0) == 0) {
+ stream.Printf("nullptr");
+ return true;
+ } else {
+ bool print_pointee = false;
+ Status error;
+ ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
+ if (pointee_sp && error.Success()) {
+ if (pointee_sp->DumpPrintableRepresentation(
+ stream, ValueObject::eValueObjectRepresentationStyleSummary,
+ lldb::eFormatInvalid,
+ ValueObject::PrintableRepresentationSpecialCases::eDisable,
+ false))
+ print_pointee = true;
+ }
+ if (!print_pointee)
+ stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
+ }
+
+ return true;
+}
+
+/*
+ (lldb) fr var ibeg --raw --ptr-depth 1 -T
+ (std::__1::__wrap_iter<int *>) ibeg = {
+ (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
+ (int) *__i = 1
+ }
+ }
+*/
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
+ valobj_sp, {ConstString("__i_"), ConstString("__i")})
+ : nullptr);
+}
+
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
+ LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) {
+ if (valobj_sp)
+ Update();
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
+ return (m_cntrl ? 1 : 0);
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_cntrl)
+ return lldb::ValueObjectSP();
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ValueObjectSP();
+
+ if (idx == 0)
+ return valobj_sp->GetChildMemberWithName("__ptr_");
+
+ if (idx == 1) {
+ if (auto ptr_sp = valobj_sp->GetChildMemberWithName("__ptr_")) {
+ Status status;
+ auto value_type_sp =
+ valobj_sp->GetCompilerType()
+ .GetTypeTemplateArgument(0).GetPointerType();
+ ValueObjectSP cast_ptr_sp = ptr_sp->Cast(value_type_sp);
+ ValueObjectSP value_sp = cast_ptr_sp->Dereference(status);
+ if (status.Success()) {
+ return value_sp;
+ }
+ }
+ }
+
+ return lldb::ValueObjectSP();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
+ m_cntrl = nullptr;
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+ if (!target_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ lldb::ValueObjectSP cntrl_sp(valobj_sp->GetChildMemberWithName("__cntrl_"));
+
+ m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
+ // dependency
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (name == "__ptr_")
+ return 0;
+ if (name == "$$dereference$$")
+ return 1;
+ return UINT32_MAX;
+}
+
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
+ ~LibcxxSharedPtrSyntheticFrontEnd() = default;
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
+
+lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
+ LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
+ ~LibcxxUniquePtrSyntheticFrontEnd() = default;
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
+ if (m_value_ptr_sp)
+ return m_deleter_sp ? 2 : 1;
+ return 0;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_value_ptr_sp)
+ return lldb::ValueObjectSP();
+
+ if (idx == 0)
+ return m_value_ptr_sp;
+
+ if (idx == 1)
+ return m_deleter_sp;
+
+ if (idx == 2) {
+ Status status;
+ auto value_sp = m_value_ptr_sp->Dereference(status);
+ if (status.Success()) {
+ return value_sp;
+ }
+ }
+
+ return lldb::ValueObjectSP();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
+ if (!ptr_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Retrieve the actual pointer and the deleter, and clone them to give them
+ // user-friendly names.
+ ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
+ if (value_pointer_sp)
+ m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
+
+ ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
+ if (deleter_sp)
+ m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (name == "pointer")
+ return 0;
+ if (name == "deleter")
+ return 1;
+ if (name == "$$dereference$$")
+ return 2;
+ return UINT32_MAX;
+}
+
+bool lldb_private::formatters::LibcxxContainerSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ if (valobj.IsPointerType()) {
+ uint64_t value = valobj.GetValueAsUnsigned(0);
+ if (!value)
+ return false;
+ stream.Printf("0x%016" PRIx64 " ", value);
+ }
+ return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
+ nullptr, nullptr, &valobj, false, false);
+}
+
+/// The field layout in a libc++ string (cap, side, data or data, size, cap).
+namespace {
+enum class StringLayout { CSD, DSC };
+}
+
+/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
+/// extract its data payload. Return the size + payload pair.
+// TODO: Support big-endian architectures.
+static std::optional<std::pair<uint64_t, ValueObjectSP>>
+ExtractLibcxxStringInfo(ValueObject &valobj) {
+ ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
+ if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
+ return {};
+
+ // __r_ is a compressed_pair of the actual data and the allocator. The data we
+ // want is in the first base class.
+ ValueObjectSP valobj_r_base_sp = valobj_r_sp->GetChildAtIndex(0);
+ if (!valobj_r_base_sp)
+ return {};
+
+ ValueObjectSP valobj_rep_sp =
+ valobj_r_base_sp->GetChildMemberWithName("__value_");
+ if (!valobj_rep_sp)
+ return {};
+
+ ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");
+ if (!l)
+ return {};
+
+ StringLayout layout = l->GetIndexOfChildWithName("__data_") == 0
+ ? StringLayout::DSC
+ : StringLayout::CSD;
+
+ bool short_mode = false; // this means the string is in short-mode and the
+ // data is stored inline
+ bool using_bitmasks = true; // Whether the class uses bitmasks for the mode
+ // flag (pre-D123580).
+ uint64_t size;
+ uint64_t size_mode_value = 0;
+
+ ValueObjectSP short_sp = valobj_rep_sp->GetChildMemberWithName("__s");
+ if (!short_sp)
+ return {};
+
+ ValueObjectSP is_long = short_sp->GetChildMemberWithName("__is_long_");
+ ValueObjectSP size_sp = short_sp->GetChildMemberWithName("__size_");
+ if (!size_sp)
+ return {};
+
+ if (is_long) {
+ using_bitmasks = false;
+ short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);
+ size = size_sp->GetValueAsUnsigned(/*fail_value=*/0);
+ } else {
+ // The string mode is encoded in the size field.
+ size_mode_value = size_sp->GetValueAsUnsigned(0);
+ uint8_t mode_mask = layout == StringLayout::DSC ? 0x80 : 1;
+ short_mode = (size_mode_value & mode_mask) == 0;
+ }
+
+ if (short_mode) {
+ ValueObjectSP location_sp = short_sp->GetChildMemberWithName("__data_");
+ if (using_bitmasks)
+ size = (layout == StringLayout::DSC) ? size_mode_value
+ : ((size_mode_value >> 1) % 256);
+
+ if (!location_sp)
+ return {};
+
+ // When the small-string optimization takes place, the data must fit in the
+ // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's
+ // likely that the string isn't initialized and we're reading garbage.
+ ExecutionContext exe_ctx(location_sp->GetExecutionContextRef());
+ const std::optional<uint64_t> max_bytes =
+ location_sp->GetCompilerType().GetByteSize(
+ exe_ctx.GetBestExecutionContextScope());
+ if (!max_bytes || size > *max_bytes)
+ return {};
+
+ return std::make_pair(size, location_sp);
+ }
+
+ // we can use the layout_decider object as the data pointer
+ ValueObjectSP location_sp = l->GetChildMemberWithName("__data_");
+ ValueObjectSP size_vo = l->GetChildMemberWithName("__size_");
+ ValueObjectSP capacity_vo = l->GetChildMemberWithName("__cap_");
+ if (!size_vo || !location_sp || !capacity_vo)
+ return {};
+ size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
+ uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
+ if (!using_bitmasks && layout == StringLayout::CSD)
+ capacity *= 2;
+ if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||
+ capacity < size)
+ return {};
+ return std::make_pair(size, location_sp);
+}
+
+static bool
+LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options,
+ ValueObjectSP location_sp, size_t size) {
+ if (size == 0) {
+ stream.Printf("L\"\"");
+ return true;
+ }
+ if (!location_sp)
+ return false;
+
+ StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
+ if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
+ const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
+ if (size > max_size) {
+ size = max_size;
+ options.SetIsTruncated(true);
+ }
+ }
+
+ DataExtractor extractor;
+ const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
+ if (bytes_read < size)
+ return false;
+
+ // std::wstring::size() is measured in 'characters', not bytes
+ TypeSystemClangSP scratch_ts_sp =
+ ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP());
+ if (!scratch_ts_sp)
+ return false;
+
+ auto wchar_t_size =
+ scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
+ if (!wchar_t_size)
+ return false;
+
+ options.SetData(std::move(extractor));
+ options.SetStream(&stream);
+ options.SetPrefixToken("L");
+ options.SetQuote('"');
+ options.SetSourceSize(size);
+ options.SetBinaryZeroIsTerminator(false);
+
+ switch (*wchar_t_size) {
+ case 1:
+ return StringPrinter::ReadBufferAndDumpToStream<
+ lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
+ options);
+ break;
+
+ case 2:
+ return StringPrinter::ReadBufferAndDumpToStream<
+ lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
+ options);
+ break;
+
+ case 4:
+ return StringPrinter::ReadBufferAndDumpToStream<
+ lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
+ options);
+ }
+ return false;
+}
+
+bool lldb_private::formatters::LibcxxWStringSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ auto string_info = ExtractLibcxxStringInfo(valobj);
+ if (!string_info)
+ return false;
+ uint64_t size;
+ ValueObjectSP location_sp;
+ std::tie(size, location_sp) = *string_info;
+
+ return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
+ location_sp, size);
+}
+
+template <StringPrinter::StringElementType element_type>
+static bool
+LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options,
+ std::string prefix_token, ValueObjectSP location_sp,
+ uint64_t size) {
+
+ if (size == 0) {
+ stream.Printf("\"\"");
+ return true;
+ }
+
+ if (!location_sp)
+ return false;
+
+ StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
+
+ if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
+ const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
+ if (size > max_size) {
+ size = max_size;
+ options.SetIsTruncated(true);
+ }
+ }
+
+ {
+ DataExtractor extractor;
+ const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
+ if (bytes_read < size)
+ return false;
+
+ options.SetData(std::move(extractor));
+ }
+ options.SetStream(&stream);
+ if (prefix_token.empty())
+ options.SetPrefixToken(nullptr);
+ else
+ options.SetPrefixToken(prefix_token);
+ options.SetQuote('"');
+ options.SetSourceSize(size);
+ options.SetBinaryZeroIsTerminator(false);
+ return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
+}
+
+template <StringPrinter::StringElementType element_type>
+static bool
+LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options,
+ std::string prefix_token) {
+ auto string_info = ExtractLibcxxStringInfo(valobj);
+ if (!string_info)
+ return false;
+ uint64_t size;
+ ValueObjectSP location_sp;
+ std::tie(size, location_sp) = *string_info;
+
+ return LibcxxStringSummaryProvider<element_type>(
+ valobj, stream, summary_options, prefix_token, location_sp, size);
+}
+template <StringPrinter::StringElementType element_type>
+static bool formatStringImpl(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options,
+ std::string prefix_token) {
+ StreamString scratch_stream;
+ const bool success = LibcxxStringSummaryProvider<element_type>(
+ valobj, scratch_stream, summary_options, prefix_token);
+ if (success)
+ stream << scratch_stream.GetData();
+ else
+ stream << "Summary Unavailable";
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxStringSummaryProviderASCII(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return formatStringImpl<StringPrinter::StringElementType::ASCII>(
+ valobj, stream, summary_options, "");
+}
+
+bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return formatStringImpl<StringPrinter::StringElementType::UTF16>(
+ valobj, stream, summary_options, "u");
+}
+
+bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return formatStringImpl<StringPrinter::StringElementType::UTF32>(
+ valobj, stream, summary_options, "U");
+}
+
+static std::tuple<bool, ValueObjectSP, size_t>
+LibcxxExtractStringViewData(ValueObject& valobj) {
+ auto dataobj = GetChildMemberWithName(
+ valobj, {ConstString("__data_"), ConstString("__data")});
+ auto sizeobj = GetChildMemberWithName(
+ valobj, {ConstString("__size_"), ConstString("__size")});
+ if (!dataobj || !sizeobj)
+ return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
+
+ if (!dataobj->GetError().Success() || !sizeobj->GetError().Success())
+ return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
+
+ bool success{false};
+ uint64_t size = sizeobj->GetValueAsUnsigned(0, &success);
+ if (!success)
+ return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
+
+ return std::make_tuple(true,dataobj,size);
+}
+
+template <StringPrinter::StringElementType element_type>
+static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options,
+ std::string prefix_token) {
+
+ bool success;
+ ValueObjectSP dataobj;
+ size_t size;
+ std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);
+
+ if (!success) {
+ stream << "Summary Unavailable";
+ return true;
+ }
+
+ return LibcxxStringSummaryProvider<element_type>(
+ valobj, stream, summary_options, prefix_token, dataobj, size);
+}
+
+bool lldb_private::formatters::LibcxxStringViewSummaryProviderASCII(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return formatStringViewImpl<StringPrinter::StringElementType::ASCII>(
+ valobj, stream, summary_options, "");
+}
+
+bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return formatStringViewImpl<StringPrinter::StringElementType::UTF16>(
+ valobj, stream, summary_options, "u");
+}
+
+bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+ return formatStringViewImpl<StringPrinter::StringElementType::UTF32>(
+ valobj, stream, summary_options, "U");
+}
+
+bool lldb_private::formatters::LibcxxWStringViewSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options) {
+
+ bool success;
+ ValueObjectSP dataobj;
+ size_t size;
+ std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);
+
+ if (!success) {
+ stream << "Summary Unavailable";
+ return true;
+ }
+
+ return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
+ dataobj, size);
+}
+
+static bool
+LibcxxChronoTimePointSecondsSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options,
+ const char *fmt) {
+ ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");
+ if (!ptr_sp)
+ return false;
+ ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");
+ if (!ptr_sp)
+ return false;
+
+#ifndef _WIN32
+ // The date time in the chrono library is valid in the range
+ // [-32767-01-01T00:00:00Z, 32767-12-31T23:59:59Z]. A 64-bit time_t has a
+ // larger range, the function strftime is not able to format the entire range
+ // of time_t. The exact point has not been investigated; it's limited to
+ // chrono's range.
+ const std::time_t chrono_timestamp_min =
+ -1'096'193'779'200; // -32767-01-01T00:00:00Z
+ const std::time_t chrono_timestamp_max =
+ 971'890'963'199; // 32767-12-31T23:59:59Z
+#else
+ const std::time_t chrono_timestamp_min = -43'200; // 1969-12-31T12:00:00Z
+ const std::time_t chrono_timestamp_max =
+ 32'536'850'399; // 3001-01-19T21:59:59
+#endif
+
+ const std::time_t seconds = ptr_sp->GetValueAsSigned(0);
+ if (seconds < chrono_timestamp_min || seconds > chrono_timestamp_max)
+ stream.Printf("timestamp=%" PRId64 " s", static_cast<int64_t>(seconds));
+ else {
+ std::array<char, 128> str;
+ std::size_t size =
+ std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));
+ if (size == 0)
+ return false;
+
+ stream.Printf("date/time=%s timestamp=%" PRId64 " s", str.data(),
+ static_cast<int64_t>(seconds));
+ }
+
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,
+ "%FT%H:%M:%SZ");
+}
+
+bool lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,
+ "%FT%H:%M:%S");
+}
+
+static bool
+LibcxxChronoTimepointDaysSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options,
+ const char *fmt) {
+ ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");
+ if (!ptr_sp)
+ return false;
+ ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");
+ if (!ptr_sp)
+ return false;
+
+#ifndef _WIN32
+ // The date time in the chrono library is valid in the range
+ // [-32767-01-01Z, 32767-12-31Z]. A 32-bit time_t has a larger range, the
+ // function strftime is not able to format the entire range of time_t. The
+ // exact point has not been investigated; it's limited to chrono's range.
+ const int chrono_timestamp_min = -12'687'428; // -32767-01-01Z
+ const int chrono_timestamp_max = 11'248'737; // 32767-12-31Z
+#else
+ const int chrono_timestamp_min = 0; // 1970-01-01Z
+ const int chrono_timestamp_max = 376'583; // 3001-01-19Z
+#endif
+
+ const int days = ptr_sp->GetValueAsSigned(0);
+ if (days < chrono_timestamp_min || days > chrono_timestamp_max)
+ stream.Printf("timestamp=%d days", days);
+
+ else {
+ const std::time_t seconds = std::time_t(86400) * days;
+
+ std::array<char, 128> str;
+ std::size_t size =
+ std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));
+ if (size == 0)
+ return false;
+
+ stream.Printf("date=%s timestamp=%d days", str.data(), days);
+ }
+
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,
+ "%FZ");
+}
+
+bool lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,
+ "%F");
+}
+
+bool lldb_private::formatters::LibcxxChronoMonthSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ // FIXME: These are the names used in the C++20 ostream operator. Since LLVM
+ // uses C++17 it's not possible to use the ostream operator directly.
+ static const std::array<std::string_view, 12> months = {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"};
+
+ ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__m_");
+ if (!ptr_sp)
+ return false;
+
+ const unsigned month = ptr_sp->GetValueAsUnsigned(0);
+ if (month >= 1 && month <= 12)
+ stream << "month=" << months[month - 1];
+ else
+ stream.Printf("month=%u", month);
+
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ // FIXME: These are the names used in the C++20 ostream operator. Since LLVM
+ // uses C++17 it's not possible to use the ostream operator directly.
+ static const std::array<std::string_view, 7> weekdays = {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"};
+
+ ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__wd_");
+ if (!ptr_sp)
+ return false;
+
+ const unsigned weekday = ptr_sp->GetValueAsUnsigned(0);
+ if (weekday < 7)
+ stream << "weekday=" << weekdays[weekday];
+ else
+ stream.Printf("weekday=%u", weekday);
+
+ return true;
+}
+
+bool lldb_private::formatters::LibcxxChronoYearMonthDaySummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__y_");
+ if (!ptr_sp)
+ return false;
+ ptr_sp = ptr_sp->GetChildMemberWithName("__y_");
+ if (!ptr_sp)
+ return false;
+ int year = ptr_sp->GetValueAsSigned(0);
+
+ ptr_sp = valobj.GetChildMemberWithName("__m_");
+ if (!ptr_sp)
+ return false;
+ ptr_sp = ptr_sp->GetChildMemberWithName("__m_");
+ if (!ptr_sp)
+ return false;
+ const unsigned month = ptr_sp->GetValueAsUnsigned(0);
+
+ ptr_sp = valobj.GetChildMemberWithName("__d_");
+ if (!ptr_sp)
+ return false;
+ ptr_sp = ptr_sp->GetChildMemberWithName("__d_");
+ if (!ptr_sp)
+ return false;
+ const unsigned day = ptr_sp->GetValueAsUnsigned(0);
+
+ stream << "date=";
+ if (year < 0) {
+ stream << '-';
+ year = -year;
+ }
+ stream.Printf("%04d-%02u-%02u", year, month, day);
+
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
new file mode 100644
index 000000000000..5307b5251ca8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -0,0 +1,244 @@
+//===-- LibCxx.h ---------------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXX_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXX_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+
+/// Find a child member of \c obj_sp, trying all alternative names in order.
+lldb::ValueObjectSP
+GetChildMemberWithName(ValueObject &obj,
+ llvm::ArrayRef<ConstString> alternative_names);
+
+lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
+lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
+
+
+bool LibcxxStringSummaryProviderASCII(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::string
+
+bool LibcxxStringSummaryProviderUTF16(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::u16string
+
+bool LibcxxStringSummaryProviderUTF32(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::u32string
+
+bool LibcxxWStringSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::wstring
+
+bool LibcxxStringViewSummaryProviderASCII(
+ ValueObject &valueObj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::string_view
+
+bool LibcxxStringViewSummaryProviderUTF16(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::u16string_view
+
+bool LibcxxStringViewSummaryProviderUTF32(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &summary_options); // libc++ std::u32string_view
+
+bool LibcxxWStringViewSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::wstring_view
+
+bool LibcxxStdSliceArraySummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::slice_array
+
+bool LibcxxSmartPointerSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions
+ &options); // libc++ std::shared_ptr<> and std::weak_ptr<>
+
+// libc++ std::unique_ptr<>
+bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+bool LibcxxFunctionSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::function<>
+
+SyntheticChildrenFrontEnd *
+LibcxxVectorBoolSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+bool LibcxxContainerSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+/// Formatter for libc++ std::span<>.
+bool LibcxxSpanSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+SyntheticChildrenFrontEnd *
+LibCxxVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+ ~LibcxxSharedPtrSyntheticFrontEnd() override;
+
+private:
+ ValueObject *m_cntrl;
+};
+
+class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+ ~LibcxxUniquePtrSyntheticFrontEnd() override;
+
+private:
+ lldb::ValueObjectSP m_value_ptr_sp;
+ lldb::ValueObjectSP m_deleter_sp;
+};
+
+SyntheticChildrenFrontEnd *
+LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdValarraySyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdSliceArraySyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdProxyArraySyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdMapSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdUnorderedMapSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *LibcxxQueueFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *LibcxxTupleFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
+SyntheticChildrenFrontEnd *
+LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibcxxStdRangesRefViewSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+bool LibcxxChronoSysSecondsSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::chrono::sys_seconds
+
+bool LibcxxChronoSysDaysSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::chrono::sys_days
+
+bool LibcxxChronoLocalSecondsSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::chrono::local_seconds
+
+bool LibcxxChronoLocalDaysSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::chrono::local_days
+
+bool LibcxxChronoMonthSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::chrono::month
+
+bool LibcxxChronoWeekdaySummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::chrono::weekday
+
+bool LibcxxChronoYearMonthDaySummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::chrono::year_month_day
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXX_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp
new file mode 100644
index 000000000000..7f30dc186291
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp
@@ -0,0 +1,151 @@
+//===-- LibCxxAtomic.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxxAtomic.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+//
+// We are supporting two versions of libc++ std::atomic
+//
+// Given std::atomic<int> i;
+//
+// The previous version of std::atomic was laid out like this
+//
+// (lldb) frame var -L -R i
+// 0x00007ffeefbff9a0: (std::__1::atomic<int>) i = {
+// 0x00007ffeefbff9a0: std::__1::__atomic_base<int, true> = {
+// 0x00007ffeefbff9a0: std::__1::__atomic_base<int, false> = {
+// 0x00007ffeefbff9a0: __a_ = 5
+// }
+// }
+// }
+//
+// In this case we need to obtain __a_ and the current version is laid out as so
+//
+// (lldb) frame var -L -R i
+// 0x00007ffeefbff9b0: (std::__1::atomic<int>) i = {
+// 0x00007ffeefbff9b0: std::__1::__atomic_base<int, true> = {
+// 0x00007ffeefbff9b0: std::__1::__atomic_base<int, false> = {
+// 0x00007ffeefbff9b0: __a_ = {
+// 0x00007ffeefbff9b0: std::__1::__cxx_atomic_base_impl<int> = {
+// 0x00007ffeefbff9b0: __a_value = 5
+// }
+// }
+// }
+// }
+//}
+//
+// In this case we need to obtain __a_value
+//
+// The below method covers both cases and returns the relevant member as a
+// ValueObjectSP
+//
+ValueObjectSP
+lldb_private::formatters::GetLibCxxAtomicValue(ValueObject &valobj) {
+ ValueObjectSP non_sythetic = valobj.GetNonSyntheticValue();
+ if (!non_sythetic)
+ return {};
+
+ ValueObjectSP member__a_ = non_sythetic->GetChildMemberWithName("__a_");
+ if (!member__a_)
+ return {};
+
+ ValueObjectSP member__a_value =
+ member__a_->GetChildMemberWithName("__a_value");
+ if (!member__a_value)
+ return member__a_;
+
+ return member__a_value;
+}
+
+bool lldb_private::formatters::LibCxxAtomicSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+
+ if (ValueObjectSP atomic_value = GetLibCxxAtomicValue(valobj)) {
+ std::string summary;
+ if (atomic_value->GetSummaryAsCString(summary, options) &&
+ summary.size() > 0) {
+ stream.Printf("%s", summary.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+namespace lldb_private {
+namespace formatters {
+class LibcxxStdAtomicSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdAtomicSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ValueObject *m_real_child = nullptr;
+};
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
+ LibcxxStdAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::Update() {
+ ValueObjectSP atomic_value = GetLibCxxAtomicValue(m_backend);
+ if (atomic_value)
+ m_real_child = GetLibCxxAtomicValue(m_backend).get();
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdAtomicSyntheticFrontEnd::CalculateNumChildren() {
+ return m_real_child ? 1 : 0;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (idx == 0)
+ return m_real_child->GetSP()->Clone(ConstString("Value"));
+ return nullptr;
+}
+
+size_t lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ return name == "Value" ? 0 : UINT32_MAX;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new LibcxxStdAtomicSyntheticFrontEnd(valobj_sp);
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h
new file mode 100644
index 000000000000..6fcceb645c7b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.h
@@ -0,0 +1,33 @@
+//===-- LibCxxAtomic.h -------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXATOMIC_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXATOMIC_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+
+lldb::ValueObjectSP GetLibCxxAtomicValue(ValueObject &valobj);
+
+bool LibCxxAtomicSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options);
+
+SyntheticChildrenFrontEnd *
+LibcxxAtomicSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXATOMIC_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
new file mode 100644
index 000000000000..bd9c72497664
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp
@@ -0,0 +1,119 @@
+//===-- LibCxxInitializerList.cpp -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+class LibcxxInitializerListSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxInitializerListSyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ValueObject *m_start = nullptr;
+ CompilerType m_element_type;
+ uint32_t m_element_size = 0;
+ size_t m_num_elements = 0;
+};
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
+ LibcxxInitializerListSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
+ ~LibcxxInitializerListSyntheticFrontEnd() {
+ // this needs to stay around because it's a child object who will follow its
+ // parent's life cycle
+ // delete m_start;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxInitializerListSyntheticFrontEnd::CalculateNumChildren() {
+ m_num_elements = 0;
+ ValueObjectSP size_sp(m_backend.GetChildMemberWithName("__size_"));
+ if (size_sp)
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ return m_num_elements;
+}
+
+lldb::ValueObjectSP lldb_private::formatters::
+ LibcxxInitializerListSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (!m_start)
+ return lldb::ValueObjectSP();
+
+ uint64_t offset = idx * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::Update() {
+ m_start = nullptr;
+ m_num_elements = 0;
+ m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
+ if (!m_element_type.IsValid())
+ return lldb::ChildCacheState::eRefetch;
+
+ if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
+ m_element_size = *size;
+ // Store raw pointers or end up with a circular dependency.
+ m_start = m_backend.GetChildMemberWithName("__begin_").get();
+ }
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_start)
+ return UINT32_MAX;
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibcxxInitializerListSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
new file mode 100644
index 000000000000..d7cfeb30557c
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
@@ -0,0 +1,426 @@
+//===-- LibCxxList.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace {
+
+class ListEntry {
+public:
+ ListEntry() = default;
+ ListEntry(ValueObjectSP entry_sp) : m_entry_sp(std::move(entry_sp)) {}
+ ListEntry(ValueObject *entry)
+ : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
+
+ ListEntry next() {
+ if (!m_entry_sp)
+ return ListEntry();
+ return ListEntry(m_entry_sp->GetChildMemberWithName("__next_"));
+ }
+
+ ListEntry prev() {
+ if (!m_entry_sp)
+ return ListEntry();
+ return ListEntry(m_entry_sp->GetChildMemberWithName("__prev_"));
+ }
+
+ uint64_t value() const {
+ if (!m_entry_sp)
+ return 0;
+ return m_entry_sp->GetValueAsUnsigned(0);
+ }
+
+ bool null() { return (value() == 0); }
+
+ explicit operator bool() { return GetEntry() && !null(); }
+
+ ValueObjectSP GetEntry() { return m_entry_sp; }
+
+ void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
+
+ bool operator==(const ListEntry &rhs) const { return value() == rhs.value(); }
+
+ bool operator!=(const ListEntry &rhs) const { return !(*this == rhs); }
+
+private:
+ ValueObjectSP m_entry_sp;
+};
+
+class ListIterator {
+public:
+ ListIterator() = default;
+ ListIterator(ListEntry entry) : m_entry(std::move(entry)) {}
+ ListIterator(ValueObjectSP entry) : m_entry(std::move(entry)) {}
+ ListIterator(ValueObject *entry) : m_entry(entry) {}
+
+ ValueObjectSP value() { return m_entry.GetEntry(); }
+
+ ValueObjectSP advance(size_t count) {
+ if (count == 0)
+ return m_entry.GetEntry();
+ if (count == 1) {
+ next();
+ return m_entry.GetEntry();
+ }
+ while (count > 0) {
+ next();
+ count--;
+ if (m_entry.null())
+ return lldb::ValueObjectSP();
+ }
+ return m_entry.GetEntry();
+ }
+
+ bool operator==(const ListIterator &rhs) const {
+ return (rhs.m_entry == m_entry);
+ }
+
+protected:
+ void next() { m_entry = m_entry.next(); }
+
+ void prev() { m_entry = m_entry.prev(); }
+
+private:
+ ListEntry m_entry;
+};
+
+class AbstractListFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ return ExtractIndexFromString(name.GetCString());
+ }
+ bool MightHaveChildren() override { return true; }
+ lldb::ChildCacheState Update() override;
+
+protected:
+ AbstractListFrontEnd(ValueObject &valobj)
+ : SyntheticChildrenFrontEnd(valobj) {}
+
+ size_t m_count = 0;
+ ValueObject *m_head = nullptr;
+
+ static constexpr bool g_use_loop_detect = true;
+ size_t m_loop_detected = 0; // The number of elements that have had loop
+ // detection run over them.
+ ListEntry m_slow_runner; // Used for loop detection
+ ListEntry m_fast_runner; // Used for loop detection
+
+ size_t m_list_capping_size = 0;
+ CompilerType m_element_type;
+ std::map<size_t, ListIterator> m_iterators;
+
+ bool HasLoop(size_t count);
+ ValueObjectSP GetItem(size_t idx);
+};
+
+class ForwardListFrontEnd : public AbstractListFrontEnd {
+public:
+ ForwardListFrontEnd(ValueObject &valobj);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+ ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+ lldb::ChildCacheState Update() override;
+};
+
+class ListFrontEnd : public AbstractListFrontEnd {
+public:
+ ListFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~ListFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+private:
+ lldb::addr_t m_node_address = 0;
+ ValueObject *m_tail = nullptr;
+};
+
+} // end anonymous namespace
+
+lldb::ChildCacheState AbstractListFrontEnd::Update() {
+ m_loop_detected = 0;
+ m_count = UINT32_MAX;
+ m_head = nullptr;
+ m_list_capping_size = 0;
+ m_slow_runner.SetEntry(nullptr);
+ m_fast_runner.SetEntry(nullptr);
+ m_iterators.clear();
+
+ if (m_backend.GetTargetSP())
+ m_list_capping_size =
+ m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
+ if (m_list_capping_size == 0)
+ m_list_capping_size = 255;
+
+ CompilerType list_type = m_backend.GetCompilerType();
+ if (list_type.IsReferenceType())
+ list_type = list_type.GetNonReferenceType();
+
+ if (list_type.GetNumTemplateArguments() == 0)
+ return lldb::ChildCacheState::eRefetch;
+ m_element_type = list_type.GetTypeTemplateArgument(0);
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool AbstractListFrontEnd::HasLoop(size_t count) {
+ if (!g_use_loop_detect)
+ return false;
+ // don't bother checking for a loop if we won't actually need to jump nodes
+ if (m_count < 2)
+ return false;
+
+ if (m_loop_detected == 0) {
+ // This is the first time we are being run (after the last update). Set up
+ // the loop invariant for the first element.
+ m_slow_runner = ListEntry(m_head).next();
+ m_fast_runner = m_slow_runner.next();
+ m_loop_detected = 1;
+ }
+
+ // Loop invariant:
+ // Loop detection has been run over the first m_loop_detected elements. If
+ // m_slow_runner == m_fast_runner then the loop has been detected after
+ // m_loop_detected elements.
+ const size_t steps_to_run = std::min(count, m_count);
+ while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
+ m_slow_runner != m_fast_runner) {
+
+ m_slow_runner = m_slow_runner.next();
+ m_fast_runner = m_fast_runner.next().next();
+ m_loop_detected++;
+ }
+ if (count <= m_loop_detected)
+ return false; // No loop in the first m_loop_detected elements.
+ if (!m_slow_runner || !m_fast_runner)
+ return false; // Reached the end of the list. Definitely no loops.
+ return m_slow_runner == m_fast_runner;
+}
+
+ValueObjectSP AbstractListFrontEnd::GetItem(size_t idx) {
+ size_t advance = idx;
+ ListIterator current(m_head);
+ if (idx > 0) {
+ auto cached_iterator = m_iterators.find(idx - 1);
+ if (cached_iterator != m_iterators.end()) {
+ current = cached_iterator->second;
+ advance = 1;
+ }
+ }
+ ValueObjectSP value_sp = current.advance(advance);
+ m_iterators[idx] = current;
+ return value_sp;
+}
+
+ForwardListFrontEnd::ForwardListFrontEnd(ValueObject &valobj)
+ : AbstractListFrontEnd(valobj) {
+ Update();
+}
+
+llvm::Expected<uint32_t> ForwardListFrontEnd::CalculateNumChildren() {
+ if (m_count != UINT32_MAX)
+ return m_count;
+
+ ListEntry current(m_head);
+ m_count = 0;
+ while (current && m_count < m_list_capping_size) {
+ ++m_count;
+ current = current.next();
+ }
+ return m_count;
+}
+
+ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx >= CalculateNumChildrenIgnoringErrors())
+ return nullptr;
+
+ if (!m_head)
+ return nullptr;
+
+ if (HasLoop(idx + 1))
+ return nullptr;
+
+ ValueObjectSP current_sp = GetItem(idx);
+ if (!current_sp)
+ return nullptr;
+
+ current_sp = current_sp->GetChildAtIndex(1); // get the __value_ child
+ if (!current_sp)
+ return nullptr;
+
+ // we need to copy current_sp into a new object otherwise we will end up with
+ // all items named __value_
+ DataExtractor data;
+ Status error;
+ current_sp->GetData(data, error);
+ if (error.Fail())
+ return nullptr;
+
+ return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState ForwardListFrontEnd::Update() {
+ AbstractListFrontEnd::Update();
+
+ Status err;
+ ValueObjectSP backend_addr(m_backend.AddressOf(err));
+ if (err.Fail() || !backend_addr)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
+ if (!impl_sp)
+ return lldb::ChildCacheState::eRefetch;
+ impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
+ if (!impl_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_head = impl_sp->GetChildMemberWithName("__next_").get();
+ return lldb::ChildCacheState::eRefetch;
+}
+
+ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : AbstractListFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+llvm::Expected<uint32_t> ListFrontEnd::CalculateNumChildren() {
+ if (m_count != UINT32_MAX)
+ return m_count;
+ if (!m_head || !m_tail || m_node_address == 0)
+ return 0;
+ ValueObjectSP size_alloc(m_backend.GetChildMemberWithName("__size_alloc_"));
+ if (size_alloc) {
+ ValueObjectSP value = GetFirstValueOfLibCXXCompressedPair(*size_alloc);
+ if (value) {
+ m_count = value->GetValueAsUnsigned(UINT32_MAX);
+ }
+ }
+ if (m_count != UINT32_MAX) {
+ return m_count;
+ } else {
+ uint64_t next_val = m_head->GetValueAsUnsigned(0);
+ uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
+ if (next_val == 0 || prev_val == 0)
+ return 0;
+ if (next_val == m_node_address)
+ return 0;
+ if (next_val == prev_val)
+ return 1;
+ uint64_t size = 2;
+ ListEntry current(m_head);
+ while (current.next() && current.next().value() != m_node_address) {
+ size++;
+ current = current.next();
+ if (size > m_list_capping_size)
+ break;
+ }
+ return m_count = (size - 1);
+ }
+}
+
+lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(uint32_t idx) {
+ static ConstString g_value("__value_");
+ static ConstString g_next("__next_");
+
+ if (idx >= CalculateNumChildrenIgnoringErrors())
+ return lldb::ValueObjectSP();
+
+ if (!m_head || !m_tail || m_node_address == 0)
+ return lldb::ValueObjectSP();
+
+ if (HasLoop(idx + 1))
+ return lldb::ValueObjectSP();
+
+ ValueObjectSP current_sp = GetItem(idx);
+ if (!current_sp)
+ return lldb::ValueObjectSP();
+
+ current_sp = current_sp->GetChildAtIndex(1); // get the __value_ child
+ if (!current_sp)
+ return lldb::ValueObjectSP();
+
+ if (current_sp->GetName() == g_next) {
+ ProcessSP process_sp(current_sp->GetProcessSP());
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+
+ // if we grabbed the __next_ pointer, then the child is one pointer deep-er
+ lldb::addr_t addr = current_sp->GetParent()->GetPointerValue();
+ addr = addr + 2 * process_sp->GetAddressByteSize();
+ ExecutionContext exe_ctx(process_sp);
+ current_sp =
+ CreateValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
+ if (!current_sp)
+ return lldb::ValueObjectSP();
+ }
+
+ // we need to copy current_sp into a new object otherwise we will end up with
+ // all items named __value_
+ DataExtractor data;
+ Status error;
+ current_sp->GetData(data, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromData(name.GetString(), data,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState ListFrontEnd::Update() {
+ AbstractListFrontEnd::Update();
+ m_tail = nullptr;
+ m_node_address = 0;
+
+ Status err;
+ ValueObjectSP backend_addr(m_backend.AddressOf(err));
+ if (err.Fail() || !backend_addr)
+ return lldb::ChildCacheState::eRefetch;
+ m_node_address = backend_addr->GetValueAsUnsigned(0);
+ if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
+ return lldb::ChildCacheState::eRefetch;
+ ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__end_"));
+ if (!impl_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_head = impl_sp->GetChildMemberWithName("__next_").get();
+ m_tail = impl_sp->GetChildMemberWithName("__prev_").get();
+ return lldb::ChildCacheState::eRefetch;
+}
+
+SyntheticChildrenFrontEnd *formatters::LibcxxStdListSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new ListFrontEnd(valobj_sp) : nullptr);
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibcxxStdForwardListSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return valobj_sp ? new ForwardListFrontEnd(*valobj_sp) : nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
new file mode 100644
index 000000000000..5106a63d531f
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -0,0 +1,499 @@
+//===-- LibCxxMap.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include <cstdint>
+#include <locale>
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+// The flattened layout of the std::__tree_iterator::__ptr_ looks
+// as follows:
+//
+// The following shows the contiguous block of memory:
+//
+// +-----------------------------+ class __tree_end_node
+// __ptr_ | pointer __left_; |
+// +-----------------------------+ class __tree_node_base
+// | pointer __right_; |
+// | __parent_pointer __parent_; |
+// | bool __is_black_; |
+// +-----------------------------+ class __tree_node
+// | __node_value_type __value_; | <<< our key/value pair
+// +-----------------------------+
+//
+// where __ptr_ has type __iter_pointer.
+
+class MapEntry {
+public:
+ MapEntry() = default;
+ explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
+ explicit MapEntry(ValueObject *entry)
+ : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
+
+ ValueObjectSP left() const {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetSyntheticChildAtOffset(
+ 0, m_entry_sp->GetCompilerType(), true);
+ }
+
+ ValueObjectSP right() const {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetSyntheticChildAtOffset(
+ m_entry_sp->GetProcessSP()->GetAddressByteSize(),
+ m_entry_sp->GetCompilerType(), true);
+ }
+
+ ValueObjectSP parent() const {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetSyntheticChildAtOffset(
+ 2 * m_entry_sp->GetProcessSP()->GetAddressByteSize(),
+ m_entry_sp->GetCompilerType(), true);
+ }
+
+ uint64_t value() const {
+ if (!m_entry_sp)
+ return 0;
+ return m_entry_sp->GetValueAsUnsigned(0);
+ }
+
+ bool error() const {
+ if (!m_entry_sp)
+ return true;
+ return m_entry_sp->GetError().Fail();
+ }
+
+ bool null() const { return (value() == 0); }
+
+ ValueObjectSP GetEntry() const { return m_entry_sp; }
+
+ void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
+
+ bool operator==(const MapEntry &rhs) const {
+ return (rhs.m_entry_sp.get() == m_entry_sp.get());
+ }
+
+private:
+ ValueObjectSP m_entry_sp;
+};
+
+class MapIterator {
+public:
+ MapIterator(ValueObject *entry, size_t depth = 0)
+ : m_entry(entry), m_max_depth(depth), m_error(false) {}
+
+ MapIterator() = default;
+
+ ValueObjectSP value() { return m_entry.GetEntry(); }
+
+ ValueObjectSP advance(size_t count) {
+ ValueObjectSP fail;
+ if (m_error)
+ return fail;
+ size_t steps = 0;
+ while (count > 0) {
+ next();
+ count--, steps++;
+ if (m_error || m_entry.null() || (steps > m_max_depth))
+ return fail;
+ }
+ return m_entry.GetEntry();
+ }
+
+private:
+ /// Mimicks libc++'s __tree_next algorithm, which libc++ uses
+ /// in its __tree_iteartor::operator++.
+ void next() {
+ if (m_entry.null())
+ return;
+ MapEntry right(m_entry.right());
+ if (!right.null()) {
+ m_entry = tree_min(std::move(right));
+ return;
+ }
+ size_t steps = 0;
+ while (!is_left_child(m_entry)) {
+ if (m_entry.error()) {
+ m_error = true;
+ return;
+ }
+ m_entry.SetEntry(m_entry.parent());
+ steps++;
+ if (steps > m_max_depth) {
+ m_entry = MapEntry();
+ return;
+ }
+ }
+ m_entry = MapEntry(m_entry.parent());
+ }
+
+ /// Mimicks libc++'s __tree_min algorithm.
+ MapEntry tree_min(MapEntry x) {
+ if (x.null())
+ return MapEntry();
+ MapEntry left(x.left());
+ size_t steps = 0;
+ while (!left.null()) {
+ if (left.error()) {
+ m_error = true;
+ return MapEntry();
+ }
+ x = left;
+ left.SetEntry(x.left());
+ steps++;
+ if (steps > m_max_depth)
+ return MapEntry();
+ }
+ return x;
+ }
+
+ bool is_left_child(const MapEntry &x) {
+ if (x.null())
+ return false;
+ MapEntry rhs(x.parent());
+ rhs.SetEntry(rhs.left());
+ return x.value() == rhs.value();
+ }
+
+ MapEntry m_entry;
+ size_t m_max_depth = 0;
+ bool m_error = false;
+};
+
+namespace lldb_private {
+namespace formatters {
+class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdMapSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ /// Returns the ValueObject for the __tree_node type that
+ /// holds the key/value pair of the node at index \ref idx.
+ ///
+ /// \param[in] idx The child index that we're looking to get
+ /// the key/value pair for.
+ ///
+ /// \param[in] max_depth The maximum search depth after which
+ /// we stop trying to find the key/value
+ /// pair for.
+ ///
+ /// \returns On success, returns the ValueObjectSP corresponding
+ /// to the __tree_node's __value_ member (which holds
+ /// the key/value pair the formatter wants to display).
+ /// On failure, will return nullptr.
+ ValueObjectSP GetKeyValuePair(size_t idx, size_t max_depth);
+
+ ValueObject *m_tree = nullptr;
+ ValueObject *m_root_node = nullptr;
+ CompilerType m_node_ptr_type;
+ size_t m_count = UINT32_MAX;
+ std::map<size_t, MapIterator> m_iterators;
+};
+
+class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+ ~LibCxxMapIteratorSyntheticFrontEnd() override = default;
+
+private:
+ ValueObjectSP m_pair_sp = nullptr;
+};
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
+ LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren() {
+ if (m_count != UINT32_MAX)
+ return m_count;
+
+ if (m_tree == nullptr)
+ return 0;
+
+ ValueObjectSP size_node(m_tree->GetChildMemberWithName("__pair3_"));
+ if (!size_node)
+ return 0;
+
+ size_node = GetFirstValueOfLibCXXCompressedPair(*size_node);
+
+ if (!size_node)
+ return 0;
+
+ m_count = size_node->GetValueAsUnsigned(0);
+ return m_count;
+}
+
+ValueObjectSP
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetKeyValuePair(
+ size_t idx, size_t max_depth) {
+ MapIterator iterator(m_root_node, max_depth);
+
+ size_t advance_by = idx;
+ if (idx > 0) {
+ // If we have already created the iterator for the previous
+ // index, we can start from there and advance by 1.
+ auto cached_iterator = m_iterators.find(idx - 1);
+ if (cached_iterator != m_iterators.end()) {
+ iterator = cached_iterator->second;
+ advance_by = 1;
+ }
+ }
+
+ ValueObjectSP iterated_sp(iterator.advance(advance_by));
+ if (!iterated_sp)
+ // this tree is garbage - stop
+ return nullptr;
+
+ if (!m_node_ptr_type.IsValid())
+ return nullptr;
+
+ // iterated_sp is a __iter_pointer at this point.
+ // We can cast it to a __node_pointer (which is what libc++ does).
+ auto value_type_sp = iterated_sp->Cast(m_node_ptr_type);
+ if (!value_type_sp)
+ return nullptr;
+
+ // Finally, get the key/value pair.
+ value_type_sp = value_type_sp->GetChildMemberWithName("__value_");
+ if (!value_type_sp)
+ return nullptr;
+
+ m_iterators[idx] = iterator;
+
+ return value_type_sp;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ static ConstString g_cc_("__cc_"), g_cc("__cc");
+ static ConstString g_nc("__nc");
+ uint32_t num_children = CalculateNumChildrenIgnoringErrors();
+ if (idx >= num_children)
+ return nullptr;
+
+ if (m_tree == nullptr || m_root_node == nullptr)
+ return nullptr;
+
+ ValueObjectSP key_val_sp = GetKeyValuePair(idx, /*max_depth=*/num_children);
+ if (!key_val_sp) {
+ // this will stop all future searches until an Update() happens
+ m_tree = nullptr;
+ return nullptr;
+ }
+
+ // at this point we have a valid
+ // we need to copy current_sp into a new object otherwise we will end up with
+ // all items named __value_
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ auto potential_child_sp = key_val_sp->Clone(ConstString(name.GetString()));
+ if (potential_child_sp) {
+ switch (potential_child_sp->GetNumChildrenIgnoringErrors()) {
+ case 1: {
+ auto child0_sp = potential_child_sp->GetChildAtIndex(0);
+ if (child0_sp &&
+ (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc))
+ potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
+ break;
+ }
+ case 2: {
+ auto child0_sp = potential_child_sp->GetChildAtIndex(0);
+ auto child1_sp = potential_child_sp->GetChildAtIndex(1);
+ if (child0_sp &&
+ (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc) &&
+ child1_sp && child1_sp->GetName() == g_nc)
+ potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
+ break;
+ }
+ }
+ }
+ return potential_child_sp;
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
+ m_count = UINT32_MAX;
+ m_tree = m_root_node = nullptr;
+ m_iterators.clear();
+ m_tree = m_backend.GetChildMemberWithName("__tree_").get();
+ if (!m_tree)
+ return lldb::ChildCacheState::eRefetch;
+ m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get();
+ m_node_ptr_type =
+ m_tree->GetCompilerType().GetDirectNestedTypeWithName("__node_pointer");
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ return ExtractIndexFromString(name.GetCString());
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr);
+}
+
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
+ LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
+ m_pair_sp.reset();
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+ if (!target_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // m_backend is a std::map::iterator
+ // ...which is a __map_iterator<__tree_iterator<..., __node_pointer, ...>>
+ //
+ // Then, __map_iterator::__i_ is a __tree_iterator
+ auto tree_iter_sp = valobj_sp->GetChildMemberWithName("__i_");
+ if (!tree_iter_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Type is __tree_iterator::__node_pointer
+ // (We could alternatively also get this from the template argument)
+ auto node_pointer_type =
+ tree_iter_sp->GetCompilerType().GetDirectNestedTypeWithName(
+ "__node_pointer");
+ if (!node_pointer_type.IsValid())
+ return lldb::ChildCacheState::eRefetch;
+
+ // __ptr_ is a __tree_iterator::__iter_pointer
+ auto iter_pointer_sp = tree_iter_sp->GetChildMemberWithName("__ptr_");
+ if (!iter_pointer_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Cast the __iter_pointer to a __node_pointer (which stores our key/value
+ // pair)
+ auto node_pointer_sp = iter_pointer_sp->Cast(node_pointer_type);
+ if (!node_pointer_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ auto key_value_sp = node_pointer_sp->GetChildMemberWithName("__value_");
+ if (!key_value_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Create the synthetic child, which is a pair where the key and value can be
+ // retrieved by querying the synthetic frontend for
+ // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second")
+ // respectively.
+ //
+ // std::map stores the actual key/value pair in value_type::__cc_ (or
+ // previously __cc).
+ key_value_sp = key_value_sp->Clone(ConstString("pair"));
+ if (key_value_sp->GetNumChildrenIgnoringErrors() == 1) {
+ auto child0_sp = key_value_sp->GetChildAtIndex(0);
+ if (child0_sp &&
+ (child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc"))
+ key_value_sp = child0_sp->Clone(ConstString("pair"));
+ }
+
+ m_pair_sp = key_value_sp;
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
+ return 2;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_pair_sp)
+ return nullptr;
+
+ return m_pair_sp->GetChildAtIndex(idx);
+}
+
+bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_pair_sp)
+ return UINT32_MAX;
+
+ return m_pair_sp->GetIndexOfChildWithName(name);
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
new file mode 100644
index 000000000000..726f06523b97
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp
@@ -0,0 +1,194 @@
+//===-- LibCxxProxyArray.cpp-----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+
+/// Data formatter for libc++'s std::"proxy_array".
+///
+/// A proxy_array's are created by using:
+/// std::gslice_array operator[](const std::gslice& gslicearr);
+/// std::mask_array operator[](const std::valarray<bool>& boolarr);
+/// std::indirect_array operator[](const std::valarray<std::size_t>& indarr);
+///
+/// These arrays have the following members:
+/// - __vp_ points to std::valarray::__begin_
+/// - __1d_ an array of offsets of the elements from @a __vp_
+class LibcxxStdProxyArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdProxyArraySyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ /// A non-owning pointer to the array's __vp_.
+ ValueObject *m_base = nullptr;
+ /// The type of the array's template argument T.
+ CompilerType m_element_type;
+ /// The sizeof the array's template argument T.
+ uint32_t m_element_size = 0;
+
+ /// A non-owning pointer to the array's __1d_.__begin_.
+ ValueObject *m_start = nullptr;
+ /// A non-owning pointer to the array's __1d_.__end_.
+ ValueObject *m_finish = nullptr;
+ /// The type of the __1d_ array's template argument T (size_t).
+ CompilerType m_element_type_size_t;
+ /// The sizeof the __1d_ array's template argument T (size_t)
+ uint32_t m_element_size_size_t = 0;
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
+ LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
+ ~LibcxxStdProxyArraySyntheticFrontEnd() {
+ // these need to stay around because they are child objects who will follow
+ // their parent's life cycle
+ // delete m_base;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdProxyArraySyntheticFrontEnd::CalculateNumChildren() {
+
+ if (!m_start || !m_finish)
+ return 0;
+ uint64_t start_val = m_start->GetValueAsUnsigned(0);
+ uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
+
+ if (start_val == 0 || finish_val == 0)
+ return 0;
+
+ if (start_val >= finish_val)
+ return 0;
+
+ size_t num_children = (finish_val - start_val);
+ if (num_children % m_element_size_size_t)
+ return 0;
+ return num_children / m_element_size_size_t;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_base)
+ return lldb::ValueObjectSP();
+
+ uint64_t offset = idx * m_element_size_size_t;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+
+ lldb::ValueObjectSP indirect = CreateValueObjectFromAddress(
+ "", offset, m_backend.GetExecutionContextRef(), m_element_type_size_t);
+ if (!indirect)
+ return lldb::ValueObjectSP();
+
+ const size_t value = indirect->GetValueAsUnsigned(0);
+ if (!value)
+ return lldb::ValueObjectSP();
+
+ offset = value * m_element_size;
+ offset = offset + m_base->GetValueAsUnsigned(0);
+
+ StreamString name;
+ name.Printf("[%" PRIu64 "] -> [%zu]", (uint64_t)idx, value);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::Update() {
+ m_base = nullptr;
+ m_start = nullptr;
+ m_finish = nullptr;
+
+ CompilerType type = m_backend.GetCompilerType();
+ if (type.GetNumTemplateArguments() == 0)
+ return ChildCacheState::eRefetch;
+
+ m_element_type = type.GetTypeTemplateArgument(0);
+ if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr))
+ m_element_size = *size;
+
+ if (m_element_size == 0)
+ return ChildCacheState::eRefetch;
+
+ ValueObjectSP vector = m_backend.GetChildMemberWithName("__1d_");
+ if (!vector)
+ return ChildCacheState::eRefetch;
+
+ type = vector->GetCompilerType();
+ if (type.GetNumTemplateArguments() == 0)
+ return ChildCacheState::eRefetch;
+
+ m_element_type_size_t = type.GetTypeTemplateArgument(0);
+ if (std::optional<uint64_t> size = m_element_type_size_t.GetByteSize(nullptr))
+ m_element_size_size_t = *size;
+
+ if (m_element_size_size_t == 0)
+ return ChildCacheState::eRefetch;
+
+ ValueObjectSP base = m_backend.GetChildMemberWithName("__vp_");
+ ValueObjectSP start = vector->GetChildMemberWithName("__begin_");
+ ValueObjectSP finish = vector->GetChildMemberWithName("__end_");
+ if (!base || !start || !finish)
+ return ChildCacheState::eRefetch;
+
+ m_base = base.get();
+ m_start = start.get();
+ m_finish = finish.get();
+
+ return ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_base)
+ return std::numeric_limits<size_t>::max();
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ return new LibcxxStdProxyArraySyntheticFrontEnd(valobj_sp);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp
new file mode 100644
index 000000000000..5b459a17fe29
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp
@@ -0,0 +1,65 @@
+//===-- LibCxxQueue.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class QueueFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ QueueFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
+ Update();
+ }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ return m_container_sp ? m_container_sp->GetIndexOfChildWithName(name)
+ : UINT32_MAX;
+ }
+
+ bool MightHaveChildren() override { return true; }
+ lldb::ChildCacheState Update() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_container_sp ? m_container_sp->GetNumChildren() : 0;
+ }
+
+ ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ return m_container_sp ? m_container_sp->GetChildAtIndex(idx)
+ : nullptr;
+ }
+
+private:
+ // The lifetime of a ValueObject and all its derivative ValueObjects
+ // (children, clones, etc.) is managed by a ClusterManager. These
+ // objects are only destroyed when every shared pointer to any of them
+ // is destroyed, so we must not store a shared pointer to any ValueObject
+ // derived from our backend ValueObject (since we're in the same cluster).
+ ValueObject* m_container_sp = nullptr;
+};
+} // namespace
+
+lldb::ChildCacheState QueueFrontEnd::Update() {
+ m_container_sp = nullptr;
+ ValueObjectSP c_sp = m_backend.GetChildMemberWithName("c");
+ if (!c_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_container_sp = c_sp->GetSyntheticValue().get();
+ return lldb::ChildCacheState::eRefetch;
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibcxxQueueFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new QueueFrontEnd(*valobj_sp);
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp
new file mode 100644
index 000000000000..01a7b8f142ec
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp
@@ -0,0 +1,88 @@
+//===-- LibCxxRangesRefView.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "llvm/ADT/APSInt.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+
+class LibcxxStdRangesRefViewSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdRangesRefViewSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdRangesRefViewSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ // __range_ will be the sole child of this type
+ return 1;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ // Since we only have a single child, return it
+ assert(idx == 0);
+ return m_range_sp;
+ }
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override { return true; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ // We only have a single child
+ return 0;
+ }
+
+private:
+ /// Pointer to the dereferenced __range_ member
+ lldb::ValueObjectSP m_range_sp = nullptr;
+};
+
+lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEnd::
+ LibcxxStdRangesRefViewSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEnd::Update() {
+ ValueObjectSP range_ptr =
+ GetChildMemberWithName(m_backend, {ConstString("__range_")});
+ if (!range_ptr)
+ return lldb::ChildCacheState::eRefetch;
+
+ lldb_private::Status error;
+ m_range_sp = range_ptr->Dereference(error);
+
+ return error.Success() ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+LibcxxStdRangesRefViewSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ CompilerType type = valobj_sp->GetCompilerType();
+ if (!type.IsValid())
+ return nullptr;
+ return new LibcxxStdRangesRefViewSyntheticFrontEnd(valobj_sp);
+}
+
+} // namespace formatters
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
new file mode 100644
index 000000000000..c33d8e91af70
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp
@@ -0,0 +1,166 @@
+//===-- LibCxxSliceArray.cpp-----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+
+bool LibcxxStdSliceArraySummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options) {
+ ValueObjectSP obj = valobj.GetNonSyntheticValue();
+ if (!obj)
+ return false;
+
+ ValueObjectSP ptr_sp = obj->GetChildMemberWithName("__size_");
+ if (!ptr_sp)
+ return false;
+ const size_t size = ptr_sp->GetValueAsUnsigned(0);
+
+ ptr_sp = obj->GetChildMemberWithName("__stride_");
+ if (!ptr_sp)
+ return false;
+ const size_t stride = ptr_sp->GetValueAsUnsigned(0);
+
+ stream.Printf("stride=%zu size=%zu", stride, size);
+
+ return true;
+}
+
+/// Data formatter for libc++'s std::slice_array.
+///
+/// A slice_array is created by using:
+/// operator[](std::slice slicearr);
+/// and std::slice is created by:
+/// slice(std::size_t start, std::size_t size, std::size_t stride);
+/// The std::slice_array has the following members:
+/// - __vp_ points to std::valarray::__begin_ + @a start
+/// - __size_ is @a size
+/// - __stride_is @a stride
+class LibcxxStdSliceArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdSliceArraySyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ /// A non-owning pointer to slice_array.__vp_.
+ ValueObject *m_start = nullptr;
+ /// slice_array.__size_.
+ size_t m_size = 0;
+ /// slice_array.__stride_.
+ size_t m_stride = 0;
+ /// The type of slice_array's template argument T.
+ CompilerType m_element_type;
+ /// The sizeof slice_array's template argument T.
+ uint32_t m_element_size = 0;
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
+ LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
+ ~LibcxxStdSliceArraySyntheticFrontEnd() {
+ // these need to stay around because they are child objects who will follow
+ // their parent's life cycle
+ // delete m_start;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdSliceArraySyntheticFrontEnd::CalculateNumChildren() {
+ return m_size;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_start)
+ return lldb::ValueObjectSP();
+
+ uint64_t offset = idx * m_stride * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::Update() {
+ m_start = nullptr;
+
+ CompilerType type = m_backend.GetCompilerType();
+ if (type.GetNumTemplateArguments() == 0)
+ return ChildCacheState::eRefetch;
+
+ m_element_type = type.GetTypeTemplateArgument(0);
+ if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr))
+ m_element_size = *size;
+
+ if (m_element_size == 0)
+ return ChildCacheState::eRefetch;
+
+ ValueObjectSP start = m_backend.GetChildMemberWithName("__vp_");
+ ValueObjectSP size = m_backend.GetChildMemberWithName("__size_");
+ ValueObjectSP stride = m_backend.GetChildMemberWithName("__stride_");
+
+ if (!start || !size || !stride)
+ return ChildCacheState::eRefetch;
+
+ m_start = start.get();
+ m_size = size->GetValueAsUnsigned(0);
+ m_stride = stride->GetValueAsUnsigned(0);
+
+ return ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_start)
+ return std::numeric_limits<size_t>::max();
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ return new LibcxxStdSliceArraySyntheticFrontEnd(valobj_sp);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
new file mode 100644
index 000000000000..9895f336bfd0
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp
@@ -0,0 +1,153 @@
+//===-- LibCxxSpan.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include "llvm/ADT/APSInt.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+
+class LibcxxStdSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdSpanSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ /// Determines properties of the std::span<> associated with this object
+ //
+ // std::span can either be instantiated with a compile-time known
+ // extent or a std::dynamic_extent (this is the default if only the
+ // type template argument is provided). The layout of std::span
+ // depends on whether the extent is dynamic or not. For static
+ // extents (e.g., std::span<int, 9>):
+ //
+ // (std::__1::span<const int, 9>) s = {
+ // __data = 0x000000016fdff494
+ // }
+ //
+ // For dynamic extents, e.g., std::span<int>, the layout is:
+ //
+ // (std::__1::span<const int, 18446744073709551615>) s = {
+ // __data = 0x000000016fdff494
+ // __size = 6
+ // }
+ //
+ // This function checks for a '__size' member to determine the number
+ // of elements in the span. If no such member exists, we get the size
+ // from the only other place it can be: the template argument.
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ValueObject *m_start = nullptr; ///< First element of span. Held, not owned.
+ CompilerType m_element_type{}; ///< Type of span elements.
+ size_t m_num_elements = 0; ///< Number of elements in span.
+ uint32_t m_element_size = 0; ///< Size in bytes of each span element.
+};
+
+lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
+ LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdSpanSyntheticFrontEnd::CalculateNumChildren() {
+ return m_num_elements;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_start)
+ return {};
+
+ uint64_t offset = idx * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() {
+ // Get element type.
+ ValueObjectSP data_type_finder_sp = GetChildMemberWithName(
+ m_backend, {ConstString("__data_"), ConstString("__data")});
+ if (!data_type_finder_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
+
+ // Get element size.
+ if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
+ m_element_size = *size;
+
+ // Get data.
+ if (m_element_size > 0) {
+ m_start = data_type_finder_sp.get();
+ }
+
+ // Get number of elements.
+ if (auto size_sp = GetChildMemberWithName(
+ m_backend, {ConstString("__size_"), ConstString("__size")})) {
+ m_num_elements = size_sp->GetValueAsUnsigned(0);
+ } else if (auto arg =
+ m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) {
+
+ m_num_elements = arg->value.getLimitedValue();
+ }
+ }
+
+ return lldb::ChildCacheState::eReuse;
+}
+
+bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_start)
+ return UINT32_MAX;
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ CompilerType type = valobj_sp->GetCompilerType();
+ if (!type.IsValid() || type.GetNumTemplateArguments() != 2)
+ return nullptr;
+ return new LibcxxStdSpanSyntheticFrontEnd(valobj_sp);
+}
+
+} // namespace formatters
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
new file mode 100644
index 000000000000..3e3259ab428d
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp
@@ -0,0 +1,95 @@
+//===-- LibCxxTuple.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class TupleFrontEnd: public SyntheticChildrenFrontEnd {
+public:
+ TupleFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
+ Update();
+ }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ return formatters::ExtractIndexFromString(name.GetCString());
+ }
+
+ bool MightHaveChildren() override { return true; }
+ lldb::ChildCacheState Update() override;
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_elements.size();
+ }
+ ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+private:
+ // The lifetime of a ValueObject and all its derivative ValueObjects
+ // (children, clones, etc.) is managed by a ClusterManager. These
+ // objects are only destroyed when every shared pointer to any of them
+ // is destroyed, so we must not store a shared pointer to any ValueObject
+ // derived from our backend ValueObject (since we're in the same cluster).
+ std::vector<ValueObject*> m_elements;
+ ValueObject* m_base = nullptr;
+};
+}
+
+lldb::ChildCacheState TupleFrontEnd::Update() {
+ m_elements.clear();
+ m_base = nullptr;
+
+ ValueObjectSP base_sp;
+ base_sp = m_backend.GetChildMemberWithName("__base_");
+ if (!base_sp) {
+ // Pre r304382 name of the base element.
+ base_sp = m_backend.GetChildMemberWithName("base_");
+ }
+ if (!base_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_base = base_sp.get();
+ m_elements.assign(base_sp->GetCompilerType().GetNumDirectBaseClasses(),
+ nullptr);
+ return lldb::ChildCacheState::eRefetch;
+}
+
+ValueObjectSP TupleFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx >= m_elements.size())
+ return ValueObjectSP();
+ if (!m_base)
+ return ValueObjectSP();
+ if (m_elements[idx])
+ return m_elements[idx]->GetSP();
+
+ CompilerType holder_type =
+ m_base->GetCompilerType().GetDirectBaseClassAtIndex(idx, nullptr);
+ if (!holder_type)
+ return ValueObjectSP();
+ ValueObjectSP holder_sp = m_base->GetChildAtIndex(idx);
+ if (!holder_sp)
+ return ValueObjectSP();
+
+ ValueObjectSP elem_sp = holder_sp->GetChildAtIndex(0);
+ if (elem_sp)
+ m_elements[idx] =
+ elem_sp->Clone(ConstString(llvm::formatv("[{0}]", idx).str())).get();
+
+ if (m_elements[idx])
+ return m_elements[idx]->GetSP();
+ return ValueObjectSP();
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibcxxTupleFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new TupleFrontEnd(*valobj_sp);
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
new file mode 100644
index 000000000000..93e7f4f4fd86
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -0,0 +1,388 @@
+//===-- LibCxxUnorderedMap.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+class LibcxxStdUnorderedMapSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ CompilerType m_element_type;
+ CompilerType m_node_type;
+ ValueObject *m_tree = nullptr;
+ size_t m_num_elements = 0;
+ ValueObject *m_next_element = nullptr;
+ std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
+};
+
+class LibCxxUnorderedMapIteratorSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibCxxUnorderedMapIteratorSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ lldb::ValueObjectSP m_pair_sp; ///< ValueObject for the key/value pair
+ ///< that the iterator currently points
+ ///< to.
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
+ LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(),
+ m_elements_cache() {
+ if (valobj_sp)
+ Update();
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdUnorderedMapSyntheticFrontEnd::CalculateNumChildren() {
+ return m_num_elements;
+}
+
+static void consumeInlineNamespace(llvm::StringRef &name) {
+ // Delete past an inline namespace, if any: __[a-zA-Z0-9_]+::
+ auto scratch = name;
+ if (scratch.consume_front("__") && std::isalnum(scratch[0])) {
+ scratch = scratch.drop_while([](char c) { return std::isalnum(c); });
+ if (scratch.consume_front("::")) {
+ // Successfully consumed a namespace.
+ name = scratch;
+ }
+ }
+}
+
+static bool isStdTemplate(ConstString type_name, llvm::StringRef type) {
+ llvm::StringRef name = type_name.GetStringRef();
+ // The type name may be prefixed with `std::__<inline-namespace>::`.
+ if (name.consume_front("std::"))
+ consumeInlineNamespace(name);
+ return name.consume_front(type) && name.starts_with("<");
+}
+
+static bool isUnorderedMap(ConstString type_name) {
+ return isStdTemplate(type_name, "unordered_map") ||
+ isStdTemplate(type_name, "unordered_multimap");
+}
+
+lldb::ValueObjectSP lldb_private::formatters::
+ LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx >= CalculateNumChildrenIgnoringErrors())
+ return lldb::ValueObjectSP();
+ if (m_tree == nullptr)
+ return lldb::ValueObjectSP();
+
+ while (idx >= m_elements_cache.size()) {
+ if (m_next_element == nullptr)
+ return lldb::ValueObjectSP();
+
+ Status error;
+ ValueObjectSP node_sp = m_next_element->Dereference(error);
+ if (!node_sp || error.Fail())
+ return lldb::ValueObjectSP();
+
+ ValueObjectSP value_sp = node_sp->GetChildMemberWithName("__value_");
+ ValueObjectSP hash_sp = node_sp->GetChildMemberWithName("__hash_");
+ if (!hash_sp || !value_sp) {
+ if (!m_element_type) {
+ auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
+ if (!p1_sp)
+ return nullptr;
+
+ ValueObjectSP first_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
+ if (!first_sp)
+ return nullptr;
+
+ m_element_type = first_sp->GetCompilerType();
+ m_element_type = m_element_type.GetTypeTemplateArgument(0);
+ m_element_type = m_element_type.GetPointeeType();
+ m_node_type = m_element_type;
+ m_element_type = m_element_type.GetTypeTemplateArgument(0);
+ // This synthetic provider is used for both unordered_(multi)map and
+ // unordered_(multi)set. For unordered_map, the element type has an
+ // additional type layer, an internal struct (`__hash_value_type`)
+ // that wraps a std::pair. Peel away the internal wrapper type - whose
+ // structure is of no value to users, to expose the std::pair. This
+ // matches the structure returned by the std::map synthetic provider.
+ if (isUnorderedMap(m_backend.GetTypeName())) {
+ std::string name;
+ CompilerType field_type = m_element_type.GetFieldAtIndex(
+ 0, name, nullptr, nullptr, nullptr);
+ CompilerType actual_type = field_type.GetTypedefedType();
+ if (isStdTemplate(actual_type.GetTypeName(), "pair"))
+ m_element_type = actual_type;
+ }
+ }
+ if (!m_node_type)
+ return nullptr;
+ node_sp = m_next_element->Cast(m_node_type.GetPointerType())
+ ->Dereference(error);
+ if (!node_sp || error.Fail())
+ return nullptr;
+
+ hash_sp = node_sp->GetChildMemberWithName("__hash_");
+ if (!hash_sp)
+ return nullptr;
+
+ value_sp = node_sp->GetChildMemberWithName("__value_");
+ if (!value_sp) {
+ // clang-format off
+ // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an
+ // anonymous union.
+ // Child 0: __hash_node_base base class
+ // Child 1: __hash_
+ // Child 2: anonymous union
+ // clang-format on
+ auto anon_union_sp = node_sp->GetChildAtIndex(2);
+ if (!anon_union_sp)
+ return nullptr;
+
+ value_sp = anon_union_sp->GetChildMemberWithName("__value_");
+ if (!value_sp)
+ return nullptr;
+ }
+ }
+ m_elements_cache.push_back(
+ {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
+ m_next_element = node_sp->GetChildMemberWithName("__next_").get();
+ if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
+ m_next_element = nullptr;
+ }
+
+ std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
+ if (!val_hash.first)
+ return lldb::ValueObjectSP();
+ StreamString stream;
+ stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ DataExtractor data;
+ Status error;
+ val_hash.first->GetData(data, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ const bool thread_and_frame_only_if_stopped = true;
+ ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
+ thread_and_frame_only_if_stopped);
+ return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
+ m_element_type);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() {
+ m_num_elements = 0;
+ m_next_element = nullptr;
+ m_elements_cache.clear();
+ ValueObjectSP table_sp = m_backend.GetChildMemberWithName("__table_");
+ if (!table_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP p2_sp = table_sp->GetChildMemberWithName("__p2_");
+ if (!p2_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
+ if (!num_elements_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP p1_sp = table_sp->GetChildMemberWithName("__p1_");
+ if (!p1_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP value_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
+ if (!value_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_tree = value_sp->GetChildMemberWithName("__next_").get();
+ if (m_tree == nullptr)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
+
+ if (m_num_elements > 0)
+ m_next_element = m_tree;
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ return ExtractIndexFromString(name.GetCString());
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
+
+lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+lldb::ChildCacheState lldb_private::formatters::
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd::Update() {
+ m_pair_sp.reset();
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+
+ if (!target_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Get the unordered_map::iterator
+ // m_backend is an 'unordered_map::iterator', aka a
+ // '__hash_map_iterator<__hash_table::iterator>'
+ //
+ // __hash_map_iterator::__i_ is a __hash_table::iterator (aka
+ // __hash_iterator<__node_pointer>)
+ auto hash_iter_sp = valobj_sp->GetChildMemberWithName("__i_");
+ if (!hash_iter_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ // Type is '__hash_iterator<__node_pointer>'
+ auto hash_iter_type = hash_iter_sp->GetCompilerType();
+ if (!hash_iter_type.IsValid())
+ return lldb::ChildCacheState::eRefetch;
+
+ // Type is '__node_pointer'
+ auto node_pointer_type = hash_iter_type.GetTypeTemplateArgument(0);
+ if (!node_pointer_type.IsValid())
+ return lldb::ChildCacheState::eRefetch;
+
+ // Cast the __hash_iterator to a __node_pointer (which stores our key/value
+ // pair)
+ auto hash_node_sp = hash_iter_sp->Cast(node_pointer_type);
+ if (!hash_node_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ auto key_value_sp = hash_node_sp->GetChildMemberWithName("__value_");
+ if (!key_value_sp) {
+ // clang-format off
+ // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an
+ // anonymous union.
+ // Child 0: __hash_node_base base class
+ // Child 1: __hash_
+ // Child 2: anonymous union
+ // clang-format on
+ auto anon_union_sp = hash_node_sp->GetChildAtIndex(2);
+ if (!anon_union_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ key_value_sp = anon_union_sp->GetChildMemberWithName("__value_");
+ if (!key_value_sp)
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ // Create the synthetic child, which is a pair where the key and value can be
+ // retrieved by querying the synthetic frontend for
+ // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second")
+ // respectively.
+ //
+ // std::unordered_map stores the actual key/value pair in
+ // __hash_value_type::__cc_ (or previously __cc).
+ auto potential_child_sp = key_value_sp->Clone(ConstString("pair"));
+ if (potential_child_sp)
+ if (potential_child_sp->GetNumChildrenIgnoringErrors() == 1)
+ if (auto child0_sp = potential_child_sp->GetChildAtIndex(0);
+ child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc")
+ potential_child_sp = child0_sp->Clone(ConstString("pair"));
+
+ m_pair_sp = potential_child_sp;
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
+ return 2;
+}
+
+lldb::ValueObjectSP lldb_private::formatters::
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (m_pair_sp)
+ return m_pair_sp->GetChildAtIndex(idx);
+ return lldb::ValueObjectSP();
+}
+
+bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (name == "first")
+ return 0;
+ if (name == "second")
+ return 1;
+ return UINT32_MAX;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
new file mode 100644
index 000000000000..99f94406e99a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
@@ -0,0 +1,145 @@
+//===-- LibCxxValarray.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+class LibcxxStdValarraySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdValarraySyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ /// A non-owning pointer to valarray's __begin_ member.
+ ValueObject *m_start = nullptr;
+ /// A non-owning pointer to valarray's __end_ member.
+ ValueObject *m_finish = nullptr;
+ /// The type of valarray's template argument T.
+ CompilerType m_element_type;
+ /// The sizeof valarray's template argument T.
+ uint32_t m_element_size = 0;
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
+ LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
+ ~LibcxxStdValarraySyntheticFrontEnd() {
+ // these need to stay around because they are child objects who will follow
+ // their parent's life cycle
+ // delete m_start;
+ // delete m_finish;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdValarraySyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_start || !m_finish)
+ return 0;
+ uint64_t start_val = m_start->GetValueAsUnsigned(0);
+ uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
+
+ if (start_val == 0 || finish_val == 0)
+ return 0;
+
+ if (start_val >= finish_val)
+ return 0;
+
+ size_t num_children = (finish_val - start_val);
+ if (num_children % m_element_size)
+ return 0;
+ return num_children / m_element_size;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_start || !m_finish)
+ return lldb::ValueObjectSP();
+
+ uint64_t offset = idx * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::Update() {
+ m_start = m_finish = nullptr;
+
+ CompilerType type = m_backend.GetCompilerType();
+ if (type.GetNumTemplateArguments() == 0)
+ return ChildCacheState::eRefetch;
+
+ m_element_type = type.GetTypeTemplateArgument(0);
+ if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr))
+ m_element_size = *size;
+
+ if (m_element_size == 0)
+ return ChildCacheState::eRefetch;
+
+ ValueObjectSP start = m_backend.GetChildMemberWithName("__begin_");
+ ValueObjectSP finish = m_backend.GetChildMemberWithName("__end_");
+
+ if (!start || !finish)
+ return ChildCacheState::eRefetch;
+
+ m_start = start.get();
+ m_finish = finish.get();
+
+ return ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_start || !m_finish)
+ return std::numeric_limits<size_t>::max();
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ return new LibcxxStdValarraySyntheticFrontEnd(valobj_sp);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
new file mode 100644
index 000000000000..62794318e077
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp
@@ -0,0 +1,281 @@
+//===-- LibCxxVariant.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxxVariant.h"
+#include "LibCxx.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+#include "llvm/ADT/ScopeExit.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+// libc++ variant implementation contains two members that we care about both
+// are contained in the __impl member.
+// - __index which tells us which of the variadic template types is the active
+// type for the variant
+// - __data is a variadic union which recursively contains itself as member
+// which refers to the tailing variadic types.
+// - __head which refers to the leading non pack type
+// - __value refers to the actual value contained
+// - __tail which refers to the remaining pack types
+//
+// e.g. given std::variant<int,double,char> v1
+//
+// (lldb) frame var -R v1.__impl.__data
+//(... __union<... 0, int, double, char>) v1.__impl.__data = {
+// ...
+// __head = {
+// __value = ...
+// }
+// __tail = {
+// ...
+// __head = {
+// __value = ...
+// }
+// __tail = {
+// ...
+// __head = {
+// __value = ...
+// ...
+//
+// So given
+// - __index equal to 0 the active value is contained in
+//
+// __data.__head.__value
+//
+// - __index equal to 1 the active value is contained in
+//
+// __data.__tail.__head.__value
+//
+// - __index equal to 2 the active value is contained in
+//
+// __data.__tail.__tail.__head.__value
+//
+
+namespace {
+// libc++ std::variant index could have one of three states
+// 1) Valid, we can obtain it and its not variant_npos
+// 2) Invalid, we can't obtain it or it is not a type we expect
+// 3) NPos, its value is variant_npos which means the variant has no value
+enum class LibcxxVariantIndexValidity { Valid, Invalid, NPos };
+
+uint64_t VariantNposValue(uint64_t index_byte_size) {
+ switch (index_byte_size) {
+ case 1:
+ return static_cast<uint8_t>(-1);
+ case 2:
+ return static_cast<uint16_t>(-1);
+ case 4:
+ return static_cast<uint32_t>(-1);
+ }
+ lldbassert(false && "Unknown index type size");
+ return static_cast<uint32_t>(-1); // Fallback to stable ABI type.
+}
+
+LibcxxVariantIndexValidity
+LibcxxVariantGetIndexValidity(ValueObjectSP &impl_sp) {
+ ValueObjectSP index_sp(impl_sp->GetChildMemberWithName("__index"));
+
+ if (!index_sp)
+ return LibcxxVariantIndexValidity::Invalid;
+
+ // In the stable ABI, the type of __index is just int.
+ // In the unstable ABI, where _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION is
+ // enabled, the type can either be unsigned char/short/int depending on
+ // how many variant types there are.
+ // We only need to do this here when comparing against npos, because npos is
+ // just `-1`, but that translates to different unsigned values depending on
+ // the byte size.
+ CompilerType index_type = index_sp->GetCompilerType();
+
+ std::optional<uint64_t> index_type_bytes = index_type.GetByteSize(nullptr);
+ if (!index_type_bytes)
+ return LibcxxVariantIndexValidity::Invalid;
+
+ uint64_t npos_value = VariantNposValue(*index_type_bytes);
+ uint64_t index_value = index_sp->GetValueAsUnsigned(0);
+
+ if (index_value == npos_value)
+ return LibcxxVariantIndexValidity::NPos;
+
+ return LibcxxVariantIndexValidity::Valid;
+}
+
+std::optional<uint64_t> LibcxxVariantIndexValue(ValueObjectSP &impl_sp) {
+ ValueObjectSP index_sp(impl_sp->GetChildMemberWithName("__index"));
+
+ if (!index_sp)
+ return {};
+
+ return {index_sp->GetValueAsUnsigned(0)};
+}
+
+ValueObjectSP LibcxxVariantGetNthHead(ValueObjectSP &impl_sp, uint64_t index) {
+ ValueObjectSP data_sp(impl_sp->GetChildMemberWithName("__data"));
+
+ if (!data_sp)
+ return ValueObjectSP{};
+
+ ValueObjectSP current_level = data_sp;
+ for (uint64_t n = index; n != 0; --n) {
+ ValueObjectSP tail_sp(current_level->GetChildMemberWithName("__tail"));
+
+ if (!tail_sp)
+ return ValueObjectSP{};
+
+ current_level = tail_sp;
+ }
+
+ return current_level->GetChildMemberWithName("__head");
+}
+} // namespace
+
+namespace lldb_private {
+namespace formatters {
+bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+
+ ValueObjectSP impl_sp = GetChildMemberWithName(
+ *valobj_sp, {ConstString("__impl_"), ConstString("__impl")});
+
+ if (!impl_sp)
+ return false;
+
+ LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
+
+ if (validity == LibcxxVariantIndexValidity::Invalid)
+ return false;
+
+ if (validity == LibcxxVariantIndexValidity::NPos) {
+ stream.Printf(" No Value");
+ return true;
+ }
+
+ auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
+
+ if (!optional_index_value)
+ return false;
+
+ uint64_t index_value = *optional_index_value;
+
+ ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
+
+ if (!nth_head)
+ return false;
+
+ CompilerType head_type = nth_head->GetCompilerType();
+
+ if (!head_type)
+ return false;
+
+ CompilerType template_type = head_type.GetTypeTemplateArgument(1);
+
+ if (!template_type)
+ return false;
+
+ stream << " Active Type = " << template_type.GetDisplayTypeName() << " ";
+
+ return true;
+}
+} // namespace formatters
+} // namespace lldb_private
+
+namespace {
+class VariantFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) {
+ Update();
+ }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ return formatters::ExtractIndexFromString(name.GetCString());
+ }
+
+ bool MightHaveChildren() override { return true; }
+ lldb::ChildCacheState Update() override;
+ llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; }
+ ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+private:
+ size_t m_size = 0;
+};
+} // namespace
+
+lldb::ChildCacheState VariantFrontEnd::Update() {
+ m_size = 0;
+ ValueObjectSP impl_sp = formatters::GetChildMemberWithName(
+ m_backend, {ConstString("__impl_"), ConstString("__impl")});
+ if (!impl_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp);
+
+ if (validity == LibcxxVariantIndexValidity::Invalid)
+ return lldb::ChildCacheState::eRefetch;
+
+ if (validity == LibcxxVariantIndexValidity::NPos)
+ return lldb::ChildCacheState::eReuse;
+
+ m_size = 1;
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+ValueObjectSP VariantFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx >= m_size)
+ return {};
+
+ ValueObjectSP impl_sp = formatters::GetChildMemberWithName(
+ m_backend, {ConstString("__impl_"), ConstString("__impl")});
+ if (!impl_sp)
+ return {};
+
+ auto optional_index_value = LibcxxVariantIndexValue(impl_sp);
+
+ if (!optional_index_value)
+ return {};
+
+ uint64_t index_value = *optional_index_value;
+
+ ValueObjectSP nth_head = LibcxxVariantGetNthHead(impl_sp, index_value);
+
+ if (!nth_head)
+ return {};
+
+ CompilerType head_type = nth_head->GetCompilerType();
+
+ if (!head_type)
+ return {};
+
+ CompilerType template_type = head_type.GetTypeTemplateArgument(1);
+
+ if (!template_type)
+ return {};
+
+ ValueObjectSP head_value(nth_head->GetChildMemberWithName("__value"));
+
+ if (!head_value)
+ return {};
+
+ return head_value->Clone(ConstString("Value"));
+}
+
+SyntheticChildrenFrontEnd *
+formatters::LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP valobj_sp) {
+ if (valobj_sp)
+ return new VariantFrontEnd(*valobj_sp);
+ return nullptr;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h
new file mode 100644
index 000000000000..9488d94efda7
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.h
@@ -0,0 +1,29 @@
+//===-- LibCxxVariant.h ----------------------------------------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXVARIANT_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXVARIANT_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+bool LibcxxVariantSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libc++ std::variant<>
+
+SyntheticChildrenFrontEnd *LibcxxVariantFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBCXXVARIANT_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
new file mode 100644
index 000000000000..461fed35164b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -0,0 +1,279 @@
+//===-- LibCxxVector.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibCxx.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Utility/ConstString.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace lldb_private {
+namespace formatters {
+class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibcxxStdVectorSyntheticFrontEnd() override;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ValueObject *m_start = nullptr;
+ ValueObject *m_finish = nullptr;
+ CompilerType m_element_type;
+ uint32_t m_element_size = 0;
+};
+
+class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override { return true; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ CompilerType m_bool_type;
+ ExecutionContextRef m_exe_ctx_ref;
+ uint64_t m_count = 0;
+ lldb::addr_t m_base_data_address = 0;
+ std::map<size_t, lldb::ValueObjectSP> m_children;
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
+ LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
+ ~LibcxxStdVectorSyntheticFrontEnd() {
+ // these need to stay around because they are child objects who will follow
+ // their parent's life cycle
+ // delete m_start;
+ // delete m_finish;
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
+ if (!m_start || !m_finish)
+ return 0;
+ uint64_t start_val = m_start->GetValueAsUnsigned(0);
+ uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
+
+ if (start_val == 0 || finish_val == 0)
+ return 0;
+
+ if (start_val >= finish_val)
+ return 0;
+
+ size_t num_children = (finish_val - start_val);
+ if (num_children % m_element_size)
+ return 0;
+ return num_children / m_element_size;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ if (!m_start || !m_finish)
+ return lldb::ValueObjectSP();
+
+ uint64_t offset = idx * m_element_size;
+ offset = offset + m_start->GetValueAsUnsigned(0);
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ return CreateValueObjectFromAddress(name.GetString(), offset,
+ m_backend.GetExecutionContextRef(),
+ m_element_type);
+}
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
+ m_start = m_finish = nullptr;
+ ValueObjectSP data_type_finder_sp(
+ m_backend.GetChildMemberWithName("__end_cap_"));
+ if (!data_type_finder_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ data_type_finder_sp =
+ GetFirstValueOfLibCXXCompressedPair(*data_type_finder_sp);
+ if (!data_type_finder_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
+ if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
+ m_element_size = *size;
+
+ if (m_element_size > 0) {
+ // store raw pointers or end up with a circular dependency
+ m_start = m_backend.GetChildMemberWithName("__begin_").get();
+ m_finish = m_backend.GetChildMemberWithName("__end_").get();
+ }
+ }
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_start || !m_finish)
+ return UINT32_MAX;
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
+ LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(),
+ m_children() {
+ if (valobj_sp) {
+ Update();
+ m_bool_type =
+ valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
+ }
+}
+
+llvm::Expected<uint32_t> lldb_private::formatters::
+ LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren() {
+ return m_count;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
+ uint32_t idx) {
+ auto iter = m_children.find(idx), end = m_children.end();
+ if (iter != end)
+ return iter->second;
+ if (idx >= m_count)
+ return {};
+ if (m_base_data_address == 0 || m_count == 0)
+ return {};
+ if (!m_bool_type)
+ return {};
+ size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
+ size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
+ lldb::addr_t byte_location = m_base_data_address + byte_idx;
+ ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
+ if (!process_sp)
+ return {};
+ uint8_t byte = 0;
+ uint8_t mask = 0;
+ Status err;
+ size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
+ if (err.Fail() || bytes_read == 0)
+ return {};
+ mask = 1 << bit_index;
+ bool bit_set = ((byte & mask) != 0);
+ std::optional<uint64_t> size = m_bool_type.GetByteSize(nullptr);
+ if (!size)
+ return {};
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
+ if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
+ // regardless of endianness, anything non-zero is true
+ *(buffer_sp->GetBytes()) = 1;
+ }
+ StreamString name;
+ name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ ValueObjectSP retval_sp(CreateValueObjectFromData(
+ name.GetString(),
+ DataExtractor(buffer_sp, process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize()),
+ m_exe_ctx_ref, m_bool_type));
+ if (retval_sp)
+ m_children[idx] = retval_sp;
+ return retval_sp;
+}
+
+/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
+ __begin_ = 0x00000001001000e0
+ __size_ = 56
+ __cap_alloc_ = {
+ std::__1::__libcpp_compressed_pair_imp<unsigned long,
+ std::__1::allocator<unsigned long> > = {
+ __first_ = 1
+ }
+ }
+ }*/
+
+lldb::ChildCacheState
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() {
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_"));
+ if (!size_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_count = size_sp->GetValueAsUnsigned(0);
+ if (!m_count)
+ return lldb::ChildCacheState::eReuse;
+ ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_"));
+ if (!begin_sp) {
+ m_count = 0;
+ return lldb::ChildCacheState::eRefetch;
+ }
+ m_base_data_address = begin_sp->GetValueAsUnsigned(0);
+ if (!m_base_data_address) {
+ m_count = 0;
+ return lldb::ChildCacheState::eRefetch;
+ }
+ return lldb::ChildCacheState::eRefetch;
+}
+
+size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (!m_count || !m_base_data_address)
+ return UINT32_MAX;
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ CompilerType type = valobj_sp->GetCompilerType();
+ if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
+ return nullptr;
+ CompilerType arg_type = type.GetTypeTemplateArgument(0);
+ if (arg_type.GetTypeName() == "bool")
+ return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
+ return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
new file mode 100644
index 000000000000..86bb575af5ca
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -0,0 +1,472 @@
+//===-- LibStdcpp.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibStdcpp.h"
+#include "LibCxx.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/StringPrinter.h"
+#include "lldb/DataFormatters/VectorIterator.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/Stream.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace {
+
+class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+ /*
+ (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
+ std::char_traits<char>, std::allocator<char> > > >) ibeg = {
+ (_Base_ptr) _M_node = 0x0000000100103910 {
+ (std::_Rb_tree_color) _M_color = _S_black
+ (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
+ (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
+ (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
+ }
+ }
+ */
+
+public:
+ explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ExecutionContextRef m_exe_ctx_ref;
+ lldb::addr_t m_pair_address = 0;
+ CompilerType m_pair_type;
+ lldb::ValueObjectSP m_pair_sp;
+};
+
+class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+private:
+
+ // The lifetime of a ValueObject and all its derivative ValueObjects
+ // (children, clones, etc.) is managed by a ClusterManager. These
+ // objects are only destroyed when every shared pointer to any of them
+ // is destroyed, so we must not store a shared pointer to any ValueObject
+ // derived from our backend ValueObject (since we're in the same cluster).
+ ValueObject* m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
+ ValueObject* m_obj_obj = nullptr; // Underlying object (held, not owned)
+};
+
+} // end of anonymous namespace
+
+LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
+ m_pair_sp() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+
+ if (!target_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
+
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+ ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
+ if (!_M_node_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
+ if (m_pair_address == 0)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_pair_address += (is_64bit ? 32 : 16);
+
+ CompilerType my_type(valobj_sp->GetCompilerType());
+ if (my_type.GetNumTemplateArguments() >= 1) {
+ CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
+ if (!pair_type)
+ return lldb::ChildCacheState::eRefetch;
+ m_pair_type = pair_type;
+ } else
+ return lldb::ChildCacheState::eRefetch;
+
+ return lldb::ChildCacheState::eReuse;
+}
+
+llvm::Expected<uint32_t>
+LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
+ return 2;
+}
+
+lldb::ValueObjectSP
+LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (m_pair_address != 0 && m_pair_type) {
+ if (!m_pair_sp)
+ m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
+ m_exe_ctx_ref, m_pair_type);
+ if (m_pair_sp)
+ return m_pair_sp->GetChildAtIndex(idx);
+ }
+ return lldb::ValueObjectSP();
+}
+
+bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
+
+size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ if (name == "first")
+ return 0;
+ if (name == "second")
+ return 1;
+ return UINT32_MAX;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
+
+/*
+ (lldb) fr var ibeg --ptr-depth 1
+ (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
+ ibeg = {
+ _M_current = 0x00000001001037a0 {
+ *_M_current = 1
+ }
+ }
+ */
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
+ valobj_sp, {ConstString("_M_current")})
+ : nullptr);
+}
+
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::
+ VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,
+ llvm::ArrayRef<ConstString> item_names)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
+ m_item_names(item_names), m_item_sp() {
+ if (valobj_sp)
+ Update();
+}
+
+lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() {
+ m_item_sp.reset();
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP item_ptr =
+ formatters::GetChildMemberWithName(*valobj_sp, m_item_names);
+ if (!item_ptr)
+ return lldb::ChildCacheState::eRefetch;
+ if (item_ptr->GetValueAsUnsigned(0) == 0)
+ return lldb::ChildCacheState::eRefetch;
+ Status err;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ m_item_sp = CreateValueObjectFromAddress(
+ "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
+ item_ptr->GetCompilerType().GetPointeeType());
+ if (err.Fail())
+ m_item_sp.reset();
+ return lldb::ChildCacheState::eRefetch;
+}
+
+llvm::Expected<uint32_t>
+VectorIteratorSyntheticFrontEnd::CalculateNumChildren() {
+ return 1;
+}
+
+lldb::ValueObjectSP
+VectorIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx == 0)
+ return m_item_sp;
+ return lldb::ValueObjectSP();
+}
+
+bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
+
+size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ if (name == "item")
+ return 0;
+ return UINT32_MAX;
+}
+
+bool lldb_private::formatters::LibStdcppStringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ const bool scalar_is_load_addr = true;
+ AddressType addr_type;
+ lldb::addr_t addr_of_string = LLDB_INVALID_ADDRESS;
+ if (valobj.IsPointerOrReferenceType()) {
+ Status error;
+ ValueObjectSP pointee_sp = valobj.Dereference(error);
+ if (pointee_sp && error.Success())
+ addr_of_string = pointee_sp->GetAddressOf(scalar_is_load_addr, &addr_type);
+ } else
+ addr_of_string =
+ valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
+ if (addr_of_string != LLDB_INVALID_ADDRESS) {
+ switch (addr_type) {
+ case eAddressTypeLoad: {
+ ProcessSP process_sp(valobj.GetProcessSP());
+ if (!process_sp)
+ return false;
+
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
+ Status error;
+ lldb::addr_t addr_of_data =
+ process_sp->ReadPointerFromMemory(addr_of_string, error);
+ if (error.Fail() || addr_of_data == 0 ||
+ addr_of_data == LLDB_INVALID_ADDRESS)
+ return false;
+ options.SetLocation(addr_of_data);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetNeedsZeroTermination(false);
+ options.SetBinaryZeroIsTerminator(true);
+ lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
+ addr_of_string + process_sp->GetAddressByteSize(), error);
+ if (error.Fail())
+ return false;
+ options.SetSourceSize(size_of_data);
+ options.SetHasSourceSize(true);
+
+ if (!StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF8>(options)) {
+ stream.Printf("Summary Unavailable");
+ return true;
+ } else
+ return true;
+ } break;
+ case eAddressTypeHost:
+ break;
+ case eAddressTypeInvalid:
+ case eAddressTypeFile:
+ break;
+ }
+ }
+ return false;
+}
+
+bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ const bool scalar_is_load_addr = true;
+ AddressType addr_type;
+ lldb::addr_t addr_of_string =
+ valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
+ if (addr_of_string != LLDB_INVALID_ADDRESS) {
+ switch (addr_type) {
+ case eAddressTypeLoad: {
+ ProcessSP process_sp(valobj.GetProcessSP());
+ if (!process_sp)
+ return false;
+
+ CompilerType wchar_compiler_type =
+ valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
+
+ if (!wchar_compiler_type)
+ return false;
+
+ // Safe to pass nullptr for exe_scope here.
+ std::optional<uint64_t> size = wchar_compiler_type.GetBitSize(nullptr);
+ if (!size)
+ return false;
+ const uint32_t wchar_size = *size;
+
+ StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
+ Status error;
+ lldb::addr_t addr_of_data =
+ process_sp->ReadPointerFromMemory(addr_of_string, error);
+ if (error.Fail() || addr_of_data == 0 ||
+ addr_of_data == LLDB_INVALID_ADDRESS)
+ return false;
+ options.SetLocation(addr_of_data);
+ options.SetTargetSP(valobj.GetTargetSP());
+ options.SetStream(&stream);
+ options.SetNeedsZeroTermination(false);
+ options.SetBinaryZeroIsTerminator(false);
+ lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
+ addr_of_string + process_sp->GetAddressByteSize(), error);
+ if (error.Fail())
+ return false;
+ options.SetSourceSize(size_of_data);
+ options.SetHasSourceSize(true);
+ options.SetPrefixToken("L");
+
+ switch (wchar_size) {
+ case 8:
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF8>(options);
+ case 16:
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF16>(options);
+ case 32:
+ return StringPrinter::ReadStringAndDumpToStream<
+ StringPrinter::StringElementType::UTF32>(options);
+ default:
+ stream.Printf("size for wchar_t is not valid");
+ return true;
+ }
+ return true;
+ } break;
+ case eAddressTypeHost:
+ break;
+ case eAddressTypeInvalid:
+ case eAddressTypeFile:
+ break;
+ }
+ }
+ return false;
+}
+
+LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+llvm::Expected<uint32_t>
+LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
+ return 1;
+}
+
+lldb::ValueObjectSP
+LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx == 0)
+ return m_ptr_obj->GetSP();
+ if (idx == 1) {
+ if (m_ptr_obj && !m_obj_obj) {
+ Status error;
+ ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
+ if (error.Success())
+ m_obj_obj = obj_obj->Clone(ConstString("object")).get();
+ }
+ if (m_obj_obj)
+ return m_obj_obj->GetSP();
+ }
+ return lldb::ValueObjectSP();
+}
+
+lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {
+ auto backend = m_backend.GetSP();
+ if (!backend)
+ return lldb::ChildCacheState::eRefetch;
+
+ auto valobj_sp = backend->GetNonSyntheticValue();
+ if (!valobj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
+ if (!ptr_obj_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get();
+ m_obj_obj = nullptr;
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }
+
+size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ if (name == "pointer")
+ return 0;
+ if (name == "object" || name == "$$dereference$$")
+ return 1;
+ return UINT32_MAX;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
+
+bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
+ if (!valobj_sp)
+ return false;
+
+ ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
+ if (!ptr_sp)
+ return false;
+
+ ValueObjectSP usecount_sp(
+ valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"}));
+ if (!usecount_sp)
+ return false;
+
+ if (ptr_sp->GetValueAsUnsigned(0) == 0 ||
+ usecount_sp->GetValueAsUnsigned(0) == 0) {
+ stream.Printf("nullptr");
+ return true;
+ }
+
+ Status error;
+ ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
+ if (pointee_sp && error.Success()) {
+ if (pointee_sp->DumpPrintableRepresentation(
+ stream, ValueObject::eValueObjectRepresentationStyleSummary,
+ lldb::eFormatInvalid,
+ ValueObject::PrintableRepresentationSpecialCases::eDisable,
+ false)) {
+ return true;
+ }
+ }
+
+ stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
+ return true;
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
new file mode 100644
index 000000000000..1c1c8fdb9ea4
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
@@ -0,0 +1,67 @@
+//===-- LibStdcpp.h ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBSTDCPP_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBSTDCPP_H
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/Stream.h"
+
+namespace lldb_private {
+namespace formatters {
+bool LibStdcppStringSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libcstdc++ c++11 std::string
+
+bool LibStdcppWStringSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libcstdc++ c++11 std::wstring
+
+bool LibStdcppSmartPointerSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions
+ &options); // libstdc++ std::shared_ptr<> and std::weak_ptr<>
+
+bool LibStdcppUniquePointerSummaryProvider(
+ ValueObject &valobj, Stream &stream,
+ const TypeSummaryOptions &options); // libstdc++ std::unique_ptr<>
+
+SyntheticChildrenFrontEnd *
+LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibStdcppTupleSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibStdcppBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibStdcppOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+SyntheticChildrenFrontEnd *
+LibStdcppUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
+} // namespace formatters
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_LIBSTDCPP_H
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
new file mode 100644
index 000000000000..05199ba35b9a
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
@@ -0,0 +1,112 @@
+//===-- LibStdcppTuple.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibStdcpp.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
+
+#include <memory>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace {
+
+class LibStdcppTupleSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ explicit LibStdcppTupleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ // The lifetime of a ValueObject and all its derivative ValueObjects
+ // (children, clones, etc.) is managed by a ClusterManager. These
+ // objects are only destroyed when every shared pointer to any of them
+ // is destroyed, so we must not store a shared pointer to any ValueObject
+ // derived from our backend ValueObject (since we're in the same cluster).
+ std::vector<ValueObject*> m_members;
+};
+
+} // end of anonymous namespace
+
+LibStdcppTupleSyntheticFrontEnd::LibStdcppTupleSyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ Update();
+}
+
+lldb::ChildCacheState LibStdcppTupleSyntheticFrontEnd::Update() {
+ m_members.clear();
+
+ ValueObjectSP valobj_backend_sp = m_backend.GetSP();
+ if (!valobj_backend_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ ValueObjectSP next_child_sp = valobj_backend_sp->GetNonSyntheticValue();
+ while (next_child_sp != nullptr) {
+ ValueObjectSP current_child = next_child_sp;
+ next_child_sp = nullptr;
+
+ size_t child_count = current_child->GetNumChildrenIgnoringErrors();
+ for (size_t i = 0; i < child_count; ++i) {
+ ValueObjectSP child_sp = current_child->GetChildAtIndex(i);
+ llvm::StringRef name_str = child_sp->GetName().GetStringRef();
+ if (name_str.starts_with("std::_Tuple_impl<")) {
+ next_child_sp = child_sp;
+ } else if (name_str.starts_with("std::_Head_base<")) {
+ ValueObjectSP value_sp =
+ child_sp->GetChildMemberWithName("_M_head_impl");
+ if (value_sp) {
+ StreamString name;
+ name.Printf("[%zd]", m_members.size());
+ m_members.push_back(value_sp->Clone(ConstString(name.GetString())).get());
+ }
+ }
+ }
+ }
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool LibStdcppTupleSyntheticFrontEnd::MightHaveChildren() { return true; }
+
+lldb::ValueObjectSP
+LibStdcppTupleSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx < m_members.size() && m_members[idx])
+ return m_members[idx]->GetSP();
+ return lldb::ValueObjectSP();
+}
+
+llvm::Expected<uint32_t>
+LibStdcppTupleSyntheticFrontEnd::CalculateNumChildren() {
+ return m_members.size();
+}
+
+size_t LibStdcppTupleSyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ return ExtractIndexFromString(name.GetCString());
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibStdcppTupleSyntheticFrontEnd(valobj_sp) : nullptr);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp
new file mode 100644
index 000000000000..92f540d9ca52
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp
@@ -0,0 +1,183 @@
+//===-- LibStdcppUniquePointer.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LibStdcpp.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Utility/ConstString.h"
+
+#include <memory>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+namespace {
+
+class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
+
+ lldb::ChildCacheState Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+ bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
+
+private:
+ // The lifetime of a ValueObject and all its derivative ValueObjects
+ // (children, clones, etc.) is managed by a ClusterManager. These
+ // objects are only destroyed when every shared pointer to any of them
+ // is destroyed, so we must not store a shared pointer to any ValueObject
+ // derived from our backend ValueObject (since we're in the same cluster).
+ ValueObject* m_ptr_obj = nullptr;
+ ValueObject* m_obj_obj = nullptr;
+ ValueObject* m_del_obj = nullptr;
+
+ ValueObjectSP GetTuple();
+};
+
+} // end of anonymous namespace
+
+LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(
+ lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ Update();
+}
+
+ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() {
+ ValueObjectSP valobj_backend_sp = m_backend.GetSP();
+
+ if (!valobj_backend_sp)
+ return nullptr;
+
+ ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
+ if (!valobj_sp)
+ return nullptr;
+
+ ValueObjectSP obj_child_sp = valobj_sp->GetChildMemberWithName("_M_t");
+ if (!obj_child_sp)
+ return nullptr;
+
+ ValueObjectSP obj_subchild_sp = obj_child_sp->GetChildMemberWithName("_M_t");
+
+ // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp
+ // (for libstdc++ 6.0.23).
+ if (obj_subchild_sp) {
+ return obj_subchild_sp;
+ }
+
+ return obj_child_sp;
+}
+
+lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() {
+ ValueObjectSP tuple_sp = GetTuple();
+
+ if (!tuple_sp)
+ return lldb::ChildCacheState::eRefetch;
+
+ std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
+ LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
+
+ ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);
+ if (ptr_obj)
+ m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get();
+
+ // Add a 'deleter' child if there was a non-empty deleter type specified.
+ //
+ // The object might have size=1 in the TypeSystem but occupies no dedicated
+ // storage due to no_unique_address, so infer the actual size from the total
+ // size of the unique_ptr class. If sizeof(unique_ptr) == sizeof(void*) then
+ // the deleter is empty and should be hidden.
+ if (tuple_sp->GetByteSize() > ptr_obj->GetByteSize()) {
+ ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);
+ if (del_obj)
+ m_del_obj = del_obj->Clone(ConstString("deleter")).get();
+ }
+ m_obj_obj = nullptr;
+
+ return lldb::ChildCacheState::eRefetch;
+}
+
+bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; }
+
+lldb::ValueObjectSP
+LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (idx == 0 && m_ptr_obj)
+ return m_ptr_obj->GetSP();
+ if (idx == 1 && m_del_obj)
+ return m_del_obj->GetSP();
+ if (idx == 2) {
+ if (m_ptr_obj && !m_obj_obj) {
+ Status error;
+ ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
+ if (error.Success()) {
+ m_obj_obj = obj_obj->Clone(ConstString("object")).get();
+ }
+ }
+ if (m_obj_obj)
+ return m_obj_obj->GetSP();
+ }
+ return lldb::ValueObjectSP();
+}
+
+llvm::Expected<uint32_t>
+LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
+ if (m_del_obj)
+ return 2;
+ return 1;
+}
+
+size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ if (name == "ptr" || name == "pointer")
+ return 0;
+ if (name == "del" || name == "deleter")
+ return 1;
+ if (name == "obj" || name == "object" || name == "$$dereference$$")
+ return 2;
+ return UINT32_MAX;
+}
+
+bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
+ Stream &stream, const TypeSummaryOptions &options) {
+ if (!m_ptr_obj)
+ return false;
+
+ bool success;
+ uint64_t ptr_value = m_ptr_obj->GetValueAsUnsigned(0, &success);
+ if (!success)
+ return false;
+ if (ptr_value == 0)
+ stream.Printf("nullptr");
+ else
+ stream.Printf("0x%" PRIx64, ptr_value);
+ return true;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
+
+bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
+ return formatter.GetSummary(stream, options);
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp
new file mode 100644
index 000000000000..72afc6fe75ac
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.cpp
@@ -0,0 +1,105 @@
+//===-- MSVCUndecoratedNameParser.cpp -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "MSVCUndecoratedNameParser.h"
+
+#include <stack>
+
+MSVCUndecoratedNameParser::MSVCUndecoratedNameParser(llvm::StringRef name) {
+ // Global ctor and dtor are global functions.
+ if (name.contains("dynamic initializer for") ||
+ name.contains("dynamic atexit destructor for")) {
+ m_specifiers.emplace_back(name, name);
+ return;
+ }
+
+ std::size_t last_base_start = 0;
+
+ std::stack<std::size_t> stack;
+ unsigned int open_angle_brackets = 0;
+ for (size_t i = 0; i < name.size(); i++) {
+ switch (name[i]) {
+ case '<':
+ // Do not treat `operator<' and `operator<<' as templates
+ // (sometimes they represented as `<' and `<<' in the name).
+ if (i == last_base_start ||
+ (i == last_base_start + 1 && name[last_base_start] == '<'))
+ break;
+
+ stack.push(i);
+ open_angle_brackets++;
+
+ break;
+ case '>':
+ if (!stack.empty() && name[stack.top()] == '<') {
+ open_angle_brackets--;
+ stack.pop();
+ }
+
+ break;
+ case '`':
+ stack.push(i);
+
+ break;
+ case '\'':
+ while (!stack.empty()) {
+ std::size_t top = stack.top();
+ if (name[top] == '<')
+ open_angle_brackets--;
+
+ stack.pop();
+
+ if (name[top] == '`')
+ break;
+ }
+
+ break;
+ case ':':
+ if (open_angle_brackets)
+ break;
+ if (i == 0 || name[i - 1] != ':')
+ break;
+
+ m_specifiers.emplace_back(name.take_front(i - 1),
+ name.slice(last_base_start, i - 1));
+
+ last_base_start = i + 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ m_specifiers.emplace_back(name, name.drop_front(last_base_start));
+}
+
+bool MSVCUndecoratedNameParser::IsMSVCUndecoratedName(llvm::StringRef name) {
+ return name.contains('`');
+}
+
+bool MSVCUndecoratedNameParser::ExtractContextAndIdentifier(
+ llvm::StringRef name, llvm::StringRef &context,
+ llvm::StringRef &identifier) {
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+
+ std::size_t count = specs.size();
+ identifier = count > 0 ? specs[count - 1].GetBaseName() : "";
+ context = count > 1 ? specs[count - 2].GetFullName() : "";
+
+ return count;
+}
+
+llvm::StringRef MSVCUndecoratedNameParser::DropScope(llvm::StringRef name) {
+ MSVCUndecoratedNameParser parser(name);
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+ if (specs.empty())
+ return "";
+
+ return specs[specs.size() - 1].GetBaseName();
+}
diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h
new file mode 100644
index 000000000000..e5b60a0a1d5b
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h
@@ -0,0 +1,50 @@
+//===-- MSVCUndecoratedNameParser.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCUNDECORATEDNAMEPARSER_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCUNDECORATEDNAMEPARSER_H
+
+#include <vector>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+class MSVCUndecoratedNameSpecifier {
+public:
+ MSVCUndecoratedNameSpecifier(llvm::StringRef full_name,
+ llvm::StringRef base_name)
+ : m_full_name(full_name), m_base_name(base_name) {}
+
+ llvm::StringRef GetFullName() const { return m_full_name; }
+ llvm::StringRef GetBaseName() const { return m_base_name; }
+
+private:
+ llvm::StringRef m_full_name;
+ llvm::StringRef m_base_name;
+};
+
+class MSVCUndecoratedNameParser {
+public:
+ explicit MSVCUndecoratedNameParser(llvm::StringRef name);
+
+ llvm::ArrayRef<MSVCUndecoratedNameSpecifier> GetSpecifiers() const {
+ return m_specifiers;
+ }
+
+ static bool IsMSVCUndecoratedName(llvm::StringRef name);
+ static bool ExtractContextAndIdentifier(llvm::StringRef name,
+ llvm::StringRef &context,
+ llvm::StringRef &identifier);
+
+ static llvm::StringRef DropScope(llvm::StringRef name);
+
+private:
+ std::vector<MSVCUndecoratedNameSpecifier> m_specifiers;
+};
+
+#endif