aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/DataFormatters
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/DataFormatters')
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/CXXFunctionPointer.cpp87
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/DataVisualization.cpp196
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/DumpValueObjectOptions.cpp214
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp113
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/FormatClasses.cpp49
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp795
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/FormattersHelpers.cpp128
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/LanguageCategory.cpp136
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/StringPrinter.cpp560
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/TypeCategory.cpp334
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp265
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/TypeFormat.cpp205
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp203
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp251
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp886
-rw-r--r--contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp335
16 files changed, 4757 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/CXXFunctionPointer.cpp b/contrib/llvm-project/lldb/source/DataFormatters/CXXFunctionPointer.cpp
new file mode 100644
index 000000000000..6543433d17ff
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/CXXFunctionPointer.cpp
@@ -0,0 +1,87 @@
+//===-- CXXFunctionPointer.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 "lldb/DataFormatters/CXXFunctionPointer.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-enumerations.h"
+
+#include <string>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool lldb_private::formatters::CXXFunctionPointerSummaryProvider(
+ ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+ std::string destination;
+ StreamString sstr;
+ AddressType func_ptr_address_type = eAddressTypeInvalid;
+ addr_t func_ptr_address = valobj.GetPointerValue(&func_ptr_address_type);
+ if (func_ptr_address != 0 && func_ptr_address != LLDB_INVALID_ADDRESS) {
+ switch (func_ptr_address_type) {
+ case eAddressTypeInvalid:
+ case eAddressTypeFile:
+ case eAddressTypeHost:
+ break;
+
+ case eAddressTypeLoad: {
+ ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
+
+ Address so_addr;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target && !target->GetSectionLoadList().IsEmpty()) {
+ target->GetSectionLoadList().ResolveLoadAddress(func_ptr_address,
+ so_addr);
+ if (so_addr.GetSection() == nullptr) {
+ // If we have an address that doesn't correspond to any symbol,
+ // it might have authentication bits. Strip them & see if it
+ // now points to a symbol -- if so, do the SymbolContext lookup
+ // based on the stripped address.
+ // If we find a symbol with the ptrauth bits stripped, print the
+ // raw value into the stream, and replace the Address with the
+ // one that points to a symbol for a fuller description.
+ if (Process *process = exe_ctx.GetProcessPtr()) {
+ if (ABISP abi_sp = process->GetABI()) {
+ addr_t fixed_addr = abi_sp->FixCodeAddress(func_ptr_address);
+ if (fixed_addr != func_ptr_address) {
+ Address test_address;
+ test_address.SetLoadAddress(fixed_addr, target);
+ if (test_address.GetSection() != nullptr) {
+ int addrsize = target->GetArchitecture().GetAddressByteSize();
+ sstr.Printf("actual=0x%*.*" PRIx64 " ", addrsize * 2,
+ addrsize * 2, fixed_addr);
+ so_addr = test_address;
+ }
+ }
+ }
+ }
+ }
+
+ if (so_addr.IsValid()) {
+ so_addr.Dump(&sstr, exe_ctx.GetBestExecutionContextScope(),
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleSectionNameOffset);
+ }
+ }
+ } break;
+ }
+ }
+ if (sstr.GetSize() > 0) {
+ if (valobj.GetValueType() == lldb::eValueTypeVTableEntry)
+ stream.PutCString(sstr.GetData());
+ else
+ stream.Printf("(%s)", sstr.GetData());
+ return true;
+ } else
+ return false;
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/DataVisualization.cpp b/contrib/llvm-project/lldb/source/DataFormatters/DataVisualization.cpp
new file mode 100644
index 000000000000..036c9372baf8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/DataVisualization.cpp
@@ -0,0 +1,196 @@
+//===-- DataVisualization.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 "lldb/DataFormatters/DataVisualization.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+static FormatManager &GetFormatManager() {
+ static FormatManager g_format_manager;
+ return g_format_manager;
+}
+
+void DataVisualization::ForceUpdate() { GetFormatManager().Changed(); }
+
+uint32_t DataVisualization::GetCurrentRevision() {
+ return GetFormatManager().GetCurrentRevision();
+}
+
+bool DataVisualization::ShouldPrintAsOneLiner(ValueObject &valobj) {
+ return GetFormatManager().ShouldPrintAsOneLiner(valobj);
+}
+
+lldb::TypeFormatImplSP
+DataVisualization::GetFormat(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ return GetFormatManager().GetFormat(valobj, use_dynamic);
+}
+
+lldb::TypeFormatImplSP
+DataVisualization::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return GetFormatManager().GetFormatForType(type_sp);
+}
+
+lldb::TypeSummaryImplSP
+DataVisualization::GetSummaryFormat(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ return GetFormatManager().GetSummaryFormat(valobj, use_dynamic);
+}
+
+lldb::TypeSummaryImplSP
+DataVisualization::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return GetFormatManager().GetSummaryForType(type_sp);
+}
+
+lldb::SyntheticChildrenSP
+DataVisualization::GetSyntheticChildren(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ return GetFormatManager().GetSyntheticChildren(valobj, use_dynamic);
+}
+
+lldb::TypeFilterImplSP
+DataVisualization::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return GetFormatManager().GetFilterForType(type_sp);
+}
+
+lldb::ScriptedSyntheticChildrenSP
+DataVisualization::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return GetFormatManager().GetSyntheticForType(type_sp);
+}
+
+bool DataVisualization::AnyMatches(
+ const FormattersMatchCandidate &candidate_type,
+ TypeCategoryImpl::FormatCategoryItems items, bool only_enabled,
+ const char **matching_category,
+ TypeCategoryImpl::FormatCategoryItems *matching_type) {
+ return GetFormatManager().AnyMatches(candidate_type, items, only_enabled,
+ matching_category, matching_type);
+}
+
+bool DataVisualization::Categories::GetCategory(ConstString category,
+ lldb::TypeCategoryImplSP &entry,
+ bool allow_create) {
+ entry = GetFormatManager().GetCategory(category, allow_create);
+ return (entry.get() != nullptr);
+}
+
+bool DataVisualization::Categories::GetCategory(
+ lldb::LanguageType language, lldb::TypeCategoryImplSP &entry) {
+ if (LanguageCategory *lang_category =
+ GetFormatManager().GetCategoryForLanguage(language))
+ entry = lang_category->GetCategory();
+ return (entry.get() != nullptr);
+}
+
+void DataVisualization::Categories::Add(ConstString category) {
+ GetFormatManager().GetCategory(category);
+}
+
+bool DataVisualization::Categories::Delete(ConstString category) {
+ GetFormatManager().DisableCategory(category);
+ return GetFormatManager().DeleteCategory(category);
+}
+
+void DataVisualization::Categories::Clear() {
+ GetFormatManager().ClearCategories();
+}
+
+void DataVisualization::Categories::Clear(ConstString category) {
+ GetFormatManager().GetCategory(category)->Clear(eFormatCategoryItemSummary);
+}
+
+void DataVisualization::Categories::Enable(ConstString category,
+ TypeCategoryMap::Position pos) {
+ if (GetFormatManager().GetCategory(category)->IsEnabled())
+ GetFormatManager().DisableCategory(category);
+ GetFormatManager().EnableCategory(category, pos, {});
+}
+
+void DataVisualization::Categories::Enable(lldb::LanguageType lang_type) {
+ if (LanguageCategory *lang_category =
+ GetFormatManager().GetCategoryForLanguage(lang_type))
+ lang_category->Enable();
+}
+
+void DataVisualization::Categories::Disable(ConstString category) {
+ if (GetFormatManager().GetCategory(category)->IsEnabled())
+ GetFormatManager().DisableCategory(category);
+}
+
+void DataVisualization::Categories::Disable(lldb::LanguageType lang_type) {
+ if (LanguageCategory *lang_category =
+ GetFormatManager().GetCategoryForLanguage(lang_type))
+ lang_category->Disable();
+}
+
+void DataVisualization::Categories::Enable(
+ const lldb::TypeCategoryImplSP &category, TypeCategoryMap::Position pos) {
+ if (category.get()) {
+ if (category->IsEnabled())
+ GetFormatManager().DisableCategory(category);
+ GetFormatManager().EnableCategory(category, pos);
+ }
+}
+
+void DataVisualization::Categories::Disable(
+ const lldb::TypeCategoryImplSP &category) {
+ if (category.get() && category->IsEnabled())
+ GetFormatManager().DisableCategory(category);
+}
+
+void DataVisualization::Categories::EnableStar() {
+ GetFormatManager().EnableAllCategories();
+}
+
+void DataVisualization::Categories::DisableStar() {
+ GetFormatManager().DisableAllCategories();
+}
+
+void DataVisualization::Categories::ForEach(
+ TypeCategoryMap::ForEachCallback callback) {
+ GetFormatManager().ForEachCategory(callback);
+}
+
+uint32_t DataVisualization::Categories::GetCount() {
+ return GetFormatManager().GetCategoriesCount();
+}
+
+lldb::TypeCategoryImplSP
+DataVisualization::Categories::GetCategoryAtIndex(size_t index) {
+ return GetFormatManager().GetCategoryAtIndex(index);
+}
+
+bool DataVisualization::NamedSummaryFormats::GetSummaryFormat(
+ ConstString type, lldb::TypeSummaryImplSP &entry) {
+ return GetFormatManager().GetNamedSummaryContainer().GetExact(type, entry);
+}
+
+void DataVisualization::NamedSummaryFormats::Add(
+ ConstString type, const lldb::TypeSummaryImplSP &entry) {
+ GetFormatManager().GetNamedSummaryContainer().Add(type, entry);
+}
+
+bool DataVisualization::NamedSummaryFormats::Delete(ConstString type) {
+ return GetFormatManager().GetNamedSummaryContainer().Delete(type);
+}
+
+void DataVisualization::NamedSummaryFormats::Clear() {
+ GetFormatManager().GetNamedSummaryContainer().Clear();
+}
+
+void DataVisualization::NamedSummaryFormats::ForEach(
+ std::function<bool(const TypeMatcher &, const lldb::TypeSummaryImplSP &)>
+ callback) {
+ GetFormatManager().GetNamedSummaryContainer().ForEach(callback);
+}
+
+uint32_t DataVisualization::NamedSummaryFormats::GetCount() {
+ return GetFormatManager().GetNamedSummaryContainer().GetCount();
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/DumpValueObjectOptions.cpp b/contrib/llvm-project/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
new file mode 100644
index 000000000000..c5e84810cdc8
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
@@ -0,0 +1,214 @@
+//===-- DumpValueObjectOptions.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 "lldb/DataFormatters/DumpValueObjectOptions.h"
+
+#include "lldb/Core/ValueObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+DumpValueObjectOptions::DumpValueObjectOptions()
+ : m_summary_sp(), m_root_valobj_name(),
+ m_max_ptr_depth(PointerDepth{PointerDepth::Mode::Default, 0}),
+ m_decl_printing_helper(), m_child_printing_decider(),
+ m_pointer_as_array(), m_use_synthetic(true),
+ m_scope_already_checked(false), m_flat_output(false), m_ignore_cap(false),
+ m_show_types(false), m_show_location(false), m_use_objc(false),
+ m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false),
+ m_hide_value(false), m_run_validator(false),
+ m_use_type_display_name(true), m_allow_oneliner_mode(true),
+ m_hide_pointer_value(false), m_reveal_empty_aggregates(true) {}
+
+DumpValueObjectOptions::DumpValueObjectOptions(ValueObject &valobj)
+ : DumpValueObjectOptions() {
+ m_use_dynamic = valobj.GetDynamicValueType();
+ m_use_synthetic = valobj.IsSynthetic();
+ m_varformat_language = valobj.GetPreferredDisplayLanguage();
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetMaximumPointerDepth(PointerDepth depth) {
+ m_max_ptr_depth = depth;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetMaximumDepth(uint32_t depth, bool is_default) {
+ m_max_depth = depth;
+ m_max_depth_is_default = is_default;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetDeclPrintingHelper(DeclPrintingHelper helper) {
+ m_decl_printing_helper = helper;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetChildPrintingDecider(ChildPrintingDecider decider) {
+ m_child_printing_decider = decider;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetShowTypes(bool show) {
+ m_show_types = show;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetShowLocation(bool show) {
+ m_show_location = show;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetUseObjectiveC(bool use) {
+ m_use_objc = use;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetShowSummary(bool show) {
+ if (!show)
+ SetOmitSummaryDepth(UINT32_MAX);
+ else
+ SetOmitSummaryDepth(0);
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetUseDynamicType(lldb::DynamicValueType dyn) {
+ m_use_dynamic = dyn;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetUseSyntheticValue(bool use_synthetic) {
+ m_use_synthetic = use_synthetic;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetScopeChecked(bool check) {
+ m_scope_already_checked = check;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetFlatOutput(bool flat) {
+ m_flat_output = flat;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetOmitSummaryDepth(uint32_t depth) {
+ m_omit_summary_depth = depth;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetIgnoreCap(bool ignore) {
+ m_ignore_cap = ignore;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetRawDisplay() {
+ SetUseSyntheticValue(false);
+ SetOmitSummaryDepth(UINT32_MAX);
+ SetIgnoreCap(true);
+ SetHideName(false);
+ SetHideValue(false);
+ SetUseTypeDisplayName(false);
+ SetAllowOnelinerMode(false);
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetFormat(lldb::Format format) {
+ m_format = format;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetSummary(lldb::TypeSummaryImplSP summary) {
+ m_summary_sp = summary;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetRootValueObjectName(const char *name) {
+ if (name)
+ m_root_valobj_name.assign(name);
+ else
+ m_root_valobj_name.clear();
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetHideRootType(bool hide_root_type) {
+ m_hide_root_type = hide_root_type;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetHideRootName(bool hide_root_name) {
+ m_hide_root_name = hide_root_name;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetHideName(bool hide_name) {
+ m_hide_name = hide_name;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetHideValue(bool hide_value) {
+ m_hide_value = hide_value;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetHidePointerValue(bool hide) {
+ m_hide_pointer_value = hide;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetVariableFormatDisplayLanguage(
+ lldb::LanguageType lang) {
+ m_varformat_language = lang;
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetRunValidator(bool run) {
+ m_run_validator = run;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetUseTypeDisplayName(bool dis) {
+ m_use_type_display_name = dis;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetAllowOnelinerMode(bool oneliner) {
+ m_allow_oneliner_mode = oneliner;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetRevealEmptyAggregates(bool reveal) {
+ m_reveal_empty_aggregates = reveal;
+ return *this;
+}
+
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetElementCount(uint32_t element_count) {
+ m_pointer_as_array = PointerAsArraySettings(element_count);
+ return *this;
+}
+
+DumpValueObjectOptions &DumpValueObjectOptions::SetPointerAsArray(
+ const PointerAsArraySettings &ptr_array) {
+ m_pointer_as_array = ptr_array;
+ return *this;
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp b/contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp
new file mode 100644
index 000000000000..6c83b36e79de
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp
@@ -0,0 +1,113 @@
+//===-- FormatCache.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 "lldb/DataFormatters/FormatCache.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+FormatCache::Entry::Entry()
+ : m_format_cached(false), m_summary_cached(false),
+ m_synthetic_cached(false) {}
+
+bool FormatCache::Entry::IsFormatCached() { return m_format_cached; }
+
+bool FormatCache::Entry::IsSummaryCached() { return m_summary_cached; }
+
+bool FormatCache::Entry::IsSyntheticCached() { return m_synthetic_cached; }
+
+void FormatCache::Entry::Get(lldb::TypeFormatImplSP &retval) {
+ retval = m_format_sp;
+}
+
+void FormatCache::Entry::Get(lldb::TypeSummaryImplSP &retval) {
+ retval = m_summary_sp;
+}
+
+void FormatCache::Entry::Get(lldb::SyntheticChildrenSP &retval) {
+ retval = m_synthetic_sp;
+}
+
+void FormatCache::Entry::Set(lldb::TypeFormatImplSP format_sp) {
+ m_format_cached = true;
+ m_format_sp = format_sp;
+}
+
+void FormatCache::Entry::Set(lldb::TypeSummaryImplSP summary_sp) {
+ m_summary_cached = true;
+ m_summary_sp = summary_sp;
+}
+
+void FormatCache::Entry::Set(lldb::SyntheticChildrenSP synthetic_sp) {
+ m_synthetic_cached = true;
+ m_synthetic_sp = synthetic_sp;
+}
+
+namespace lldb_private {
+
+template<> bool FormatCache::Entry::IsCached<lldb::TypeFormatImplSP>() {
+ return IsFormatCached();
+}
+template<> bool FormatCache::Entry::IsCached<lldb::TypeSummaryImplSP> () {
+ return IsSummaryCached();
+}
+template<> bool FormatCache::Entry::IsCached<lldb::SyntheticChildrenSP>() {
+ return IsSyntheticCached();
+}
+
+} // namespace lldb_private
+
+template <typename ImplSP>
+bool FormatCache::Get(ConstString type, ImplSP &format_impl_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ auto entry = m_entries[type];
+ if (entry.IsCached<ImplSP>()) {
+ m_cache_hits++;
+ entry.Get(format_impl_sp);
+ return true;
+ }
+ m_cache_misses++;
+ format_impl_sp.reset();
+ return false;
+}
+
+/// Explicit instantiations for the three types.
+/// \{
+template bool
+FormatCache::Get<lldb::TypeFormatImplSP>(ConstString, lldb::TypeFormatImplSP &);
+template bool
+FormatCache::Get<lldb::TypeSummaryImplSP>(ConstString,
+ lldb::TypeSummaryImplSP &);
+template bool
+FormatCache::Get<lldb::SyntheticChildrenSP>(ConstString,
+ lldb::SyntheticChildrenSP &);
+/// \}
+
+void FormatCache::Set(ConstString type, lldb::TypeFormatImplSP &format_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_entries[type].Set(format_sp);
+}
+
+void FormatCache::Set(ConstString type, lldb::TypeSummaryImplSP &summary_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_entries[type].Set(summary_sp);
+}
+
+void FormatCache::Set(ConstString type,
+ lldb::SyntheticChildrenSP &synthetic_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_entries[type].Set(synthetic_sp);
+}
+
+void FormatCache::Clear() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_entries.clear();
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/FormatClasses.cpp b/contrib/llvm-project/lldb/source/DataFormatters/FormatClasses.cpp
new file mode 100644
index 000000000000..44fa96033bc1
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/FormatClasses.cpp
@@ -0,0 +1,49 @@
+//===-- FormatClasses.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 "lldb/DataFormatters/FormatClasses.h"
+
+#include "lldb/DataFormatters/FormatManager.h"
+
+
+
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+FormattersMatchData::FormattersMatchData(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic)
+ : m_valobj(valobj), m_dynamic_value_type(use_dynamic),
+ m_formatters_match_vector({}, false), m_type_for_cache(),
+ m_candidate_languages() {
+ m_type_for_cache = FormatManager::GetTypeForCache(valobj, use_dynamic);
+ m_candidate_languages =
+ FormatManager::GetCandidateLanguages(valobj.GetObjectRuntimeLanguage());
+}
+
+FormattersMatchVector FormattersMatchData::GetMatchesVector() {
+ if (!m_formatters_match_vector.second) {
+ m_formatters_match_vector.second = true;
+ m_formatters_match_vector.first =
+ FormatManager::GetPossibleMatches(m_valobj, m_dynamic_value_type);
+ }
+ return m_formatters_match_vector.first;
+}
+
+ConstString FormattersMatchData::GetTypeForCache() { return m_type_for_cache; }
+
+CandidateLanguagesVector FormattersMatchData::GetCandidateLanguages() {
+ return m_candidate_languages;
+}
+
+ValueObject &FormattersMatchData::GetValueObject() { return m_valobj; }
+
+lldb::DynamicValueType FormattersMatchData::GetDynamicValueType() {
+ return m_dynamic_value_type;
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp b/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp
new file mode 100644
index 000000000000..7e19989a8264
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp
@@ -0,0 +1,795 @@
+//===-- FormatManager.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 "lldb/DataFormatters/FormatManager.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/DataFormatters/LanguageCategory.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+struct FormatInfo {
+ Format format;
+ const char format_char; // One or more format characters that can be used for
+ // this format.
+ const char *format_name; // Long format name that can be used to specify the
+ // current format
+};
+
+static constexpr FormatInfo g_format_infos[] = {
+ {eFormatDefault, '\0', "default"},
+ {eFormatBoolean, 'B', "boolean"},
+ {eFormatBinary, 'b', "binary"},
+ {eFormatBytes, 'y', "bytes"},
+ {eFormatBytesWithASCII, 'Y', "bytes with ASCII"},
+ {eFormatChar, 'c', "character"},
+ {eFormatCharPrintable, 'C', "printable character"},
+ {eFormatComplexFloat, 'F', "complex float"},
+ {eFormatCString, 's', "c-string"},
+ {eFormatDecimal, 'd', "decimal"},
+ {eFormatEnum, 'E', "enumeration"},
+ {eFormatHex, 'x', "hex"},
+ {eFormatHexUppercase, 'X', "uppercase hex"},
+ {eFormatFloat, 'f', "float"},
+ {eFormatOctal, 'o', "octal"},
+ {eFormatOSType, 'O', "OSType"},
+ {eFormatUnicode16, 'U', "unicode16"},
+ {eFormatUnicode32, '\0', "unicode32"},
+ {eFormatUnsigned, 'u', "unsigned decimal"},
+ {eFormatPointer, 'p', "pointer"},
+ {eFormatVectorOfChar, '\0', "char[]"},
+ {eFormatVectorOfSInt8, '\0', "int8_t[]"},
+ {eFormatVectorOfUInt8, '\0', "uint8_t[]"},
+ {eFormatVectorOfSInt16, '\0', "int16_t[]"},
+ {eFormatVectorOfUInt16, '\0', "uint16_t[]"},
+ {eFormatVectorOfSInt32, '\0', "int32_t[]"},
+ {eFormatVectorOfUInt32, '\0', "uint32_t[]"},
+ {eFormatVectorOfSInt64, '\0', "int64_t[]"},
+ {eFormatVectorOfUInt64, '\0', "uint64_t[]"},
+ {eFormatVectorOfFloat16, '\0', "float16[]"},
+ {eFormatVectorOfFloat32, '\0', "float32[]"},
+ {eFormatVectorOfFloat64, '\0', "float64[]"},
+ {eFormatVectorOfUInt128, '\0', "uint128_t[]"},
+ {eFormatComplexInteger, 'I', "complex integer"},
+ {eFormatCharArray, 'a', "character array"},
+ {eFormatAddressInfo, 'A', "address"},
+ {eFormatHexFloat, '\0', "hex float"},
+ {eFormatInstruction, 'i', "instruction"},
+ {eFormatVoid, 'v', "void"},
+ {eFormatUnicode8, 'u', "unicode8"},
+};
+
+static_assert((sizeof(g_format_infos) / sizeof(g_format_infos[0])) ==
+ kNumFormats,
+ "All formats must have a corresponding info entry.");
+
+static uint32_t g_num_format_infos = std::size(g_format_infos);
+
+static bool GetFormatFromFormatChar(char format_char, Format &format) {
+ for (uint32_t i = 0; i < g_num_format_infos; ++i) {
+ if (g_format_infos[i].format_char == format_char) {
+ format = g_format_infos[i].format;
+ return true;
+ }
+ }
+ format = eFormatInvalid;
+ return false;
+}
+
+static bool GetFormatFromFormatName(llvm::StringRef format_name,
+ Format &format) {
+ uint32_t i;
+ for (i = 0; i < g_num_format_infos; ++i) {
+ if (format_name.equals_insensitive(g_format_infos[i].format_name)) {
+ format = g_format_infos[i].format;
+ return true;
+ }
+ }
+
+ for (i = 0; i < g_num_format_infos; ++i) {
+ if (llvm::StringRef(g_format_infos[i].format_name)
+ .starts_with_insensitive(format_name)) {
+ format = g_format_infos[i].format;
+ return true;
+ }
+ }
+ format = eFormatInvalid;
+ return false;
+}
+
+void FormatManager::Changed() {
+ ++m_last_revision;
+ m_format_cache.Clear();
+ std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
+ for (auto &iter : m_language_categories_map) {
+ if (iter.second)
+ iter.second->GetFormatCache().Clear();
+ }
+}
+
+bool FormatManager::GetFormatFromCString(const char *format_cstr,
+ lldb::Format &format) {
+ bool success = false;
+ if (format_cstr && format_cstr[0]) {
+ if (format_cstr[1] == '\0') {
+ success = GetFormatFromFormatChar(format_cstr[0], format);
+ if (success)
+ return true;
+ }
+
+ success = GetFormatFromFormatName(format_cstr, format);
+ }
+ if (!success)
+ format = eFormatInvalid;
+ return success;
+}
+
+char FormatManager::GetFormatAsFormatChar(lldb::Format format) {
+ for (uint32_t i = 0; i < g_num_format_infos; ++i) {
+ if (g_format_infos[i].format == format)
+ return g_format_infos[i].format_char;
+ }
+ return '\0';
+}
+
+const char *FormatManager::GetFormatAsCString(Format format) {
+ if (format >= eFormatDefault && format < kNumFormats)
+ return g_format_infos[format].format_name;
+ return nullptr;
+}
+
+void FormatManager::EnableAllCategories() {
+ m_categories_map.EnableAllCategories();
+ std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
+ for (auto &iter : m_language_categories_map) {
+ if (iter.second)
+ iter.second->Enable();
+ }
+}
+
+void FormatManager::DisableAllCategories() {
+ m_categories_map.DisableAllCategories();
+ std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
+ for (auto &iter : m_language_categories_map) {
+ if (iter.second)
+ iter.second->Disable();
+ }
+}
+
+void FormatManager::GetPossibleMatches(
+ ValueObject &valobj, CompilerType compiler_type,
+ lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries,
+ FormattersMatchCandidate::Flags current_flags, bool root_level) {
+ compiler_type = compiler_type.GetTypeForFormatters();
+ ConstString type_name(compiler_type.GetTypeName());
+ // A ValueObject that couldn't be made correctly won't necessarily have a
+ // target. We aren't going to find a formatter in this case anyway, so we
+ // should just exit.
+ TargetSP target_sp = valobj.GetTargetSP();
+ if (!target_sp)
+ return;
+ ScriptInterpreter *script_interpreter =
+ target_sp->GetDebugger().GetScriptInterpreter();
+ if (valobj.GetBitfieldBitSize() > 0) {
+ StreamString sstring;
+ sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize());
+ ConstString bitfieldname(sstring.GetString());
+ entries.push_back({bitfieldname, script_interpreter,
+ TypeImpl(compiler_type), current_flags});
+ }
+
+ if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) {
+ entries.push_back({type_name, script_interpreter, TypeImpl(compiler_type),
+ current_flags});
+
+ ConstString display_type_name(compiler_type.GetTypeName());
+ if (display_type_name != type_name)
+ entries.push_back({display_type_name, script_interpreter,
+ TypeImpl(compiler_type), current_flags});
+ }
+
+ for (bool is_rvalue_ref = true, j = true;
+ j && compiler_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) {
+ CompilerType non_ref_type = compiler_type.GetNonReferenceType();
+ GetPossibleMatches(valobj, non_ref_type, use_dynamic, entries,
+ current_flags.WithStrippedReference());
+ if (non_ref_type.IsTypedefType()) {
+ CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType();
+ deffed_referenced_type =
+ is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType()
+ : deffed_referenced_type.GetLValueReferenceType();
+ // this is not exactly the usual meaning of stripping typedefs
+ GetPossibleMatches(
+ valobj, deffed_referenced_type,
+ use_dynamic, entries, current_flags.WithStrippedTypedef());
+ }
+ }
+
+ if (compiler_type.IsPointerType()) {
+ CompilerType non_ptr_type = compiler_type.GetPointeeType();
+ GetPossibleMatches(valobj, non_ptr_type, use_dynamic, entries,
+ current_flags.WithStrippedPointer());
+ if (non_ptr_type.IsTypedefType()) {
+ CompilerType deffed_pointed_type =
+ non_ptr_type.GetTypedefedType().GetPointerType();
+ // this is not exactly the usual meaning of stripping typedefs
+ GetPossibleMatches(valobj, deffed_pointed_type, use_dynamic, entries,
+ current_flags.WithStrippedTypedef());
+ }
+ }
+
+ // For arrays with typedef-ed elements, we add a candidate with the typedef
+ // stripped.
+ uint64_t array_size;
+ if (compiler_type.IsArrayType(nullptr, &array_size, nullptr)) {
+ ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
+ CompilerType element_type = compiler_type.GetArrayElementType(
+ exe_ctx.GetBestExecutionContextScope());
+ if (element_type.IsTypedefType()) {
+ // Get the stripped element type and compute the stripped array type
+ // from it.
+ CompilerType deffed_array_type =
+ element_type.GetTypedefedType().GetArrayType(array_size);
+ // this is not exactly the usual meaning of stripping typedefs
+ GetPossibleMatches(
+ valobj, deffed_array_type,
+ use_dynamic, entries, current_flags.WithStrippedTypedef());
+ }
+ }
+
+ for (lldb::LanguageType language_type :
+ GetCandidateLanguages(valobj.GetObjectRuntimeLanguage())) {
+ if (Language *language = Language::FindPlugin(language_type)) {
+ for (const FormattersMatchCandidate& candidate :
+ language->GetPossibleFormattersMatches(valobj, use_dynamic)) {
+ entries.push_back(candidate);
+ }
+ }
+ }
+
+ // try to strip typedef chains
+ if (compiler_type.IsTypedefType()) {
+ CompilerType deffed_type = compiler_type.GetTypedefedType();
+ GetPossibleMatches(valobj, deffed_type, use_dynamic, entries,
+ current_flags.WithStrippedTypedef());
+ }
+
+ if (root_level) {
+ do {
+ if (!compiler_type.IsValid())
+ break;
+
+ CompilerType unqual_compiler_ast_type =
+ compiler_type.GetFullyUnqualifiedType();
+ if (!unqual_compiler_ast_type.IsValid())
+ break;
+ if (unqual_compiler_ast_type.GetOpaqueQualType() !=
+ compiler_type.GetOpaqueQualType())
+ GetPossibleMatches(valobj, unqual_compiler_ast_type, use_dynamic,
+ entries, current_flags);
+ } while (false);
+
+ // if all else fails, go to static type
+ if (valobj.IsDynamic()) {
+ lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
+ if (static_value_sp)
+ GetPossibleMatches(*static_value_sp.get(),
+ static_value_sp->GetCompilerType(), use_dynamic,
+ entries, current_flags, true);
+ }
+ }
+}
+
+lldb::TypeFormatImplSP
+FormatManager::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ if (!type_sp)
+ return lldb::TypeFormatImplSP();
+ lldb::TypeFormatImplSP format_chosen_sp;
+ uint32_t num_categories = m_categories_map.GetCount();
+ lldb::TypeCategoryImplSP category_sp;
+ uint32_t prio_category = UINT32_MAX;
+ for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
+ category_sp = GetCategoryAtIndex(category_id);
+ if (!category_sp->IsEnabled())
+ continue;
+ lldb::TypeFormatImplSP format_current_sp =
+ category_sp->GetFormatForType(type_sp);
+ if (format_current_sp &&
+ (format_chosen_sp.get() == nullptr ||
+ (prio_category > category_sp->GetEnabledPosition()))) {
+ prio_category = category_sp->GetEnabledPosition();
+ format_chosen_sp = format_current_sp;
+ }
+ }
+ return format_chosen_sp;
+}
+
+lldb::TypeSummaryImplSP
+FormatManager::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ if (!type_sp)
+ return lldb::TypeSummaryImplSP();
+ lldb::TypeSummaryImplSP summary_chosen_sp;
+ uint32_t num_categories = m_categories_map.GetCount();
+ lldb::TypeCategoryImplSP category_sp;
+ uint32_t prio_category = UINT32_MAX;
+ for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
+ category_sp = GetCategoryAtIndex(category_id);
+ if (!category_sp->IsEnabled())
+ continue;
+ lldb::TypeSummaryImplSP summary_current_sp =
+ category_sp->GetSummaryForType(type_sp);
+ if (summary_current_sp &&
+ (summary_chosen_sp.get() == nullptr ||
+ (prio_category > category_sp->GetEnabledPosition()))) {
+ prio_category = category_sp->GetEnabledPosition();
+ summary_chosen_sp = summary_current_sp;
+ }
+ }
+ return summary_chosen_sp;
+}
+
+lldb::TypeFilterImplSP
+FormatManager::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ if (!type_sp)
+ return lldb::TypeFilterImplSP();
+ lldb::TypeFilterImplSP filter_chosen_sp;
+ uint32_t num_categories = m_categories_map.GetCount();
+ lldb::TypeCategoryImplSP category_sp;
+ uint32_t prio_category = UINT32_MAX;
+ for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
+ category_sp = GetCategoryAtIndex(category_id);
+ if (!category_sp->IsEnabled())
+ continue;
+ lldb::TypeFilterImplSP filter_current_sp(
+ (TypeFilterImpl *)category_sp->GetFilterForType(type_sp).get());
+ if (filter_current_sp &&
+ (filter_chosen_sp.get() == nullptr ||
+ (prio_category > category_sp->GetEnabledPosition()))) {
+ prio_category = category_sp->GetEnabledPosition();
+ filter_chosen_sp = filter_current_sp;
+ }
+ }
+ return filter_chosen_sp;
+}
+
+lldb::ScriptedSyntheticChildrenSP
+FormatManager::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ if (!type_sp)
+ return lldb::ScriptedSyntheticChildrenSP();
+ lldb::ScriptedSyntheticChildrenSP synth_chosen_sp;
+ uint32_t num_categories = m_categories_map.GetCount();
+ lldb::TypeCategoryImplSP category_sp;
+ uint32_t prio_category = UINT32_MAX;
+ for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
+ category_sp = GetCategoryAtIndex(category_id);
+ if (!category_sp->IsEnabled())
+ continue;
+ lldb::ScriptedSyntheticChildrenSP synth_current_sp(
+ (ScriptedSyntheticChildren *)category_sp->GetSyntheticForType(type_sp)
+ .get());
+ if (synth_current_sp &&
+ (synth_chosen_sp.get() == nullptr ||
+ (prio_category > category_sp->GetEnabledPosition()))) {
+ prio_category = category_sp->GetEnabledPosition();
+ synth_chosen_sp = synth_current_sp;
+ }
+ }
+ return synth_chosen_sp;
+}
+
+void FormatManager::ForEachCategory(TypeCategoryMap::ForEachCallback callback) {
+ m_categories_map.ForEach(callback);
+ std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
+ for (const auto &entry : m_language_categories_map) {
+ if (auto category_sp = entry.second->GetCategory()) {
+ if (!callback(category_sp))
+ break;
+ }
+ }
+}
+
+lldb::TypeCategoryImplSP
+FormatManager::GetCategory(ConstString category_name, bool can_create) {
+ if (!category_name)
+ return GetCategory(m_default_category_name);
+ lldb::TypeCategoryImplSP category;
+ if (m_categories_map.Get(category_name, category))
+ return category;
+
+ if (!can_create)
+ return lldb::TypeCategoryImplSP();
+
+ m_categories_map.Add(
+ category_name,
+ lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name)));
+ return GetCategory(category_name);
+}
+
+lldb::Format FormatManager::GetSingleItemFormat(lldb::Format vector_format) {
+ switch (vector_format) {
+ case eFormatVectorOfChar:
+ return eFormatCharArray;
+
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfSInt64:
+ return eFormatDecimal;
+
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfUInt128:
+ return eFormatHex;
+
+ case eFormatVectorOfFloat16:
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ return eFormatFloat;
+
+ default:
+ return lldb::eFormatInvalid;
+ }
+}
+
+bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) {
+ TargetSP target_sp = valobj.GetTargetSP();
+ // if settings say no oneline whatsoever
+ if (target_sp && !target_sp->GetDebugger().GetAutoOneLineSummaries())
+ return false; // then don't oneline
+
+ // if this object has a summary, then ask the summary
+ if (valobj.GetSummaryFormat().get() != nullptr)
+ return valobj.GetSummaryFormat()->IsOneLiner();
+
+ const size_t max_num_children =
+ (target_sp ? *target_sp : Target::GetGlobalProperties())
+ .GetMaximumNumberOfChildrenToDisplay();
+ auto num_children = valobj.GetNumChildren(max_num_children);
+ if (!num_children) {
+ llvm::consumeError(num_children.takeError());
+ return true;
+ }
+ // no children, no party
+ if (*num_children == 0)
+ return false;
+
+ // ask the type if it has any opinion about this eLazyBoolCalculate == no
+ // opinion; other values should be self explanatory
+ CompilerType compiler_type(valobj.GetCompilerType());
+ if (compiler_type.IsValid()) {
+ switch (compiler_type.ShouldPrintAsOneLiner(&valobj)) {
+ case eLazyBoolNo:
+ return false;
+ case eLazyBoolYes:
+ return true;
+ case eLazyBoolCalculate:
+ break;
+ }
+ }
+
+ size_t total_children_name_len = 0;
+
+ for (size_t idx = 0; idx < *num_children; idx++) {
+ bool is_synth_val = false;
+ ValueObjectSP child_sp(valobj.GetChildAtIndex(idx));
+ // something is wrong here - bail out
+ if (!child_sp)
+ return false;
+
+ // also ask the child's type if it has any opinion
+ CompilerType child_compiler_type(child_sp->GetCompilerType());
+ if (child_compiler_type.IsValid()) {
+ switch (child_compiler_type.ShouldPrintAsOneLiner(child_sp.get())) {
+ case eLazyBoolYes:
+ // an opinion of yes is only binding for the child, so keep going
+ case eLazyBoolCalculate:
+ break;
+ case eLazyBoolNo:
+ // but if the child says no, then it's a veto on the whole thing
+ return false;
+ }
+ }
+
+ // if we decided to define synthetic children for a type, we probably care
+ // enough to show them, but avoid nesting children in children
+ if (child_sp->GetSyntheticChildren().get() != nullptr) {
+ ValueObjectSP synth_sp(child_sp->GetSyntheticValue());
+ // wait.. wat? just get out of here..
+ if (!synth_sp)
+ return false;
+ // but if we only have them to provide a value, keep going
+ if (!synth_sp->MightHaveChildren() &&
+ synth_sp->DoesProvideSyntheticValue())
+ is_synth_val = true;
+ else
+ return false;
+ }
+
+ total_children_name_len += child_sp->GetName().GetLength();
+
+ // 50 itself is a "randomly" chosen number - the idea is that
+ // overly long structs should not get this treatment
+ // FIXME: maybe make this a user-tweakable setting?
+ if (total_children_name_len > 50)
+ return false;
+
+ // if a summary is there..
+ if (child_sp->GetSummaryFormat()) {
+ // and it wants children, then bail out
+ if (child_sp->GetSummaryFormat()->DoesPrintChildren(child_sp.get()))
+ return false;
+ }
+
+ // if this child has children..
+ if (child_sp->HasChildren()) {
+ // ...and no summary...
+ // (if it had a summary and the summary wanted children, we would have
+ // bailed out anyway
+ // so this only makes us bail out if this has no summary and we would
+ // then print children)
+ if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do
+ // that if not a
+ // synthetic valued
+ // child
+ return false; // then bail out
+ }
+ }
+ return true;
+}
+
+ConstString FormatManager::GetTypeForCache(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ ValueObjectSP valobj_sp = valobj.GetQualifiedRepresentationIfAvailable(
+ use_dynamic, valobj.IsSynthetic());
+ if (valobj_sp && valobj_sp->GetCompilerType().IsValid()) {
+ if (!valobj_sp->GetCompilerType().IsMeaninglessWithoutDynamicResolution())
+ return valobj_sp->GetQualifiedTypeName();
+ }
+ return ConstString();
+}
+
+std::vector<lldb::LanguageType>
+FormatManager::GetCandidateLanguages(lldb::LanguageType lang_type) {
+ switch (lang_type) {
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC89:
+ case lldb::eLanguageTypeC99:
+ case lldb::eLanguageTypeC11:
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeC_plus_plus_03:
+ case lldb::eLanguageTypeC_plus_plus_11:
+ case lldb::eLanguageTypeC_plus_plus_14:
+ return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC};
+ default:
+ return {lang_type};
+ }
+ llvm_unreachable("Fully covered switch");
+}
+
+LanguageCategory *
+FormatManager::GetCategoryForLanguage(lldb::LanguageType lang_type) {
+ std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
+ auto iter = m_language_categories_map.find(lang_type),
+ end = m_language_categories_map.end();
+ if (iter != end)
+ return iter->second.get();
+ LanguageCategory *lang_category = new LanguageCategory(lang_type);
+ m_language_categories_map[lang_type] =
+ LanguageCategory::UniquePointer(lang_category);
+ return lang_category;
+}
+
+template <typename ImplSP>
+ImplSP FormatManager::GetHardcoded(FormattersMatchData &match_data) {
+ ImplSP retval_sp;
+ for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) {
+ if (LanguageCategory *lang_category = GetCategoryForLanguage(lang_type)) {
+ if (lang_category->GetHardcoded(*this, match_data, retval_sp))
+ return retval_sp;
+ }
+ }
+ return retval_sp;
+}
+
+namespace {
+template <typename ImplSP> const char *FormatterKind;
+template <> const char *FormatterKind<lldb::TypeFormatImplSP> = "format";
+template <> const char *FormatterKind<lldb::TypeSummaryImplSP> = "summary";
+template <> const char *FormatterKind<lldb::SyntheticChildrenSP> = "synthetic";
+} // namespace
+
+#define FORMAT_LOG(Message) "[%s] " Message, FormatterKind<ImplSP>
+
+template <typename ImplSP>
+ImplSP FormatManager::Get(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ FormattersMatchData match_data(valobj, use_dynamic);
+ if (ImplSP retval_sp = GetCached<ImplSP>(match_data))
+ return retval_sp;
+
+ Log *log = GetLog(LLDBLog::DataFormatters);
+
+ LLDB_LOGF(log, FORMAT_LOG("Search failed. Giving language a chance."));
+ for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) {
+ if (LanguageCategory *lang_category = GetCategoryForLanguage(lang_type)) {
+ ImplSP retval_sp;
+ if (lang_category->Get(match_data, retval_sp))
+ if (retval_sp) {
+ LLDB_LOGF(log, FORMAT_LOG("Language search success. Returning."));
+ return retval_sp;
+ }
+ }
+ }
+
+ LLDB_LOGF(log, FORMAT_LOG("Search failed. Giving hardcoded a chance."));
+ return GetHardcoded<ImplSP>(match_data);
+}
+
+template <typename ImplSP>
+ImplSP FormatManager::GetCached(FormattersMatchData &match_data) {
+ ImplSP retval_sp;
+ Log *log = GetLog(LLDBLog::DataFormatters);
+ if (match_data.GetTypeForCache()) {
+ LLDB_LOGF(log, "\n\n" FORMAT_LOG("Looking into cache for type %s"),
+ match_data.GetTypeForCache().AsCString("<invalid>"));
+ if (m_format_cache.Get(match_data.GetTypeForCache(), retval_sp)) {
+ if (log) {
+ LLDB_LOGF(log, FORMAT_LOG("Cache search success. Returning."));
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(),
+ m_format_cache.GetCacheMisses());
+ }
+ return retval_sp;
+ }
+ LLDB_LOGF(log, FORMAT_LOG("Cache search failed. Going normal route"));
+ }
+
+ m_categories_map.Get(match_data, retval_sp);
+ if (match_data.GetTypeForCache() && (!retval_sp || !retval_sp->NonCacheable())) {
+ LLDB_LOGF(log, FORMAT_LOG("Caching %p for type %s"),
+ static_cast<void *>(retval_sp.get()),
+ match_data.GetTypeForCache().AsCString("<invalid>"));
+ m_format_cache.Set(match_data.GetTypeForCache(), retval_sp);
+ }
+ LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
+ m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ return retval_sp;
+}
+
+#undef FORMAT_LOG
+
+lldb::TypeFormatImplSP
+FormatManager::GetFormat(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ return Get<lldb::TypeFormatImplSP>(valobj, use_dynamic);
+}
+
+lldb::TypeSummaryImplSP
+FormatManager::GetSummaryFormat(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ return Get<lldb::TypeSummaryImplSP>(valobj, use_dynamic);
+}
+
+lldb::SyntheticChildrenSP
+FormatManager::GetSyntheticChildren(ValueObject &valobj,
+ lldb::DynamicValueType use_dynamic) {
+ return Get<lldb::SyntheticChildrenSP>(valobj, use_dynamic);
+}
+
+FormatManager::FormatManager()
+ : m_last_revision(0), m_format_cache(), m_language_categories_mutex(),
+ m_language_categories_map(), m_named_summaries_map(this),
+ m_categories_map(this), m_default_category_name(ConstString("default")),
+ m_system_category_name(ConstString("system")),
+ m_vectortypes_category_name(ConstString("VectorTypes")) {
+ LoadSystemFormatters();
+ LoadVectorFormatters();
+
+ EnableCategory(m_vectortypes_category_name, TypeCategoryMap::Last,
+ lldb::eLanguageTypeObjC_plus_plus);
+ EnableCategory(m_system_category_name, TypeCategoryMap::Last,
+ lldb::eLanguageTypeObjC_plus_plus);
+}
+
+void FormatManager::LoadSystemFormatters() {
+ 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);
+
+ lldb::TypeSummaryImplSP string_format(
+ new StringSummaryFormat(string_flags, "${var%s}"));
+
+ lldb::TypeSummaryImplSP string_array_format(
+ new StringSummaryFormat(string_array_flags, "${var%char[]}"));
+
+ TypeCategoryImpl::SharedPointer sys_category_sp =
+ GetCategory(m_system_category_name);
+
+ sys_category_sp->AddTypeSummary(R"(^(unsigned )?char ?(\*|\[\])$)",
+ eFormatterMatchRegex, string_format);
+
+ sys_category_sp->AddTypeSummary(R"(^((un)?signed )?char ?\[[0-9]+\]$)",
+ eFormatterMatchRegex, string_array_format);
+
+ lldb::TypeSummaryImplSP ostype_summary(
+ new StringSummaryFormat(TypeSummaryImpl::Flags()
+ .SetCascades(false)
+ .SetSkipPointers(true)
+ .SetSkipReferences(true)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false),
+ "${var%O}"));
+
+ sys_category_sp->AddTypeSummary("OSType", eFormatterMatchExact,
+ ostype_summary);
+
+ TypeFormatImpl::Flags fourchar_flags;
+ fourchar_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences(
+ true);
+
+ AddFormat(sys_category_sp, lldb::eFormatOSType, "FourCharCode",
+ fourchar_flags);
+}
+
+void FormatManager::LoadVectorFormatters() {
+ TypeCategoryImpl::SharedPointer vectors_category_sp =
+ GetCategory(m_vectortypes_category_name);
+
+ TypeSummaryImpl::Flags vector_flags;
+ vector_flags.SetCascades(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(true)
+ .SetHideItemNames(true);
+
+ AddStringSummary(vectors_category_sp, "${var.uint128}", "builtin_type_vec128",
+ vector_flags);
+ AddStringSummary(vectors_category_sp, "", "float[4]", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "int32_t[4]", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "int16_t[8]", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vDouble", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vFloat", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vSInt8", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vSInt16", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vSInt32", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vUInt16", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vUInt8", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vUInt16", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vUInt32", vector_flags);
+ AddStringSummary(vectors_category_sp, "", "vBool32", vector_flags);
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/FormattersHelpers.cpp b/contrib/llvm-project/lldb/source/DataFormatters/FormattersHelpers.cpp
new file mode 100644
index 000000000000..085ed3d0a2f2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/FormattersHelpers.cpp
@@ -0,0 +1,128 @@
+//===-- FormattersHelpers.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 "lldb/DataFormatters/FormattersHelpers.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/RegularExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+void lldb_private::formatters::AddFormat(
+ TypeCategoryImpl::SharedPointer category_sp, lldb::Format format,
+ llvm::StringRef type_name, TypeFormatImpl::Flags flags, bool regex) {
+ lldb::TypeFormatImplSP format_sp(new TypeFormatImpl_Format(format, flags));
+
+ FormatterMatchType match_type =
+ regex ? eFormatterMatchRegex : eFormatterMatchExact;
+ category_sp->AddTypeFormat(type_name, match_type, format_sp);
+}
+
+void lldb_private::formatters::AddSummary(
+ TypeCategoryImpl::SharedPointer category_sp, TypeSummaryImplSP summary_sp,
+ llvm::StringRef type_name, bool regex) {
+ FormatterMatchType match_type =
+ regex ? eFormatterMatchRegex : eFormatterMatchExact;
+ category_sp->AddTypeSummary(type_name, match_type, summary_sp);
+}
+
+void lldb_private::formatters::AddStringSummary(
+ TypeCategoryImpl::SharedPointer category_sp, const char *string,
+ llvm::StringRef type_name, TypeSummaryImpl::Flags flags, bool regex) {
+ lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags, string));
+
+ FormatterMatchType match_type =
+ regex ? eFormatterMatchRegex : eFormatterMatchExact;
+ category_sp->AddTypeSummary(type_name, match_type, summary_sp);
+}
+
+void lldb_private::formatters::AddOneLineSummary(
+ TypeCategoryImpl::SharedPointer category_sp, llvm::StringRef type_name,
+ TypeSummaryImpl::Flags flags, bool regex) {
+ flags.SetShowMembersOneLiner(true);
+ lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags, ""));
+
+ FormatterMatchType match_type =
+ regex ? eFormatterMatchRegex : eFormatterMatchExact;
+ category_sp->AddTypeSummary(type_name, match_type, summary_sp);
+}
+
+void lldb_private::formatters::AddCXXSummary(
+ TypeCategoryImpl::SharedPointer category_sp,
+ CXXFunctionSummaryFormat::Callback funct, const char *description,
+ llvm::StringRef type_name, TypeSummaryImpl::Flags flags, bool regex) {
+ lldb::TypeSummaryImplSP summary_sp(
+ new CXXFunctionSummaryFormat(flags, funct, description));
+
+ FormatterMatchType match_type =
+ regex ? eFormatterMatchRegex : eFormatterMatchExact;
+ category_sp->AddTypeSummary(type_name, match_type, summary_sp);
+}
+
+void lldb_private::formatters::AddCXXSynthetic(
+ TypeCategoryImpl::SharedPointer category_sp,
+ CXXSyntheticChildren::CreateFrontEndCallback generator,
+ const char *description, llvm::StringRef type_name,
+ ScriptedSyntheticChildren::Flags flags, bool regex) {
+ lldb::SyntheticChildrenSP synth_sp(
+ new CXXSyntheticChildren(flags, description, generator));
+ FormatterMatchType match_type =
+ regex ? eFormatterMatchRegex : eFormatterMatchExact;
+ category_sp->AddTypeSynthetic(type_name, match_type, synth_sp);
+}
+
+void lldb_private::formatters::AddFilter(
+ TypeCategoryImpl::SharedPointer category_sp,
+ std::vector<std::string> children, const char *description,
+ llvm::StringRef type_name, ScriptedSyntheticChildren::Flags flags,
+ bool regex) {
+ TypeFilterImplSP filter_sp(new TypeFilterImpl(flags));
+ for (auto child : children)
+ filter_sp->AddExpressionPath(child);
+ FormatterMatchType match_type =
+ regex ? eFormatterMatchRegex : eFormatterMatchExact;
+ category_sp->AddTypeFilter(type_name, match_type, filter_sp);
+}
+
+size_t lldb_private::formatters::ExtractIndexFromString(const char *item_name) {
+ if (!item_name || !*item_name)
+ return UINT32_MAX;
+ if (*item_name != '[')
+ return UINT32_MAX;
+ item_name++;
+ char *endptr = nullptr;
+ unsigned long int idx = ::strtoul(item_name, &endptr, 0);
+ if (idx == 0 && endptr == item_name)
+ return UINT32_MAX;
+ if (idx == ULONG_MAX)
+ return UINT32_MAX;
+ return idx;
+}
+
+Address
+lldb_private::formatters::GetArrayAddressOrPointerValue(ValueObject &valobj) {
+ lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
+ AddressType type;
+
+ if (valobj.IsPointerType())
+ data_addr = valobj.GetPointerValue(&type);
+ else if (valobj.IsArrayType())
+ data_addr = valobj.GetAddressOf(/*scalar_is_load_address=*/true, &type);
+ if (data_addr != LLDB_INVALID_ADDRESS && type == eAddressTypeFile)
+ return Address(data_addr, valobj.GetModule()->GetSectionList());
+
+ return data_addr;
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/LanguageCategory.cpp b/contrib/llvm-project/lldb/source/DataFormatters/LanguageCategory.cpp
new file mode 100644
index 000000000000..4794186ce9ae
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/LanguageCategory.cpp
@@ -0,0 +1,136 @@
+//===-- LanguageCategory.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 "lldb/DataFormatters/LanguageCategory.h"
+
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/DataFormatters/TypeCategory.h"
+#include "lldb/DataFormatters/TypeFormat.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Target/Language.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LanguageCategory::LanguageCategory(lldb::LanguageType lang_type)
+ : m_category_sp(), m_hardcoded_formats(), m_hardcoded_summaries(),
+ m_hardcoded_synthetics(), m_format_cache(), m_enabled(false) {
+ if (Language *language_plugin = Language::FindPlugin(lang_type)) {
+ m_category_sp = language_plugin->GetFormatters();
+ m_hardcoded_formats = language_plugin->GetHardcodedFormats();
+ m_hardcoded_summaries = language_plugin->GetHardcodedSummaries();
+ m_hardcoded_synthetics = language_plugin->GetHardcodedSynthetics();
+ }
+ Enable();
+}
+
+template<typename ImplSP>
+bool LanguageCategory::Get(FormattersMatchData &match_data,
+ ImplSP &retval_sp) {
+ if (!m_category_sp)
+ return false;
+
+ if (!IsEnabled())
+ return false;
+
+ if (match_data.GetTypeForCache()) {
+ if (m_format_cache.Get(match_data.GetTypeForCache(), retval_sp))
+ return (bool)retval_sp;
+ }
+
+ ValueObject &valobj(match_data.GetValueObject());
+ bool result = m_category_sp->Get(valobj.GetObjectRuntimeLanguage(),
+ match_data.GetMatchesVector(), retval_sp);
+ if (match_data.GetTypeForCache() &&
+ (!retval_sp || !retval_sp->NonCacheable())) {
+ m_format_cache.Set(match_data.GetTypeForCache(), retval_sp);
+ }
+ return result;
+}
+
+namespace lldb_private {
+
+/// Explicit instantiations for the three types.
+/// \{
+template bool
+LanguageCategory::Get<lldb::TypeFormatImplSP>(FormattersMatchData &,
+ lldb::TypeFormatImplSP &);
+template bool
+LanguageCategory::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &,
+ lldb::TypeSummaryImplSP &);
+template bool
+LanguageCategory::Get<lldb::SyntheticChildrenSP>(FormattersMatchData &,
+ lldb::SyntheticChildrenSP &);
+/// \}
+
+template <>
+auto &LanguageCategory::GetHardcodedFinder<lldb::TypeFormatImplSP>() {
+ return m_hardcoded_formats;
+}
+
+template <>
+auto &LanguageCategory::GetHardcodedFinder<lldb::TypeSummaryImplSP>() {
+ return m_hardcoded_summaries;
+}
+
+template <>
+auto &LanguageCategory::GetHardcodedFinder<lldb::SyntheticChildrenSP>() {
+ return m_hardcoded_synthetics;
+}
+
+} // namespace lldb_private
+
+template <typename ImplSP>
+bool LanguageCategory::GetHardcoded(FormatManager &fmt_mgr,
+ FormattersMatchData &match_data,
+ ImplSP &retval_sp) {
+ if (!IsEnabled())
+ return false;
+
+ ValueObject &valobj(match_data.GetValueObject());
+ lldb::DynamicValueType use_dynamic(match_data.GetDynamicValueType());
+
+ for (auto &candidate : GetHardcodedFinder<ImplSP>()) {
+ if (auto result = candidate(valobj, use_dynamic, fmt_mgr)) {
+ retval_sp = result;
+ break;
+ }
+ }
+ return (bool)retval_sp;
+}
+
+/// Explicit instantiations for the three types.
+/// \{
+template bool LanguageCategory::GetHardcoded<lldb::TypeFormatImplSP>(
+ FormatManager &, FormattersMatchData &, lldb::TypeFormatImplSP &);
+template bool LanguageCategory::GetHardcoded<lldb::TypeSummaryImplSP>(
+ FormatManager &, FormattersMatchData &, lldb::TypeSummaryImplSP &);
+template bool LanguageCategory::GetHardcoded<lldb::SyntheticChildrenSP>(
+ FormatManager &, FormattersMatchData &, lldb::SyntheticChildrenSP &);
+/// \}
+
+lldb::TypeCategoryImplSP LanguageCategory::GetCategory() const {
+ return m_category_sp;
+}
+
+FormatCache &LanguageCategory::GetFormatCache() { return m_format_cache; }
+
+void LanguageCategory::Enable() {
+ if (m_category_sp)
+ m_category_sp->Enable(true, TypeCategoryMap::Default);
+ m_enabled = true;
+}
+
+void LanguageCategory::Disable() {
+ if (m_category_sp)
+ m_category_sp->Disable();
+ m_enabled = false;
+}
+
+bool LanguageCategory::IsEnabled() { return m_enabled; }
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/StringPrinter.cpp b/contrib/llvm-project/lldb/source/DataFormatters/StringPrinter.cpp
new file mode 100644
index 000000000000..ab07c74fd185
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/StringPrinter.cpp
@@ -0,0 +1,560 @@
+//===-- StringPrinter.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 "lldb/DataFormatters/StringPrinter.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Status.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ConvertUTF.h"
+
+#include <cctype>
+#include <locale>
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+using GetPrintableElementType = StringPrinter::GetPrintableElementType;
+using StringElementType = StringPrinter::StringElementType;
+
+/// DecodedCharBuffer stores the decoded contents of a single character. It
+/// avoids managing memory on the heap by copying decoded bytes into an in-line
+/// buffer.
+class DecodedCharBuffer {
+public:
+ DecodedCharBuffer(std::nullptr_t) {}
+
+ DecodedCharBuffer(const uint8_t *bytes, size_t size) : m_size(size) {
+ if (size > MaxLength)
+ llvm_unreachable("unsupported length");
+ memcpy(m_data, bytes, size);
+ }
+
+ DecodedCharBuffer(const char *bytes, size_t size)
+ : DecodedCharBuffer(reinterpret_cast<const uint8_t *>(bytes), size) {}
+
+ const uint8_t *GetBytes() const { return m_data; }
+
+ size_t GetSize() const { return m_size; }
+
+private:
+ static constexpr unsigned MaxLength = 16;
+
+ size_t m_size = 0;
+ uint8_t m_data[MaxLength] = {0};
+};
+
+using EscapingHelper =
+ std::function<DecodedCharBuffer(uint8_t *, uint8_t *, uint8_t *&)>;
+
+// we define this for all values of type but only implement it for those we
+// care about that's good because we get linker errors for any unsupported type
+template <StringElementType type>
+static DecodedCharBuffer
+GetPrintableImpl(uint8_t *buffer, uint8_t *buffer_end, uint8_t *&next,
+ StringPrinter::EscapeStyle escape_style);
+
+// Mimic isprint() for Unicode codepoints.
+static bool isprint32(char32_t codepoint) {
+ if (codepoint <= 0x1F || codepoint == 0x7F) // C0
+ {
+ return false;
+ }
+ if (codepoint >= 0x80 && codepoint <= 0x9F) // C1
+ {
+ return false;
+ }
+ if (codepoint == 0x2028 || codepoint == 0x2029) // line/paragraph separators
+ {
+ return false;
+ }
+ if (codepoint == 0x200E || codepoint == 0x200F ||
+ (codepoint >= 0x202A &&
+ codepoint <= 0x202E)) // bidirectional text control
+ {
+ return false;
+ }
+ if (codepoint >= 0xFFF9 &&
+ codepoint <= 0xFFFF) // interlinears and generally specials
+ {
+ return false;
+ }
+ return true;
+}
+
+DecodedCharBuffer attemptASCIIEscape(llvm::UTF32 c,
+ StringPrinter::EscapeStyle escape_style) {
+ const bool is_swift_escape_style =
+ escape_style == StringPrinter::EscapeStyle::Swift;
+ switch (c) {
+ case 0:
+ return {"\\0", 2};
+ case '\a':
+ return {"\\a", 2};
+ case '\b':
+ if (is_swift_escape_style)
+ return nullptr;
+ return {"\\b", 2};
+ case '\f':
+ if (is_swift_escape_style)
+ return nullptr;
+ return {"\\f", 2};
+ case '\n':
+ return {"\\n", 2};
+ case '\r':
+ return {"\\r", 2};
+ case '\t':
+ return {"\\t", 2};
+ case '\v':
+ if (is_swift_escape_style)
+ return nullptr;
+ return {"\\v", 2};
+ case '\"':
+ return {"\\\"", 2};
+ case '\'':
+ if (is_swift_escape_style)
+ return {"\\'", 2};
+ return nullptr;
+ case '\\':
+ return {"\\\\", 2};
+ }
+ return nullptr;
+}
+
+template <>
+DecodedCharBuffer GetPrintableImpl<StringElementType::ASCII>(
+ uint8_t *buffer, uint8_t *buffer_end, uint8_t *&next,
+ StringPrinter::EscapeStyle escape_style) {
+ // The ASCII helper always advances 1 byte at a time.
+ next = buffer + 1;
+
+ DecodedCharBuffer retval = attemptASCIIEscape(*buffer, escape_style);
+ if (retval.GetSize())
+ return retval;
+
+ // Use llvm's locale-independent isPrint(char), instead of the libc
+ // implementation which may give different results on different platforms.
+ if (llvm::isPrint(*buffer))
+ return {buffer, 1};
+
+ unsigned escaped_len;
+ constexpr unsigned max_buffer_size = 7;
+ uint8_t data[max_buffer_size];
+ switch (escape_style) {
+ case StringPrinter::EscapeStyle::CXX:
+ // Prints 4 characters, then a \0 terminator.
+ escaped_len = snprintf((char *)data, max_buffer_size, "\\x%02x", *buffer);
+ break;
+ case StringPrinter::EscapeStyle::Swift:
+ // Prints up to 6 characters, then a \0 terminator.
+ escaped_len = snprintf((char *)data, max_buffer_size, "\\u{%x}", *buffer);
+ break;
+ }
+ lldbassert(escaped_len > 0 && "unknown string escape style");
+ return {data, escaped_len};
+}
+
+template <>
+DecodedCharBuffer GetPrintableImpl<StringElementType::UTF8>(
+ uint8_t *buffer, uint8_t *buffer_end, uint8_t *&next,
+ StringPrinter::EscapeStyle escape_style) {
+ // If the utf8 encoded length is invalid (i.e., not in the closed interval
+ // [1;4]), or if there aren't enough bytes to print, or if the subsequence
+ // isn't valid utf8, fall back to printing an ASCII-escaped subsequence.
+ if (!llvm::isLegalUTF8Sequence(buffer, buffer_end))
+ return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next,
+ escape_style);
+
+ // Convert the valid utf8 sequence to a utf32 codepoint. This cannot fail.
+ llvm::UTF32 codepoint = 0;
+ const llvm::UTF8 *buffer_for_conversion = buffer;
+ llvm::ConversionResult result = llvm::convertUTF8Sequence(
+ &buffer_for_conversion, buffer_end, &codepoint, llvm::strictConversion);
+ assert(result == llvm::conversionOK &&
+ "Failed to convert legal utf8 sequence");
+ UNUSED_IF_ASSERT_DISABLED(result);
+
+ // The UTF8 helper always advances by the utf8 encoded length.
+ const unsigned utf8_encoded_len = buffer_for_conversion - buffer;
+ next = buffer + utf8_encoded_len;
+
+ DecodedCharBuffer retval = attemptASCIIEscape(codepoint, escape_style);
+ if (retval.GetSize())
+ return retval;
+ if (isprint32(codepoint))
+ return {buffer, utf8_encoded_len};
+
+ unsigned escaped_len;
+ constexpr unsigned max_buffer_size = 13;
+ uint8_t data[max_buffer_size];
+ switch (escape_style) {
+ case StringPrinter::EscapeStyle::CXX:
+ // Prints 10 characters, then a \0 terminator.
+ escaped_len = snprintf((char *)data, max_buffer_size, "\\U%08x", codepoint);
+ break;
+ case StringPrinter::EscapeStyle::Swift:
+ // Prints up to 12 characters, then a \0 terminator.
+ escaped_len = snprintf((char *)data, max_buffer_size, "\\u{%x}", codepoint);
+ break;
+ }
+ lldbassert(escaped_len > 0 && "unknown string escape style");
+ return {data, escaped_len};
+}
+
+// Given a sequence of bytes, this function returns: a sequence of bytes to
+// actually print out + a length the following unscanned position of the buffer
+// is in next
+static DecodedCharBuffer GetPrintable(StringElementType type, uint8_t *buffer,
+ uint8_t *buffer_end, uint8_t *&next,
+ StringPrinter::EscapeStyle escape_style) {
+ if (!buffer || buffer >= buffer_end)
+ return {nullptr};
+
+ switch (type) {
+ case StringElementType::ASCII:
+ return GetPrintableImpl<StringElementType::ASCII>(buffer, buffer_end, next,
+ escape_style);
+ case StringElementType::UTF8:
+ return GetPrintableImpl<StringElementType::UTF8>(buffer, buffer_end, next,
+ escape_style);
+ default:
+ return {nullptr};
+ }
+}
+
+static EscapingHelper
+GetDefaultEscapingHelper(GetPrintableElementType elem_type,
+ StringPrinter::EscapeStyle escape_style) {
+ switch (elem_type) {
+ case GetPrintableElementType::UTF8:
+ case GetPrintableElementType::ASCII:
+ return [escape_style, elem_type](uint8_t *buffer, uint8_t *buffer_end,
+ uint8_t *&next) -> DecodedCharBuffer {
+ return GetPrintable(elem_type == GetPrintableElementType::UTF8
+ ? StringElementType::UTF8
+ : StringElementType::ASCII,
+ buffer, buffer_end, next, escape_style);
+ };
+ }
+ llvm_unreachable("bad element type");
+}
+
+/// Read a string encoded in accordance with \tparam SourceDataType from a
+/// host-side LLDB buffer, then pretty-print it to a stream using \p style.
+template <typename SourceDataType>
+static bool DumpEncodedBufferToStream(
+ GetPrintableElementType style,
+ llvm::ConversionResult (*ConvertFunction)(const SourceDataType **,
+ const SourceDataType *,
+ llvm::UTF8 **, llvm::UTF8 *,
+ llvm::ConversionFlags),
+ const StringPrinter::ReadBufferAndDumpToStreamOptions &dump_options) {
+ assert(dump_options.GetStream() && "need a Stream to print the string to");
+ Stream &stream(*dump_options.GetStream());
+ if (dump_options.GetPrefixToken() != nullptr)
+ stream.Printf("%s", dump_options.GetPrefixToken());
+ if (dump_options.GetQuote() != 0)
+ stream.Printf("%c", dump_options.GetQuote());
+ auto data(dump_options.GetData());
+ auto source_size(dump_options.GetSourceSize());
+ if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd()) {
+ const int bufferSPSize = data.GetByteSize();
+ if (dump_options.GetSourceSize() == 0) {
+ const int origin_encoding = 8 * sizeof(SourceDataType);
+ source_size = bufferSPSize / (origin_encoding / 4);
+ }
+
+ const SourceDataType *data_ptr =
+ (const SourceDataType *)data.GetDataStart();
+ const SourceDataType *data_end_ptr = data_ptr + source_size;
+
+ const bool zero_is_terminator = dump_options.GetBinaryZeroIsTerminator();
+
+ if (zero_is_terminator) {
+ while (data_ptr < data_end_ptr) {
+ if (!*data_ptr) {
+ data_end_ptr = data_ptr;
+ break;
+ }
+ data_ptr++;
+ }
+
+ data_ptr = (const SourceDataType *)data.GetDataStart();
+ }
+
+ lldb::WritableDataBufferSP utf8_data_buffer_sp;
+ llvm::UTF8 *utf8_data_ptr = nullptr;
+ llvm::UTF8 *utf8_data_end_ptr = nullptr;
+
+ if (ConvertFunction) {
+ utf8_data_buffer_sp =
+ std::make_shared<DataBufferHeap>(4 * bufferSPSize, 0);
+ utf8_data_ptr = (llvm::UTF8 *)utf8_data_buffer_sp->GetBytes();
+ utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize();
+ ConvertFunction(&data_ptr, data_end_ptr, &utf8_data_ptr,
+ utf8_data_end_ptr, llvm::lenientConversion);
+ if (!zero_is_terminator)
+ utf8_data_end_ptr = utf8_data_ptr;
+ // needed because the ConvertFunction will change the value of the
+ // data_ptr.
+ utf8_data_ptr =
+ (llvm::UTF8 *)utf8_data_buffer_sp->GetBytes();
+ } else {
+ // just copy the pointers - the cast is necessary to make the compiler
+ // happy but this should only happen if we are reading UTF8 data
+ utf8_data_ptr = const_cast<llvm::UTF8 *>(
+ reinterpret_cast<const llvm::UTF8 *>(data_ptr));
+ utf8_data_end_ptr = const_cast<llvm::UTF8 *>(
+ reinterpret_cast<const llvm::UTF8 *>(data_end_ptr));
+ }
+
+ const bool escape_non_printables = dump_options.GetEscapeNonPrintables();
+ EscapingHelper escaping_callback;
+ if (escape_non_printables)
+ escaping_callback =
+ GetDefaultEscapingHelper(style, dump_options.GetEscapeStyle());
+
+ // since we tend to accept partial data (and even partially malformed data)
+ // we might end up with no NULL terminator before the end_ptr hence we need
+ // to take a slower route and ensure we stay within boundaries
+ for (; utf8_data_ptr < utf8_data_end_ptr;) {
+ if (zero_is_terminator && !*utf8_data_ptr)
+ break;
+
+ if (escape_non_printables) {
+ uint8_t *next_data = nullptr;
+ auto printable =
+ escaping_callback(utf8_data_ptr, utf8_data_end_ptr, next_data);
+ auto printable_bytes = printable.GetBytes();
+ auto printable_size = printable.GetSize();
+
+ // We failed to figure out how to print this string.
+ if (!printable_bytes || !next_data)
+ return false;
+
+ for (unsigned c = 0; c < printable_size; c++)
+ stream.Printf("%c", *(printable_bytes + c));
+ utf8_data_ptr = (uint8_t *)next_data;
+ } else {
+ stream.Printf("%c", *utf8_data_ptr);
+ utf8_data_ptr++;
+ }
+ }
+ }
+ if (dump_options.GetQuote() != 0)
+ stream.Printf("%c", dump_options.GetQuote());
+ if (dump_options.GetSuffixToken() != nullptr)
+ stream.Printf("%s", dump_options.GetSuffixToken());
+ if (dump_options.GetIsTruncated())
+ stream.Printf("...");
+ return true;
+}
+
+lldb_private::formatters::StringPrinter::ReadStringAndDumpToStreamOptions::
+ ReadStringAndDumpToStreamOptions(ValueObject &valobj)
+ : ReadStringAndDumpToStreamOptions() {
+ SetEscapeNonPrintables(
+ valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
+}
+
+lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::
+ ReadBufferAndDumpToStreamOptions(ValueObject &valobj)
+ : ReadBufferAndDumpToStreamOptions() {
+ SetEscapeNonPrintables(
+ valobj.GetTargetSP()->GetDebugger().GetEscapeNonPrintables());
+}
+
+lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStreamOptions::
+ ReadBufferAndDumpToStreamOptions(
+ const ReadStringAndDumpToStreamOptions &options)
+ : ReadBufferAndDumpToStreamOptions() {
+ SetStream(options.GetStream());
+ SetPrefixToken(options.GetPrefixToken());
+ SetSuffixToken(options.GetSuffixToken());
+ SetQuote(options.GetQuote());
+ SetEscapeNonPrintables(options.GetEscapeNonPrintables());
+ SetBinaryZeroIsTerminator(options.GetBinaryZeroIsTerminator());
+ SetEscapeStyle(options.GetEscapeStyle());
+}
+
+namespace lldb_private {
+
+namespace formatters {
+
+template <typename SourceDataType>
+static bool ReadEncodedBufferAndDumpToStream(
+ StringElementType elem_type,
+ const StringPrinter::ReadStringAndDumpToStreamOptions &options,
+ llvm::ConversionResult (*ConvertFunction)(const SourceDataType **,
+ const SourceDataType *,
+ llvm::UTF8 **, llvm::UTF8 *,
+ llvm::ConversionFlags)) {
+ assert(options.GetStream() && "need a Stream to print the string to");
+ if (!options.GetStream())
+ return false;
+
+ if (options.GetLocation() == 0 ||
+ options.GetLocation() == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb::TargetSP target_sp = options.GetTargetSP();
+ if (!target_sp)
+ return false;
+
+ constexpr int type_width = sizeof(SourceDataType);
+ constexpr int origin_encoding = 8 * type_width;
+ if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
+ return false;
+ // If not UTF8 or ASCII, conversion to UTF8 is necessary.
+ if (origin_encoding != 8 && !ConvertFunction)
+ return false;
+
+ bool needs_zero_terminator = options.GetNeedsZeroTermination();
+
+ bool is_truncated = false;
+ const auto max_size = target_sp->GetMaximumSizeOfStringSummary();
+
+ uint32_t sourceSize;
+ if (elem_type == StringElementType::ASCII && !options.GetSourceSize()) {
+ // FIXME: The NSString formatter sets HasSourceSize(true) when the size is
+ // actually unknown, as well as SetBinaryZeroIsTerminator(false). IIUC the
+ // C++ formatter also sets SetBinaryZeroIsTerminator(false) when it doesn't
+ // mean to. I don't see how this makes sense: we should fix the formatters.
+ //
+ // Until then, the behavior that's expected for ASCII strings with unknown
+ // lengths is to read up to the max size and then null-terminate. Do that.
+ sourceSize = max_size;
+ needs_zero_terminator = true;
+ } else if (options.HasSourceSize()) {
+ sourceSize = options.GetSourceSize();
+ if (!options.GetIgnoreMaxLength()) {
+ if (sourceSize > max_size) {
+ sourceSize = max_size;
+ is_truncated = true;
+ }
+ }
+ } else {
+ sourceSize = max_size;
+ needs_zero_terminator = true;
+ }
+
+ const int bufferSPSize = sourceSize * type_width;
+ lldb::WritableDataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize, 0));
+
+ // Check if we got bytes. We never get any bytes if we have an empty
+ // string, but we still continue so that we end up actually printing
+ // an empty string ("").
+ if (sourceSize != 0 && !buffer_sp->GetBytes())
+ return false;
+
+ Status error;
+ char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
+
+ if (elem_type == StringElementType::ASCII)
+ target_sp->ReadCStringFromMemory(options.GetLocation(), buffer,
+ bufferSPSize, error);
+ else if (needs_zero_terminator)
+ target_sp->ReadStringFromMemory(options.GetLocation(), buffer,
+ bufferSPSize, error, type_width);
+ else
+ target_sp->ReadMemory(options.GetLocation(), buffer, bufferSPSize, error);
+ if (error.Fail()) {
+ options.GetStream()->Printf("unable to read data");
+ return true;
+ }
+
+ StringPrinter::ReadBufferAndDumpToStreamOptions dump_options(options);
+ dump_options.SetData(
+ DataExtractor(buffer_sp, target_sp->GetArchitecture().GetByteOrder(),
+ target_sp->GetArchitecture().GetAddressByteSize()));
+ dump_options.SetSourceSize(sourceSize);
+ dump_options.SetIsTruncated(is_truncated);
+ dump_options.SetNeedsZeroTermination(needs_zero_terminator);
+ if (needs_zero_terminator)
+ dump_options.SetBinaryZeroIsTerminator(true);
+
+ GetPrintableElementType print_style = (elem_type == StringElementType::ASCII)
+ ? GetPrintableElementType::ASCII
+ : GetPrintableElementType::UTF8;
+ return DumpEncodedBufferToStream(print_style, ConvertFunction, dump_options);
+}
+
+template <>
+bool StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF8>(
+ const ReadStringAndDumpToStreamOptions &options) {
+ return ReadEncodedBufferAndDumpToStream<llvm::UTF8>(StringElementType::UTF8,
+ options, nullptr);
+}
+
+template <>
+bool StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF16>(
+ const ReadStringAndDumpToStreamOptions &options) {
+ return ReadEncodedBufferAndDumpToStream<llvm::UTF16>(
+ StringElementType::UTF16, options, llvm::ConvertUTF16toUTF8);
+}
+
+template <>
+bool StringPrinter::ReadStringAndDumpToStream<StringElementType::UTF32>(
+ const ReadStringAndDumpToStreamOptions &options) {
+ return ReadEncodedBufferAndDumpToStream<llvm::UTF32>(
+ StringElementType::UTF32, options, llvm::ConvertUTF32toUTF8);
+}
+
+template <>
+bool StringPrinter::ReadStringAndDumpToStream<StringElementType::ASCII>(
+ const ReadStringAndDumpToStreamOptions &options) {
+ return ReadEncodedBufferAndDumpToStream<char>(StringElementType::ASCII,
+ options, nullptr);
+}
+
+template <>
+bool StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF8>(
+ const ReadBufferAndDumpToStreamOptions &options) {
+ return DumpEncodedBufferToStream<llvm::UTF8>(GetPrintableElementType::UTF8,
+ nullptr, options);
+}
+
+template <>
+bool StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF16>(
+ const ReadBufferAndDumpToStreamOptions &options) {
+ return DumpEncodedBufferToStream(GetPrintableElementType::UTF8,
+ llvm::ConvertUTF16toUTF8, options);
+}
+
+template <>
+bool StringPrinter::ReadBufferAndDumpToStream<StringElementType::UTF32>(
+ const ReadBufferAndDumpToStreamOptions &options) {
+ return DumpEncodedBufferToStream(GetPrintableElementType::UTF8,
+ llvm::ConvertUTF32toUTF8, options);
+}
+
+template <>
+bool StringPrinter::ReadBufferAndDumpToStream<StringElementType::ASCII>(
+ const ReadBufferAndDumpToStreamOptions &options) {
+ // Treat ASCII the same as UTF8.
+ //
+ // FIXME: This is probably not the right thing to do (well, it's debatable).
+ // If an ASCII-encoded string happens to contain a sequence of invalid bytes
+ // that forms a valid UTF8 character, we'll print out that character. This is
+ // good if you're playing fast and loose with encodings (probably good for
+ // std::string users), but maybe not so good if you care about your string
+ // formatter respecting the semantics of your selected string encoding. In
+ // the latter case you'd want to see the character byte sequence ('\x..'), not
+ // the UTF8 character itself.
+ return ReadBufferAndDumpToStream<StringElementType::UTF8>(options);
+}
+
+} // namespace formatters
+
+} // namespace lldb_private
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeCategory.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeCategory.cpp
new file mode 100644
index 000000000000..4d8663ea9c03
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeCategory.cpp
@@ -0,0 +1,334 @@
+//===-- TypeCategory.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 "lldb/DataFormatters/TypeCategory.h"
+#include "lldb/Target/Language.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeCategoryImpl::TypeCategoryImpl(IFormatChangeListener *clist,
+ ConstString name)
+ : m_format_cont(clist), m_summary_cont(clist), m_filter_cont(clist),
+ m_synth_cont(clist), m_enabled(false), m_change_listener(clist),
+ m_mutex(), m_name(name), m_languages() {}
+
+static bool IsApplicable(lldb::LanguageType category_lang,
+ lldb::LanguageType valobj_lang) {
+ switch (category_lang) {
+ // Unless we know better, allow only exact equality.
+ default:
+ return category_lang == valobj_lang;
+
+ // the C family, we consider it as one
+ case eLanguageTypeC89:
+ case eLanguageTypeC:
+ case eLanguageTypeC99:
+ return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
+ valobj_lang == eLanguageTypeC99;
+
+ // ObjC knows about C and itself
+ case eLanguageTypeObjC:
+ return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
+ valobj_lang == eLanguageTypeC99 || valobj_lang == eLanguageTypeObjC;
+
+ // C++ knows about C and C++
+ case eLanguageTypeC_plus_plus:
+ return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
+ valobj_lang == eLanguageTypeC99 ||
+ valobj_lang == eLanguageTypeC_plus_plus;
+
+ // ObjC++ knows about C,C++,ObjC and ObjC++
+ case eLanguageTypeObjC_plus_plus:
+ return valobj_lang == eLanguageTypeC89 || valobj_lang == eLanguageTypeC ||
+ valobj_lang == eLanguageTypeC99 ||
+ valobj_lang == eLanguageTypeC_plus_plus ||
+ valobj_lang == eLanguageTypeObjC;
+
+ // Categories with unspecified language match everything.
+ case eLanguageTypeUnknown:
+ return true;
+ }
+}
+
+bool TypeCategoryImpl::IsApplicable(lldb::LanguageType lang) {
+ for (size_t idx = 0; idx < GetNumLanguages(); idx++) {
+ const lldb::LanguageType category_lang = GetLanguageAtIndex(idx);
+ if (::IsApplicable(category_lang, lang))
+ return true;
+ }
+ return false;
+}
+
+size_t TypeCategoryImpl::GetNumLanguages() {
+ if (m_languages.empty())
+ return 1;
+ return m_languages.size();
+}
+
+lldb::LanguageType TypeCategoryImpl::GetLanguageAtIndex(size_t idx) {
+ if (m_languages.empty())
+ return lldb::eLanguageTypeUnknown;
+ return m_languages[idx];
+}
+
+void TypeCategoryImpl::AddLanguage(lldb::LanguageType lang) {
+ m_languages.push_back(lang);
+}
+
+bool TypeCategoryImpl::Get(lldb::LanguageType lang,
+ const FormattersMatchVector &candidates,
+ lldb::TypeFormatImplSP &entry) {
+ if (!IsEnabled() || !IsApplicable(lang))
+ return false;
+ return m_format_cont.Get(candidates, entry);
+}
+
+bool TypeCategoryImpl::Get(lldb::LanguageType lang,
+ const FormattersMatchVector &candidates,
+ lldb::TypeSummaryImplSP &entry) {
+ if (!IsEnabled() || !IsApplicable(lang))
+ return false;
+ return m_summary_cont.Get(candidates, entry);
+}
+
+bool TypeCategoryImpl::Get(lldb::LanguageType lang,
+ const FormattersMatchVector &candidates,
+ lldb::SyntheticChildrenSP &entry) {
+ if (!IsEnabled() || !IsApplicable(lang))
+ return false;
+
+ // first find both Filter and Synth, and then check which is most recent
+ bool pick_synth = false;
+
+ TypeFilterImpl::SharedPointer filter_sp;
+ m_filter_cont.Get(candidates, filter_sp);
+
+ ScriptedSyntheticChildren::SharedPointer synth_sp;
+ m_synth_cont.Get(candidates, synth_sp);
+
+ if (!filter_sp.get() && !synth_sp.get())
+ return false;
+ else if (!filter_sp.get() && synth_sp.get())
+ pick_synth = true;
+ else if (filter_sp.get() && !synth_sp.get())
+ pick_synth = false;
+ else /*if (filter_sp.get() && synth_sp.get())*/
+ {
+ pick_synth = filter_sp->GetRevision() <= synth_sp->GetRevision();
+ }
+
+ if (pick_synth) {
+ entry = synth_sp;
+ return true;
+ } else {
+ entry = filter_sp;
+ return true;
+ }
+ return false;
+}
+
+void TypeCategoryImpl::Clear(FormatCategoryItems items) {
+ if (items & eFormatCategoryItemFormat)
+ m_format_cont.Clear();
+
+ if (items & eFormatCategoryItemSummary)
+ m_summary_cont.Clear();
+
+ if (items & eFormatCategoryItemFilter)
+ m_filter_cont.Clear();
+
+ if (items & eFormatCategoryItemSynth)
+ m_synth_cont.Clear();
+}
+
+bool TypeCategoryImpl::Delete(ConstString name, FormatCategoryItems items) {
+ bool success = false;
+
+ if (items & eFormatCategoryItemFormat)
+ success = m_format_cont.Delete(name) || success;
+
+ if (items & eFormatCategoryItemSummary)
+ success = m_summary_cont.Delete(name) || success;
+
+ if (items & eFormatCategoryItemFilter)
+ success = m_filter_cont.Delete(name) || success;
+
+ if (items & eFormatCategoryItemSynth)
+ success = m_synth_cont.Delete(name) || success;
+
+ return success;
+}
+
+uint32_t TypeCategoryImpl::GetCount(FormatCategoryItems items) {
+ uint32_t count = 0;
+
+ if (items & eFormatCategoryItemFormat)
+ count += m_format_cont.GetCount();
+
+ if (items & eFormatCategoryItemSummary)
+ count += m_summary_cont.GetCount();
+
+ if (items & eFormatCategoryItemFilter)
+ count += m_filter_cont.GetCount();
+
+ if (items & eFormatCategoryItemSynth)
+ count += m_synth_cont.GetCount();
+
+ return count;
+}
+
+bool TypeCategoryImpl::AnyMatches(
+ const FormattersMatchCandidate &candidate_type, FormatCategoryItems items,
+ bool only_enabled, const char **matching_category,
+ FormatCategoryItems *matching_type) {
+ if (!IsEnabled() && only_enabled)
+ return false;
+
+ if (items & eFormatCategoryItemFormat) {
+ if (m_format_cont.AnyMatches(candidate_type)) {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemFormat;
+ return true;
+ }
+ }
+
+ if (items & eFormatCategoryItemSummary) {
+ if (m_summary_cont.AnyMatches(candidate_type)) {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemSummary;
+ return true;
+ }
+ }
+
+ if (items & eFormatCategoryItemFilter) {
+ if (m_filter_cont.AnyMatches(candidate_type)) {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemFilter;
+ return true;
+ }
+ }
+
+ if (items & eFormatCategoryItemSynth) {
+ if (m_synth_cont.AnyMatches(candidate_type)) {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemSynth;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void TypeCategoryImpl::AutoComplete(CompletionRequest &request,
+ FormatCategoryItems items) {
+ if (items & eFormatCategoryItemFormat)
+ m_format_cont.AutoComplete(request);
+ if (items & eFormatCategoryItemSummary)
+ m_summary_cont.AutoComplete(request);
+ if (items & eFormatCategoryItemFilter)
+ m_filter_cont.AutoComplete(request);
+ if (items & eFormatCategoryItemSynth)
+ m_synth_cont.AutoComplete(request);
+}
+
+TypeCategoryImpl::FormatContainer::MapValueType
+TypeCategoryImpl::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return m_format_cont.GetForTypeNameSpecifier(type_sp);
+}
+
+TypeCategoryImpl::SummaryContainer::MapValueType
+TypeCategoryImpl::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return m_summary_cont.GetForTypeNameSpecifier(type_sp);
+}
+
+TypeCategoryImpl::FilterContainer::MapValueType
+TypeCategoryImpl::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return m_filter_cont.GetForTypeNameSpecifier(type_sp);
+}
+
+TypeCategoryImpl::SynthContainer::MapValueType
+TypeCategoryImpl::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) {
+ return m_synth_cont.GetForTypeNameSpecifier(type_sp);
+}
+
+TypeCategoryImpl::FormatContainer::MapValueType
+TypeCategoryImpl::GetFormatAtIndex(size_t index) {
+ return m_format_cont.GetAtIndex(index);
+}
+
+TypeCategoryImpl::SummaryContainer::MapValueType
+TypeCategoryImpl::GetSummaryAtIndex(size_t index) {
+ return m_summary_cont.GetAtIndex(index);
+}
+
+TypeCategoryImpl::FilterContainer::MapValueType
+TypeCategoryImpl::GetFilterAtIndex(size_t index) {
+ return m_filter_cont.GetAtIndex(index);
+}
+
+TypeCategoryImpl::SynthContainer::MapValueType
+TypeCategoryImpl::GetSyntheticAtIndex(size_t index) {
+ return m_synth_cont.GetAtIndex(index);
+}
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForFormatAtIndex(size_t index) {
+ return m_format_cont.GetTypeNameSpecifierAtIndex(index);
+}
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex(size_t index) {
+ return m_summary_cont.GetTypeNameSpecifierAtIndex(index);
+}
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForFilterAtIndex(size_t index) {
+ return m_filter_cont.GetTypeNameSpecifierAtIndex(index);
+}
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex(size_t index) {
+ return m_synth_cont.GetTypeNameSpecifierAtIndex(index);
+}
+
+void TypeCategoryImpl::Enable(bool value, uint32_t position) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if ((m_enabled = value))
+ m_enabled_position = position;
+ if (m_change_listener)
+ m_change_listener->Changed();
+}
+
+std::string TypeCategoryImpl::GetDescription() {
+ StreamString stream;
+ stream.Printf("%s (%s", GetName(), (IsEnabled() ? "enabled" : "disabled"));
+ StreamString lang_stream;
+ lang_stream.Printf(", applicable for language(s): ");
+ bool print_lang = false;
+ for (size_t idx = 0; idx < GetNumLanguages(); idx++) {
+ const lldb::LanguageType lang = GetLanguageAtIndex(idx);
+ if (lang != lldb::eLanguageTypeUnknown)
+ print_lang = true;
+ lang_stream.Printf("%s%s", Language::GetNameForLanguageType(lang),
+ idx + 1 < GetNumLanguages() ? ", " : "");
+ }
+ if (print_lang)
+ stream.PutCString(lang_stream.GetString());
+ stream.PutChar(')');
+ return std::string(stream.GetString());
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp
new file mode 100644
index 000000000000..ce2cf369b5be
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp
@@ -0,0 +1,265 @@
+//===-- TypeCategoryMap.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 "lldb/DataFormatters/TypeCategoryMap.h"
+
+#include "lldb/DataFormatters/FormatClasses.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst)
+ : m_map_mutex(), listener(lst), m_map(), m_active_categories() {
+ ConstString default_cs("default");
+ lldb::TypeCategoryImplSP default_sp =
+ lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs));
+ Add(default_cs, default_sp);
+ Enable(default_cs, First);
+}
+
+void TypeCategoryMap::Add(KeyType name, const TypeCategoryImplSP &entry) {
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ m_map[name] = entry;
+ }
+ // Release the mutex to avoid a potential deadlock between
+ // TypeCategoryMap::m_map_mutex and
+ // FormatManager::m_language_categories_mutex which can be acquired in
+ // reverse order when calling FormatManager::Changed.
+ if (listener)
+ listener->Changed();
+}
+
+bool TypeCategoryMap::Delete(KeyType name) {
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ MapIterator iter = m_map.find(name);
+ if (iter == m_map.end())
+ return false;
+ m_map.erase(name);
+ Disable(name);
+ }
+ // Release the mutex to avoid a potential deadlock between
+ // TypeCategoryMap::m_map_mutex and
+ // FormatManager::m_language_categories_mutex which can be acquired in
+ // reverse order when calling FormatManager::Changed.
+ if (listener)
+ listener->Changed();
+ return true;
+}
+
+bool TypeCategoryMap::Enable(KeyType category_name, Position pos) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ TypeCategoryImplSP category;
+ if (!Get(category_name, category))
+ return false;
+ return Enable(category, pos);
+}
+
+bool TypeCategoryMap::Disable(KeyType category_name) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ TypeCategoryImplSP category;
+ if (!Get(category_name, category))
+ return false;
+ return Disable(category);
+}
+
+bool TypeCategoryMap::Enable(TypeCategoryImplSP category, Position pos) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ if (category.get()) {
+ Position pos_w = pos;
+ if (pos == First || m_active_categories.size() == 0)
+ m_active_categories.push_front(category);
+ else if (pos == Last || pos == m_active_categories.size())
+ m_active_categories.push_back(category);
+ else if (pos < m_active_categories.size()) {
+ ActiveCategoriesList::iterator iter = m_active_categories.begin();
+ while (pos_w) {
+ pos_w--, iter++;
+ }
+ m_active_categories.insert(iter, category);
+ } else
+ return false;
+ category->Enable(true, pos);
+ return true;
+ }
+ return false;
+}
+
+bool TypeCategoryMap::Disable(TypeCategoryImplSP category) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ if (category.get()) {
+ m_active_categories.remove_if(delete_matching_categories(category));
+ category->Disable();
+ return true;
+ }
+ return false;
+}
+
+void TypeCategoryMap::EnableAllCategories() {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ std::vector<TypeCategoryImplSP> sorted_categories(m_map.size(), TypeCategoryImplSP());
+ MapType::iterator iter = m_map.begin(), end = m_map.end();
+ for (; iter != end; ++iter) {
+ if (iter->second->IsEnabled())
+ continue;
+ auto pos = iter->second->GetLastEnabledPosition();
+ if (pos >= sorted_categories.size()) {
+ auto iter = std::find_if(
+ sorted_categories.begin(), sorted_categories.end(),
+ [](const TypeCategoryImplSP &sp) -> bool { return sp.get() == nullptr; });
+ pos = std::distance(sorted_categories.begin(), iter);
+ }
+ sorted_categories.at(pos) = iter->second;
+ }
+ decltype(sorted_categories)::iterator viter = sorted_categories.begin(),
+ vend = sorted_categories.end();
+ for (; viter != vend; viter++)
+ if (*viter)
+ Enable(*viter, Last);
+}
+
+void TypeCategoryMap::DisableAllCategories() {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ for (Position p = First; !m_active_categories.empty(); p++) {
+ m_active_categories.front()->SetEnabledPosition(p);
+ Disable(m_active_categories.front());
+ }
+}
+
+void TypeCategoryMap::Clear() {
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ m_map.clear();
+ m_active_categories.clear();
+ }
+ // Release the mutex to avoid a potential deadlock between
+ // TypeCategoryMap::m_map_mutex and
+ // FormatManager::m_language_categories_mutex which can be acquired in
+ // reverse order when calling FormatManager::Changed.
+ if (listener)
+ listener->Changed();
+}
+
+bool TypeCategoryMap::Get(KeyType name, TypeCategoryImplSP &entry) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+ MapIterator iter = m_map.find(name);
+ if (iter == m_map.end())
+ return false;
+ entry = iter->second;
+ return true;
+}
+
+bool TypeCategoryMap::AnyMatches(
+ const FormattersMatchCandidate &candidate_type,
+ TypeCategoryImpl::FormatCategoryItems items, bool only_enabled,
+ const char **matching_category,
+ TypeCategoryImpl::FormatCategoryItems *matching_type) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++) {
+ if (pos->second->AnyMatches(candidate_type, items, only_enabled,
+ matching_category, matching_type))
+ return true;
+ }
+ return false;
+}
+
+template <typename ImplSP>
+void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+
+ ActiveCategoriesIterator begin, end = m_active_categories.end();
+
+ Log *log = GetLog(LLDBLog::DataFormatters);
+
+ if (log) {
+ for (auto match : match_data.GetMatchesVector()) {
+ LLDB_LOGF(
+ log,
+ "[%s] candidate match = %s %s %s %s",
+ __FUNCTION__,
+ match.GetTypeName().GetCString(),
+ match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers",
+ match.DidStripReference() ? "strip-reference" : "no-strip-reference",
+ match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef");
+ }
+ }
+
+ for (begin = m_active_categories.begin(); begin != end; begin++) {
+ lldb::TypeCategoryImplSP category_sp = *begin;
+ ImplSP current_format;
+ LLDB_LOGF(log, "[%s] Trying to use category %s", __FUNCTION__,
+ category_sp->GetName());
+ if (!category_sp->Get(
+ match_data.GetValueObject().GetObjectRuntimeLanguage(),
+ match_data.GetMatchesVector(), current_format))
+ continue;
+
+ retval = std::move(current_format);
+ return;
+ }
+ LLDB_LOGF(log, "[%s] nothing found - returning empty SP", __FUNCTION__);
+}
+
+/// Explicit instantiations for the three types.
+/// \{
+template void
+TypeCategoryMap::Get<lldb::TypeFormatImplSP>(FormattersMatchData &match_data,
+ lldb::TypeFormatImplSP &retval);
+template void
+TypeCategoryMap::Get<lldb::TypeSummaryImplSP>(FormattersMatchData &match_data,
+ lldb::TypeSummaryImplSP &retval);
+template void TypeCategoryMap::Get<lldb::SyntheticChildrenSP>(
+ FormattersMatchData &match_data, lldb::SyntheticChildrenSP &retval);
+/// \}
+
+void TypeCategoryMap::ForEach(ForEachCallback callback) {
+ if (callback) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+
+ // loop through enabled categories in respective order
+ {
+ ActiveCategoriesIterator begin, end = m_active_categories.end();
+ for (begin = m_active_categories.begin(); begin != end; begin++) {
+ lldb::TypeCategoryImplSP category = *begin;
+ if (!callback(category))
+ break;
+ }
+ }
+
+ // loop through disabled categories in just any order
+ {
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++) {
+ if (pos->second->IsEnabled())
+ continue;
+ if (!callback(pos->second))
+ break;
+ }
+ }
+ }
+}
+
+TypeCategoryImplSP TypeCategoryMap::GetAtIndex(uint32_t index) {
+ std::lock_guard<std::recursive_mutex> guard(m_map_mutex);
+
+ if (index < m_map.size()) {
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++) {
+ if (index == 0)
+ return pos->second;
+ index--;
+ }
+ }
+
+ return TypeCategoryImplSP();
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeFormat.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeFormat.cpp
new file mode 100644
index 000000000000..409c452110bd
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeFormat.cpp
@@ -0,0 +1,205 @@
+//===-- TypeFormat.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 "lldb/DataFormatters/TypeFormat.h"
+
+
+
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-public.h"
+
+#include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeFormatImpl::TypeFormatImpl(const Flags &flags) : m_flags(flags) {}
+
+TypeFormatImpl::~TypeFormatImpl() = default;
+
+TypeFormatImpl_Format::TypeFormatImpl_Format(lldb::Format f,
+ const TypeFormatImpl::Flags &flags)
+ : TypeFormatImpl(flags), m_format(f) {}
+
+TypeFormatImpl_Format::~TypeFormatImpl_Format() = default;
+
+bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj,
+ std::string &dest) const {
+ if (!valobj)
+ return false;
+ if (valobj->CanProvideValue()) {
+ Value &value(valobj->GetValue());
+ const Value::ContextType context_type = value.GetContextType();
+ ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
+ DataExtractor data;
+
+ if (context_type == Value::ContextType::RegisterInfo) {
+ const RegisterInfo *reg_info = value.GetRegisterInfo();
+ if (reg_info) {
+ Status error;
+ valobj->GetData(data, error);
+ if (error.Fail())
+ return false;
+
+ StreamString reg_sstr;
+ DumpDataExtractor(data, &reg_sstr, 0, GetFormat(), reg_info->byte_size,
+ 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0,
+ exe_ctx.GetBestExecutionContextScope());
+ dest = std::string(reg_sstr.GetString());
+ }
+ } else {
+ CompilerType compiler_type = value.GetCompilerType();
+ if (compiler_type) {
+ // put custom bytes to display in the DataExtractor to override the
+ // default value logic
+ if (GetFormat() == eFormatCString) {
+ lldb_private::Flags type_flags(compiler_type.GetTypeInfo(
+ nullptr)); // disambiguate w.r.t. TypeFormatImpl::Flags
+ if (type_flags.Test(eTypeIsPointer) &&
+ !type_flags.Test(eTypeIsObjC)) {
+ // if we are dumping a pointer as a c-string, get the pointee data
+ // as a string
+ TargetSP target_sp(valobj->GetTargetSP());
+ if (target_sp) {
+ size_t max_len = target_sp->GetMaximumSizeOfStringSummary();
+ Status error;
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(max_len + 1, 0));
+ Address address(valobj->GetPointerValue());
+ target_sp->ReadCStringFromMemory(
+ address, (char *)buffer_sp->GetBytes(), max_len, error);
+ if (error.Success())
+ data.SetData(buffer_sp);
+ }
+ }
+ } else {
+ Status error;
+ valobj->GetData(data, error);
+ if (error.Fail())
+ return false;
+ }
+
+ ExecutionContextScope *exe_scope =
+ exe_ctx.GetBestExecutionContextScope();
+ std::optional<uint64_t> size = compiler_type.GetByteSize(exe_scope);
+ if (!size)
+ return false;
+ StreamString sstr;
+ compiler_type.DumpTypeValue(
+ &sstr, // The stream to use for display
+ GetFormat(), // Format to display this type with
+ data, // Data to extract from
+ 0, // Byte offset into "m_data"
+ *size, // Byte size of item in "m_data"
+ valobj->GetBitfieldBitSize(), // Bitfield bit size
+ valobj->GetBitfieldBitOffset(), // Bitfield bit offset
+ exe_scope);
+ // Given that we do not want to set the ValueObject's m_error for a
+ // formatting error (or else we wouldn't be able to reformat until a
+ // next update), an empty string is treated as a "false" return from
+ // here, but that's about as severe as we get
+ // CompilerType::DumpTypeValue() should always return something, even
+ // if that something is an error message
+ dest = std::string(sstr.GetString());
+ }
+ }
+ return !dest.empty();
+ } else
+ return false;
+}
+
+std::string TypeFormatImpl_Format::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("%s%s%s%s", FormatManager::GetFormatAsCString(GetFormat()),
+ Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "");
+ return std::string(sstr.GetString());
+}
+
+TypeFormatImpl_EnumType::TypeFormatImpl_EnumType(
+ ConstString type_name, const TypeFormatImpl::Flags &flags)
+ : TypeFormatImpl(flags), m_enum_type(type_name), m_types() {}
+
+TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType() = default;
+
+bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj,
+ std::string &dest) const {
+ dest.clear();
+ if (!valobj)
+ return false;
+ if (!valobj->CanProvideValue())
+ return false;
+ ProcessSP process_sp;
+ TargetSP target_sp;
+ void *valobj_key = (process_sp = valobj->GetProcessSP()).get();
+ if (!valobj_key)
+ valobj_key = (target_sp = valobj->GetTargetSP()).get();
+ else
+ target_sp = process_sp->GetTarget().shared_from_this();
+ if (!valobj_key)
+ return false;
+ auto iter = m_types.find(valobj_key), end = m_types.end();
+ CompilerType valobj_enum_type;
+ if (iter == end) {
+ // probably a redundant check
+ if (!target_sp)
+ return false;
+ const ModuleList &images(target_sp->GetImages());
+ TypeQuery query(m_enum_type.GetStringRef());
+ TypeResults results;
+ images.FindTypes(nullptr, query, results);
+ if (results.GetTypeMap().Empty())
+ return false;
+ for (lldb::TypeSP type_sp : results.GetTypeMap().Types()) {
+ if (!type_sp)
+ continue;
+ if ((type_sp->GetForwardCompilerType().GetTypeInfo() &
+ eTypeIsEnumeration) == eTypeIsEnumeration) {
+ valobj_enum_type = type_sp->GetFullCompilerType();
+ m_types.emplace(valobj_key, valobj_enum_type);
+ break;
+ }
+ }
+ } else
+ valobj_enum_type = iter->second;
+ if (!valobj_enum_type.IsValid())
+ return false;
+ DataExtractor data;
+ Status error;
+ valobj->GetData(data, error);
+ if (error.Fail())
+ return false;
+ ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
+ StreamString sstr;
+ valobj_enum_type.DumpTypeValue(&sstr, lldb::eFormatEnum, data, 0,
+ data.GetByteSize(), 0, 0,
+ exe_ctx.GetBestExecutionContextScope());
+ if (!sstr.GetString().empty())
+ dest = std::string(sstr.GetString());
+ return !dest.empty();
+}
+
+std::string TypeFormatImpl_EnumType::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("as type %s%s%s%s", m_enum_type.AsCString("<invalid type>"),
+ Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "");
+ return std::string(sstr.GetString());
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp
new file mode 100644
index 000000000000..3707d2d879d3
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp
@@ -0,0 +1,203 @@
+//===-- TypeSummary.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 "lldb/DataFormatters/TypeSummary.h"
+
+
+
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-public.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/ValueObjectPrinter.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeSummaryOptions::TypeSummaryOptions() = default;
+
+lldb::LanguageType TypeSummaryOptions::GetLanguage() const { return m_lang; }
+
+lldb::TypeSummaryCapping TypeSummaryOptions::GetCapping() const {
+ return m_capping;
+}
+
+TypeSummaryOptions &TypeSummaryOptions::SetLanguage(lldb::LanguageType lang) {
+ m_lang = lang;
+ return *this;
+}
+
+TypeSummaryOptions &
+TypeSummaryOptions::SetCapping(lldb::TypeSummaryCapping cap) {
+ m_capping = cap;
+ return *this;
+}
+
+TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags)
+ : m_flags(flags), m_kind(kind) {}
+
+StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags,
+ const char *format_cstr)
+ : TypeSummaryImpl(Kind::eSummaryString, flags), m_format_str() {
+ SetSummaryString(format_cstr);
+}
+
+void StringSummaryFormat::SetSummaryString(const char *format_cstr) {
+ m_format.Clear();
+ if (format_cstr && format_cstr[0]) {
+ m_format_str = format_cstr;
+ m_error = FormatEntity::Parse(format_cstr, m_format);
+ } else {
+ m_format_str.clear();
+ m_error.Clear();
+ }
+}
+
+bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
+ const TypeSummaryOptions &options) {
+ if (!valobj) {
+ retval.assign("NULL ValueObject");
+ return false;
+ }
+
+ StreamString s;
+ ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
+ SymbolContext sc;
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ sc = frame->GetSymbolContext(lldb::eSymbolContextEverything);
+
+ if (IsOneLiner()) {
+ // We've already checked the case of a NULL valobj above. Let's put in an
+ // assert here to make sure someone doesn't take that out:
+ assert(valobj && "Must have a valid ValueObject to summarize");
+ ValueObjectPrinter printer(*valobj, &s, DumpValueObjectOptions());
+ printer.PrintChildrenOneLiner(HideNames(valobj));
+ retval = std::string(s.GetString());
+ return true;
+ } else {
+ if (FormatEntity::Format(m_format, s, &sc, &exe_ctx,
+ &sc.line_entry.range.GetBaseAddress(), valobj,
+ false, false)) {
+ retval.assign(std::string(s.GetString()));
+ return true;
+ } else {
+ retval.assign("error: summary string parsing error");
+ return false;
+ }
+ }
+}
+
+std::string StringSummaryFormat::GetDescription() {
+ StreamString sstr;
+
+ sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s", m_format_str.c_str(),
+ m_error.Fail() ? " error: " : "",
+ m_error.Fail() ? m_error.AsCString() : "",
+ Cascades() ? "" : " (not cascading)",
+ !DoesPrintChildren(nullptr) ? "" : " (show children)",
+ !DoesPrintValue(nullptr) ? " (hide value)" : "",
+ IsOneLiner() ? " (one-line printout)" : "",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ HideNames(nullptr) ? " (hide member names)" : "");
+ return std::string(sstr.GetString());
+}
+
+CXXFunctionSummaryFormat::CXXFunctionSummaryFormat(
+ const TypeSummaryImpl::Flags &flags, Callback impl, const char *description)
+ : TypeSummaryImpl(Kind::eCallback, flags), m_impl(impl),
+ m_description(description ? description : "") {}
+
+bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj,
+ std::string &dest,
+ const TypeSummaryOptions &options) {
+ dest.clear();
+ StreamString stream;
+ if (!m_impl || !m_impl(*valobj, stream, options))
+ return false;
+ dest = std::string(stream.GetString());
+ return true;
+}
+
+std::string CXXFunctionSummaryFormat::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("%s%s%s%s%s%s%s %s", Cascades() ? "" : " (not cascading)",
+ !DoesPrintChildren(nullptr) ? "" : " (show children)",
+ !DoesPrintValue(nullptr) ? " (hide value)" : "",
+ IsOneLiner() ? " (one-line printout)" : "",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ HideNames(nullptr) ? " (hide member names)" : "",
+ m_description.c_str());
+ return std::string(sstr.GetString());
+}
+
+ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags,
+ const char *function_name,
+ const char *python_script)
+ : TypeSummaryImpl(Kind::eScript, flags), m_function_name(),
+ m_python_script(), m_script_function_sp() {
+ if (function_name)
+ m_function_name.assign(function_name);
+ if (python_script)
+ m_python_script.assign(python_script);
+}
+
+bool ScriptSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval,
+ const TypeSummaryOptions &options) {
+ if (!valobj)
+ return false;
+
+ TargetSP target_sp(valobj->GetTargetSP());
+
+ if (!target_sp) {
+ retval.assign("error: no target");
+ return false;
+ }
+
+ ScriptInterpreter *script_interpreter =
+ target_sp->GetDebugger().GetScriptInterpreter();
+
+ if (!script_interpreter) {
+ retval.assign("error: no ScriptInterpreter");
+ return false;
+ }
+
+ return script_interpreter->GetScriptedSummary(
+ m_function_name.c_str(), valobj->GetSP(), m_script_function_sp, options,
+ retval);
+}
+
+std::string ScriptSummaryFormat::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("%s%s%s%s%s%s%s\n ", Cascades() ? "" : " (not cascading)",
+ !DoesPrintChildren(nullptr) ? "" : " (show children)",
+ !DoesPrintValue(nullptr) ? " (hide value)" : "",
+ IsOneLiner() ? " (one-line printout)" : "",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ HideNames(nullptr) ? " (hide member names)" : "");
+ if (m_python_script.empty()) {
+ if (m_function_name.empty()) {
+ sstr.PutCString("no backing script");
+ } else {
+ sstr.PutCString(m_function_name);
+ }
+ } else {
+ sstr.PutCString(m_python_script);
+ }
+ return std::string(sstr.GetString());
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp
new file mode 100644
index 000000000000..7aa0670190b2
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp
@@ -0,0 +1,251 @@
+//===-- TypeSynthetic.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 "lldb/lldb-enumerations.h"
+#include "lldb/lldb-public.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Symbol/CompilerType.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void TypeFilterImpl::AddExpressionPath(const std::string &path) {
+ bool need_add_dot = true;
+ if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
+ need_add_dot = false;
+ // add a '.' symbol to help forgetful users
+ if (!need_add_dot)
+ m_expression_paths.push_back(path);
+ else
+ m_expression_paths.push_back(std::string(".") + path);
+}
+
+bool TypeFilterImpl::SetExpressionPathAtIndex(size_t i,
+ const std::string &path) {
+ if (i >= GetCount())
+ return false;
+ bool need_add_dot = true;
+ if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
+ need_add_dot = false;
+ // add a '.' symbol to help forgetful users
+ if (!need_add_dot)
+ m_expression_paths[i] = path;
+ else
+ m_expression_paths[i] = std::string(".") + path;
+ return true;
+}
+
+size_t
+TypeFilterImpl::FrontEnd::GetIndexOfChildWithName(ConstString name) {
+ const char *name_cstr = name.GetCString();
+ if (name_cstr) {
+ for (size_t i = 0; i < filter->GetCount(); i++) {
+ const char *expr_cstr = filter->GetExpressionPathAtIndex(i);
+ if (expr_cstr) {
+ if (*expr_cstr == '.')
+ expr_cstr++;
+ else if (*expr_cstr == '-' && *(expr_cstr + 1) == '>')
+ expr_cstr += 2;
+ }
+ if (expr_cstr) {
+ if (!::strcmp(name_cstr, expr_cstr))
+ return i;
+ }
+ }
+ }
+ return UINT32_MAX;
+}
+
+std::string TypeFilterImpl::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("%s%s%s {\n", Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "");
+
+ for (size_t i = 0; i < GetCount(); i++) {
+ sstr.Printf(" %s\n", GetExpressionPathAtIndex(i));
+ }
+
+ sstr.Printf("}");
+ return std::string(sstr.GetString());
+}
+
+SyntheticChildren::SyntheticChildren(const Flags &flags) : m_flags(flags) {}
+
+SyntheticChildren::~SyntheticChildren() = default;
+
+CXXSyntheticChildren::CXXSyntheticChildren(
+ const SyntheticChildren::Flags &flags, const char *description,
+ CreateFrontEndCallback callback)
+ : SyntheticChildren(flags), m_create_callback(std::move(callback)),
+ m_description(description ? description : "") {}
+
+CXXSyntheticChildren::~CXXSyntheticChildren() = default;
+
+bool SyntheticChildren::IsScripted() { return false; }
+
+std::string SyntheticChildren::GetDescription() { return ""; }
+
+SyntheticChildrenFrontEnd::AutoPointer
+SyntheticChildren::GetFrontEnd(ValueObject &backend) {
+ return nullptr;
+}
+
+std::string CXXSyntheticChildren::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("%s%s%s %s", Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ m_description.c_str());
+
+ return std::string(sstr.GetString());
+}
+
+uint32_t
+SyntheticChildrenFrontEnd::CalculateNumChildrenIgnoringErrors(uint32_t max) {
+ auto value_or_err = CalculateNumChildren(max);
+ if (value_or_err)
+ return *value_or_err;
+ LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(),
+ "{0}");
+ return 0;
+}
+
+lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression(
+ llvm::StringRef name, llvm::StringRef expression,
+ const ExecutionContext &exe_ctx) {
+ ValueObjectSP valobj_sp(
+ ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx));
+ if (valobj_sp)
+ valobj_sp->SetSyntheticChildrenGenerated(true);
+ return valobj_sp;
+}
+
+lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromAddress(
+ llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
+ CompilerType type) {
+ ValueObjectSP valobj_sp(
+ ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, type));
+ if (valobj_sp)
+ valobj_sp->SetSyntheticChildrenGenerated(true);
+ return valobj_sp;
+}
+
+lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromData(
+ llvm::StringRef name, const DataExtractor &data,
+ const ExecutionContext &exe_ctx, CompilerType type) {
+ ValueObjectSP valobj_sp(
+ ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type));
+ if (valobj_sp)
+ valobj_sp->SetSyntheticChildrenGenerated(true);
+ return valobj_sp;
+}
+
+ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass,
+ ValueObject &backend)
+ : SyntheticChildrenFrontEnd(backend), m_python_class(pclass),
+ m_wrapper_sp(), m_interpreter(nullptr) {
+ if (backend.GetID() == LLDB_INVALID_UID)
+ return;
+
+ TargetSP target_sp = backend.GetTargetSP();
+
+ if (!target_sp)
+ return;
+
+ m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
+
+ if (m_interpreter != nullptr)
+ m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider(
+ m_python_class.c_str(), backend.GetSP());
+}
+
+ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default;
+
+lldb::ValueObjectSP
+ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(uint32_t idx) {
+ if (!m_wrapper_sp || !m_interpreter)
+ return lldb::ValueObjectSP();
+
+ return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx);
+}
+
+bool ScriptedSyntheticChildren::FrontEnd::IsValid() {
+ return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter);
+}
+
+llvm::Expected<uint32_t>
+ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() {
+ if (!m_wrapper_sp || m_interpreter == nullptr)
+ return 0;
+ return m_interpreter->CalculateNumChildren(m_wrapper_sp, UINT32_MAX);
+}
+
+llvm::Expected<uint32_t>
+ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) {
+ if (!m_wrapper_sp || m_interpreter == nullptr)
+ return 0;
+ return m_interpreter->CalculateNumChildren(m_wrapper_sp, max);
+}
+
+lldb::ChildCacheState ScriptedSyntheticChildren::FrontEnd::Update() {
+ if (!m_wrapper_sp || m_interpreter == nullptr)
+ return lldb::ChildCacheState::eRefetch;
+
+ return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp)
+ ? lldb::ChildCacheState::eReuse
+ : lldb::ChildCacheState::eRefetch;
+}
+
+bool ScriptedSyntheticChildren::FrontEnd::MightHaveChildren() {
+ if (!m_wrapper_sp || m_interpreter == nullptr)
+ return false;
+
+ return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp);
+}
+
+size_t ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName(
+ ConstString name) {
+ if (!m_wrapper_sp || m_interpreter == nullptr)
+ return UINT32_MAX;
+ return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp,
+ name.GetCString());
+}
+
+lldb::ValueObjectSP ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue() {
+ if (!m_wrapper_sp || m_interpreter == nullptr)
+ return nullptr;
+
+ return m_interpreter->GetSyntheticValue(m_wrapper_sp);
+}
+
+ConstString ScriptedSyntheticChildren::FrontEnd::GetSyntheticTypeName() {
+ if (!m_wrapper_sp || m_interpreter == nullptr)
+ return ConstString();
+
+ return m_interpreter->GetSyntheticTypeName(m_wrapper_sp);
+}
+
+std::string ScriptedSyntheticChildren::GetDescription() {
+ StreamString sstr;
+ sstr.Printf("%s%s%s Python class %s", Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ m_python_class.c_str());
+
+ return std::string(sstr.GetString());
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp
new file mode 100644
index 000000000000..ce24a7866e53
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -0,0 +1,886 @@
+//===-- ValueObjectPrinter.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 "lldb/DataFormatters/ValueObjectPrinter.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+
+using namespace lldb;
+using namespace lldb_private;
+
+ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s)
+ : m_orig_valobj(valobj) {
+ DumpValueObjectOptions options(valobj);
+ Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);
+}
+
+ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s,
+ const DumpValueObjectOptions &options)
+ : m_orig_valobj(valobj) {
+ Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);
+}
+
+ValueObjectPrinter::ValueObjectPrinter(
+ ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options,
+ const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,
+ InstancePointersSetSP printed_instance_pointers)
+ : m_orig_valobj(valobj) {
+ Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers);
+}
+
+void ValueObjectPrinter::Init(
+ ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options,
+ const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,
+ InstancePointersSetSP printed_instance_pointers) {
+ m_cached_valobj = nullptr;
+ m_stream = s;
+ m_options = options;
+ m_ptr_depth = ptr_depth;
+ m_curr_depth = curr_depth;
+ assert(m_stream && "cannot print to a NULL Stream");
+ m_should_print = eLazyBoolCalculate;
+ m_is_nil = eLazyBoolCalculate;
+ m_is_uninit = eLazyBoolCalculate;
+ m_is_ptr = eLazyBoolCalculate;
+ m_is_ref = eLazyBoolCalculate;
+ m_is_aggregate = eLazyBoolCalculate;
+ m_is_instance_ptr = eLazyBoolCalculate;
+ m_summary_formatter = {nullptr, false};
+ m_value.assign("");
+ m_summary.assign("");
+ m_error.assign("");
+ m_val_summary_ok = false;
+ m_printed_instance_pointers =
+ printed_instance_pointers
+ ? printed_instance_pointers
+ : InstancePointersSetSP(new InstancePointersSet());
+ SetupMostSpecializedValue();
+}
+
+llvm::Error ValueObjectPrinter::PrintValueObject() {
+ // If the incoming ValueObject is in an error state, the best we're going to
+ // get out of it is its type. But if we don't even have that, just print
+ // the error and exit early.
+ if (m_orig_valobj.GetError().Fail() &&
+ !m_orig_valobj.GetCompilerType().IsValid())
+ return m_orig_valobj.GetError().ToError();
+
+ if (ShouldPrintValueObject()) {
+ PrintLocationIfNeeded();
+ m_stream->Indent();
+
+ PrintDecl();
+ }
+
+ bool value_printed = false;
+ bool summary_printed = false;
+
+ m_val_summary_ok =
+ PrintValueAndSummaryIfNeeded(value_printed, summary_printed);
+
+ if (m_val_summary_ok)
+ return PrintChildrenIfNeeded(value_printed, summary_printed);
+ m_stream->EOL();
+
+ return llvm::Error::success();
+}
+
+ValueObject &ValueObjectPrinter::GetMostSpecializedValue() {
+ assert(m_cached_valobj && "ValueObjectPrinter must have a valid ValueObject");
+ return *m_cached_valobj;
+}
+
+void ValueObjectPrinter::SetupMostSpecializedValue() {
+ bool update_success = m_orig_valobj.UpdateValueIfNeeded(true);
+ // If we can't find anything better, we'll fall back on the original
+ // ValueObject.
+ m_cached_valobj = &m_orig_valobj;
+ if (update_success) {
+ if (m_orig_valobj.IsDynamic()) {
+ if (m_options.m_use_dynamic == eNoDynamicValues) {
+ ValueObject *static_value = m_orig_valobj.GetStaticValue().get();
+ if (static_value)
+ m_cached_valobj = static_value;
+ }
+ } else {
+ if (m_options.m_use_dynamic != eNoDynamicValues) {
+ ValueObject *dynamic_value =
+ m_orig_valobj.GetDynamicValue(m_options.m_use_dynamic).get();
+ if (dynamic_value)
+ m_cached_valobj = dynamic_value;
+ }
+ }
+
+ if (m_cached_valobj->IsSynthetic()) {
+ if (!m_options.m_use_synthetic) {
+ ValueObject *non_synthetic =
+ m_cached_valobj->GetNonSyntheticValue().get();
+ if (non_synthetic)
+ m_cached_valobj = non_synthetic;
+ }
+ } else {
+ if (m_options.m_use_synthetic) {
+ ValueObject *synthetic = m_cached_valobj->GetSyntheticValue().get();
+ if (synthetic)
+ m_cached_valobj = synthetic;
+ }
+ }
+ }
+ m_compiler_type = m_cached_valobj->GetCompilerType();
+ m_type_flags = m_compiler_type.GetTypeInfo();
+ assert(m_cached_valobj &&
+ "SetupMostSpecialized value must compute a valid ValueObject");
+}
+
+llvm::Expected<std::string> ValueObjectPrinter::GetDescriptionForDisplay() {
+ ValueObject &valobj = GetMostSpecializedValue();
+ llvm::Expected<std::string> maybe_str = valobj.GetObjectDescription();
+ if (maybe_str)
+ return maybe_str;
+
+ const char *str = nullptr;
+ if (!str)
+ str = valobj.GetSummaryAsCString();
+ if (!str)
+ str = valobj.GetValueAsCString();
+
+ if (!str)
+ return maybe_str;
+ llvm::consumeError(maybe_str.takeError());
+ return str;
+}
+
+const char *ValueObjectPrinter::GetRootNameForDisplay() {
+ const char *root_valobj_name =
+ m_options.m_root_valobj_name.empty()
+ ? GetMostSpecializedValue().GetName().AsCString()
+ : m_options.m_root_valobj_name.c_str();
+ return root_valobj_name ? root_valobj_name : "";
+}
+
+bool ValueObjectPrinter::ShouldPrintValueObject() {
+ if (m_should_print == eLazyBoolCalculate)
+ m_should_print =
+ (!m_options.m_flat_output || m_type_flags.Test(eTypeHasValue))
+ ? eLazyBoolYes
+ : eLazyBoolNo;
+ return m_should_print == eLazyBoolYes;
+}
+
+bool ValueObjectPrinter::IsNil() {
+ if (m_is_nil == eLazyBoolCalculate)
+ m_is_nil =
+ GetMostSpecializedValue().IsNilReference() ? eLazyBoolYes : eLazyBoolNo;
+ return m_is_nil == eLazyBoolYes;
+}
+
+bool ValueObjectPrinter::IsUninitialized() {
+ if (m_is_uninit == eLazyBoolCalculate)
+ m_is_uninit = GetMostSpecializedValue().IsUninitializedReference()
+ ? eLazyBoolYes
+ : eLazyBoolNo;
+ return m_is_uninit == eLazyBoolYes;
+}
+
+bool ValueObjectPrinter::IsPtr() {
+ if (m_is_ptr == eLazyBoolCalculate)
+ m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo;
+ return m_is_ptr == eLazyBoolYes;
+}
+
+bool ValueObjectPrinter::IsRef() {
+ if (m_is_ref == eLazyBoolCalculate)
+ m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo;
+ return m_is_ref == eLazyBoolYes;
+}
+
+bool ValueObjectPrinter::IsAggregate() {
+ if (m_is_aggregate == eLazyBoolCalculate)
+ m_is_aggregate =
+ m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo;
+ return m_is_aggregate == eLazyBoolYes;
+}
+
+bool ValueObjectPrinter::IsInstancePointer() {
+ // you need to do this check on the value's clang type
+ ValueObject &valobj = GetMostSpecializedValue();
+ if (m_is_instance_ptr == eLazyBoolCalculate)
+ m_is_instance_ptr = (valobj.GetValue().GetCompilerType().GetTypeInfo() &
+ eTypeInstanceIsPointer) != 0
+ ? eLazyBoolYes
+ : eLazyBoolNo;
+ if ((eLazyBoolYes == m_is_instance_ptr) && valobj.IsBaseClass())
+ m_is_instance_ptr = eLazyBoolNo;
+ return m_is_instance_ptr == eLazyBoolYes;
+}
+
+bool ValueObjectPrinter::PrintLocationIfNeeded() {
+ if (m_options.m_show_location) {
+ m_stream->Printf("%s: ", GetMostSpecializedValue().GetLocationAsCString());
+ return true;
+ }
+ return false;
+}
+
+void ValueObjectPrinter::PrintDecl() {
+ bool show_type = true;
+ // if we are at the root-level and been asked to hide the root's type, then
+ // hide it
+ if (m_curr_depth == 0 && m_options.m_hide_root_type)
+ show_type = false;
+ else
+ // otherwise decide according to the usual rules (asked to show types -
+ // always at the root level)
+ show_type = m_options.m_show_types ||
+ (m_curr_depth == 0 && !m_options.m_flat_output);
+
+ StreamString typeName;
+ // Figure out which ValueObject we're acting on
+ ValueObject &valobj = GetMostSpecializedValue();
+
+ // always show the type at the root level if it is invalid
+ if (show_type) {
+ // Some ValueObjects don't have types (like registers sets). Only print the
+ // type if there is one to print
+ ConstString type_name;
+ if (m_compiler_type.IsValid()) {
+ type_name = m_options.m_use_type_display_name
+ ? valobj.GetDisplayTypeName()
+ : valobj.GetQualifiedTypeName();
+ } else {
+ // only show an invalid type name if the user explicitly triggered
+ // show_type
+ if (m_options.m_show_types)
+ type_name = ConstString("<invalid type>");
+ }
+
+ if (type_name) {
+ std::string type_name_str(type_name.GetCString());
+ if (m_options.m_hide_pointer_value) {
+ for (auto iter = type_name_str.find(" *"); iter != std::string::npos;
+ iter = type_name_str.find(" *")) {
+ type_name_str.erase(iter, 2);
+ }
+ }
+ typeName << type_name_str.c_str();
+ }
+ }
+
+ StreamString varName;
+
+ if (ShouldShowName()) {
+ if (m_options.m_flat_output)
+ valobj.GetExpressionPath(varName);
+ else
+ varName << GetRootNameForDisplay();
+ }
+
+ bool decl_printed = false;
+ if (!m_options.m_decl_printing_helper) {
+ // if the user didn't give us a custom helper, pick one based upon the
+ // language, either the one that this printer is bound to, or the preferred
+ // one for the ValueObject
+ lldb::LanguageType lang_type =
+ (m_options.m_varformat_language == lldb::eLanguageTypeUnknown)
+ ? valobj.GetPreferredDisplayLanguage()
+ : m_options.m_varformat_language;
+ if (Language *lang_plugin = Language::FindPlugin(lang_type)) {
+ m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper();
+ }
+ }
+
+ if (m_options.m_decl_printing_helper) {
+ ConstString type_name_cstr(typeName.GetString());
+ ConstString var_name_cstr(varName.GetString());
+
+ DumpValueObjectOptions decl_print_options = m_options;
+ // Pass printing helpers an option object that indicates whether the name
+ // should be shown or hidden.
+ decl_print_options.SetHideName(!ShouldShowName());
+
+ StreamString dest_stream;
+ if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr,
+ decl_print_options, dest_stream)) {
+ decl_printed = true;
+ m_stream->PutCString(dest_stream.GetString());
+ }
+ }
+
+ // if the helper failed, or there is none, do a default thing
+ if (!decl_printed) {
+ if (!typeName.Empty())
+ m_stream->Printf("(%s) ", typeName.GetData());
+ if (!varName.Empty())
+ m_stream->Printf("%s =", varName.GetData());
+ else if (ShouldShowName())
+ m_stream->Printf(" =");
+ }
+}
+
+bool ValueObjectPrinter::CheckScopeIfNeeded() {
+ if (m_options.m_scope_already_checked)
+ return true;
+ return GetMostSpecializedValue().IsInScope();
+}
+
+TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) {
+ if (!m_summary_formatter.second) {
+ TypeSummaryImpl *entry =
+ m_options.m_summary_sp
+ ? m_options.m_summary_sp.get()
+ : GetMostSpecializedValue().GetSummaryFormat().get();
+
+ if (m_options.m_omit_summary_depth > 0)
+ entry = nullptr;
+ m_summary_formatter.first = entry;
+ m_summary_formatter.second = true;
+ }
+ if (m_options.m_omit_summary_depth > 0 && null_if_omitted)
+ return nullptr;
+ return m_summary_formatter.first;
+}
+
+static bool IsPointerValue(const CompilerType &type) {
+ Flags type_flags(type.GetTypeInfo());
+ if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer))
+ return type_flags.AllClear(eTypeIsBuiltIn);
+ return false;
+}
+
+void ValueObjectPrinter::GetValueSummaryError(std::string &value,
+ std::string &summary,
+ std::string &error) {
+ lldb::Format format = m_options.m_format;
+ ValueObject &valobj = GetMostSpecializedValue();
+ // if I am printing synthetized elements, apply the format to those elements
+ // only
+ if (m_options.m_pointer_as_array)
+ valobj.GetValueAsCString(lldb::eFormatDefault, value);
+ else if (format != eFormatDefault && format != valobj.GetFormat())
+ valobj.GetValueAsCString(format, value);
+ else {
+ const char *val_cstr = valobj.GetValueAsCString();
+ if (val_cstr)
+ value.assign(val_cstr);
+ }
+ const char *err_cstr = valobj.GetError().AsCString();
+ if (err_cstr)
+ error.assign(err_cstr);
+
+ if (!ShouldPrintValueObject())
+ return;
+
+ if (IsNil()) {
+ lldb::LanguageType lang_type =
+ (m_options.m_varformat_language == lldb::eLanguageTypeUnknown)
+ ? valobj.GetPreferredDisplayLanguage()
+ : m_options.m_varformat_language;
+ if (Language *lang_plugin = Language::FindPlugin(lang_type)) {
+ summary.assign(lang_plugin->GetNilReferenceSummaryString().str());
+ } else {
+ // We treat C as the fallback language rather than as a separate Language
+ // plugin.
+ summary.assign("NULL");
+ }
+ } else if (IsUninitialized()) {
+ summary.assign("<uninitialized>");
+ } else if (m_options.m_omit_summary_depth == 0) {
+ TypeSummaryImpl *entry = GetSummaryFormatter();
+ if (entry) {
+ valobj.GetSummaryAsCString(entry, summary,
+ m_options.m_varformat_language);
+ } else {
+ const char *sum_cstr =
+ valobj.GetSummaryAsCString(m_options.m_varformat_language);
+ if (sum_cstr)
+ summary.assign(sum_cstr);
+ }
+ }
+}
+
+bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,
+ bool &summary_printed) {
+ bool error_printed = false;
+ if (ShouldPrintValueObject()) {
+ if (!CheckScopeIfNeeded())
+ m_error.assign("out of scope");
+ if (m_error.empty()) {
+ GetValueSummaryError(m_value, m_summary, m_error);
+ }
+ if (m_error.size()) {
+ // we need to support scenarios in which it is actually fine for a value
+ // to have no type but - on the other hand - if we get an error *AND*
+ // have no type, we try to get out gracefully, since most often that
+ // combination means "could not resolve a type" and the default failure
+ // mode is quite ugly
+ if (!m_compiler_type.IsValid()) {
+ m_stream->Printf(" <could not resolve type>");
+ return false;
+ }
+
+ error_printed = true;
+ m_stream->Printf(" <%s>\n", m_error.c_str());
+ } else {
+ // Make sure we have a value and make sure the summary didn't specify
+ // that the value should not be printed - and do not print the value if
+ // this thing is nil (but show the value if the user passes a format
+ // explicitly)
+ TypeSummaryImpl *entry = GetSummaryFormatter();
+ ValueObject &valobj = GetMostSpecializedValue();
+ const bool has_nil_or_uninitialized_summary =
+ (IsNil() || IsUninitialized()) && !m_summary.empty();
+ if (!has_nil_or_uninitialized_summary && !m_value.empty() &&
+ (entry == nullptr ||
+ (entry->DoesPrintValue(&valobj) ||
+ m_options.m_format != eFormatDefault) ||
+ m_summary.empty()) &&
+ !m_options.m_hide_value) {
+ if (m_options.m_hide_pointer_value &&
+ IsPointerValue(valobj.GetCompilerType())) {
+ } else {
+ if (ShouldShowName())
+ m_stream->PutChar(' ');
+ m_stream->PutCString(m_value);
+ value_printed = true;
+ }
+ }
+
+ if (m_summary.size()) {
+ if (ShouldShowName() || value_printed)
+ m_stream->PutChar(' ');
+ m_stream->PutCString(m_summary);
+ summary_printed = true;
+ }
+ }
+ }
+ return !error_printed;
+}
+
+llvm::Error
+ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed,
+ bool summary_printed) {
+ if (ShouldPrintValueObject()) {
+ // let's avoid the overly verbose no description error for a nil thing
+ if (m_options.m_use_objc && !IsNil() && !IsUninitialized() &&
+ (!m_options.m_pointer_as_array)) {
+ if (!m_options.m_hide_value || ShouldShowName())
+ *m_stream << ' ';
+ llvm::Expected<std::string> object_desc =
+ (value_printed || summary_printed)
+ ? GetMostSpecializedValue().GetObjectDescription()
+ : GetDescriptionForDisplay();
+ if (!object_desc) {
+ // If no value or summary was printed, surface the error.
+ if (!value_printed && !summary_printed)
+ return object_desc.takeError();
+ // Otherwise gently nudge the user that they should have used
+ // `p` instead of `po`. Unfortunately we cannot be more direct
+ // about this, because we don't actually know what the user did.
+ *m_stream << "warning: no object description available\n";
+ llvm::consumeError(object_desc.takeError());
+ } else {
+ *m_stream << *object_desc;
+ // If the description already ends with a \n don't add another one.
+ if (object_desc->empty() || object_desc->back() != '\n')
+ *m_stream << '\n';
+ }
+ return llvm::Error::success();
+ }
+ }
+ return llvm::Error::success();
+}
+
+bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {
+ switch (m_mode) {
+ case Mode::Always:
+ case Mode::Default:
+ return m_count > 0;
+ case Mode::Never:
+ return false;
+ }
+ return false;
+}
+
+bool ValueObjectPrinter::ShouldPrintChildren(
+ DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
+ const bool is_ref = IsRef();
+ const bool is_ptr = IsPtr();
+ const bool is_uninit = IsUninitialized();
+
+ if (is_uninit)
+ return false;
+
+ // If we have reached the maximum depth we shouldn't print any more children.
+ if (HasReachedMaximumDepth())
+ return false;
+
+ // if the user has specified an element count, always print children as it is
+ // explicit user demand being honored
+ if (m_options.m_pointer_as_array)
+ return true;
+
+ if (m_options.m_use_objc)
+ return false;
+
+ bool print_children = true;
+ ValueObject &valobj = GetMostSpecializedValue();
+ if (TypeSummaryImpl *type_summary = GetSummaryFormatter())
+ print_children = type_summary->DoesPrintChildren(&valobj);
+
+ // We will show children for all concrete types. We won't show pointer
+ // contents unless a pointer depth has been specified. We won't reference
+ // contents unless the reference is the root object (depth of zero).
+
+ // Use a new temporary pointer depth in case we override the current
+ // pointer depth below...
+
+ if (is_ptr || is_ref) {
+ // We have a pointer or reference whose value is an address. Make sure
+ // that address is not NULL
+ AddressType ptr_address_type;
+ if (valobj.GetPointerValue(&ptr_address_type) == 0)
+ return false;
+
+ const bool is_root_level = m_curr_depth == 0;
+
+ if (is_ref && is_root_level && print_children) {
+ // If this is the root object (depth is zero) that we are showing and
+ // it is a reference, and no pointer depth has been supplied print out
+ // what it references. Don't do this at deeper depths otherwise we can
+ // end up with infinite recursion...
+ return true;
+ }
+
+ return curr_ptr_depth.CanAllowExpansion();
+ }
+
+ return print_children || m_summary.empty();
+}
+
+bool ValueObjectPrinter::ShouldExpandEmptyAggregates() {
+ TypeSummaryImpl *entry = GetSummaryFormatter();
+
+ if (!entry)
+ return true;
+
+ return entry->DoesPrintEmptyAggregates();
+}
+
+ValueObject &ValueObjectPrinter::GetValueObjectForChildrenGeneration() {
+ return GetMostSpecializedValue();
+}
+
+void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed,
+ bool summary_printed) {
+ if (m_options.m_flat_output) {
+ if (ShouldPrintValueObject())
+ m_stream->EOL();
+ } else {
+ if (ShouldPrintValueObject()) {
+ if (IsRef()) {
+ m_stream->PutCString(": ");
+ } else if (value_printed || summary_printed || ShouldShowName()) {
+ m_stream->PutChar(' ');
+ }
+ m_stream->PutCString("{\n");
+ }
+ m_stream->IndentMore();
+ }
+}
+
+void ValueObjectPrinter::PrintChild(
+ ValueObjectSP child_sp,
+ const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
+ const uint32_t consumed_summary_depth = m_options.m_pointer_as_array ? 0 : 1;
+ const bool does_consume_ptr_depth =
+ ((IsPtr() && !m_options.m_pointer_as_array) || IsRef());
+
+ DumpValueObjectOptions child_options(m_options);
+ child_options.SetFormat(m_options.m_format)
+ .SetSummary()
+ .SetRootValueObjectName();
+ child_options.SetScopeChecked(true)
+ .SetHideName(m_options.m_hide_name)
+ .SetHideValue(m_options.m_hide_value)
+ .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1
+ ? child_options.m_omit_summary_depth -
+ consumed_summary_depth
+ : 0)
+ .SetElementCount(0);
+
+ if (child_sp.get()) {
+ auto ptr_depth = curr_ptr_depth;
+ if (does_consume_ptr_depth)
+ ptr_depth = curr_ptr_depth.Decremented();
+
+ ValueObjectPrinter child_printer(*(child_sp.get()), m_stream, child_options,
+ ptr_depth, m_curr_depth + 1,
+ m_printed_instance_pointers);
+ llvm::Error error = child_printer.PrintValueObject();
+ if (error) {
+ if (m_stream)
+ *m_stream << "error: " << toString(std::move(error));
+ else
+ llvm::consumeError(std::move(error));
+ }
+ }
+}
+
+llvm::Expected<uint32_t>
+ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) {
+ ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();
+
+ if (m_options.m_pointer_as_array)
+ return m_options.m_pointer_as_array.m_element_count;
+
+ const uint32_t max_num_children =
+ m_options.m_ignore_cap ? UINT32_MAX
+ : GetMostSpecializedValue()
+ .GetTargetSP()
+ ->GetMaximumNumberOfChildrenToDisplay();
+ // Ask for one more child than the maximum to see if we should print "...".
+ auto num_children_or_err = synth_valobj.GetNumChildren(
+ llvm::SaturatingAdd(max_num_children, uint32_t(1)));
+ if (!num_children_or_err)
+ return num_children_or_err;
+ if (*num_children_or_err > max_num_children) {
+ print_dotdotdot = true;
+ return max_num_children;
+ }
+ return num_children_or_err;
+}
+
+void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) {
+ if (!m_options.m_flat_output) {
+ if (print_dotdotdot) {
+ GetMostSpecializedValue()
+ .GetTargetSP()
+ ->GetDebugger()
+ .GetCommandInterpreter()
+ .ChildrenTruncated();
+ m_stream->Indent("...\n");
+ }
+ m_stream->IndentLess();
+ m_stream->Indent("}\n");
+ }
+}
+
+bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed,
+ bool summary_printed) {
+ ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();
+
+ if (!IsAggregate())
+ return false;
+
+ if (!m_options.m_reveal_empty_aggregates) {
+ if (value_printed || summary_printed)
+ return false;
+ }
+
+ if (synth_valobj.MightHaveChildren())
+ return true;
+
+ if (m_val_summary_ok)
+ return false;
+
+ return true;
+}
+
+static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride,
+ size_t logical) {
+ return base + logical * stride;
+}
+
+ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject &synth_valobj,
+ size_t idx) {
+ if (m_options.m_pointer_as_array) {
+ // if generating pointer-as-array children, use GetSyntheticArrayMember
+ return synth_valobj.GetSyntheticArrayMember(
+ PhysicalIndexForLogicalIndex(
+ m_options.m_pointer_as_array.m_base_element,
+ m_options.m_pointer_as_array.m_stride, idx),
+ true);
+ } else {
+ // otherwise, do the usual thing
+ return synth_valobj.GetChildAtIndex(idx);
+ }
+}
+
+void ValueObjectPrinter::PrintChildren(
+ bool value_printed, bool summary_printed,
+ const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {
+ ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();
+
+ bool print_dotdotdot = false;
+ auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);
+ if (!num_children_or_err) {
+ *m_stream << " <" << llvm::toString(num_children_or_err.takeError()) << '>';
+ return;
+ }
+ uint32_t num_children = *num_children_or_err;
+ if (num_children) {
+ bool any_children_printed = false;
+
+ for (size_t idx = 0; idx < num_children; ++idx) {
+ if (ValueObjectSP child_sp = GenerateChild(synth_valobj, idx)) {
+ if (m_options.m_child_printing_decider &&
+ !m_options.m_child_printing_decider(child_sp->GetName()))
+ continue;
+ if (!any_children_printed) {
+ PrintChildrenPreamble(value_printed, summary_printed);
+ any_children_printed = true;
+ }
+ PrintChild(child_sp, curr_ptr_depth);
+ }
+ }
+
+ if (any_children_printed)
+ PrintChildrenPostamble(print_dotdotdot);
+ else {
+ if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {
+ if (ShouldPrintValueObject())
+ m_stream->PutCString(" {}\n");
+ else
+ m_stream->EOL();
+ } else
+ m_stream->EOL();
+ }
+ } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {
+ // Aggregate, no children...
+ if (ShouldPrintValueObject()) {
+ // if it has a synthetic value, then don't print {}, the synthetic
+ // children are probably only being used to vend a value
+ if (GetMostSpecializedValue().DoesProvideSyntheticValue() ||
+ !ShouldExpandEmptyAggregates())
+ m_stream->PutCString("\n");
+ else
+ m_stream->PutCString(" {}\n");
+ }
+ } else {
+ if (ShouldPrintValueObject())
+ m_stream->EOL();
+ }
+}
+
+bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
+ ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();
+
+ bool print_dotdotdot = false;
+ auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);
+ if (!num_children_or_err) {
+ *m_stream << '<' << llvm::toString(num_children_or_err.takeError()) << '>';
+ return true;
+ }
+ uint32_t num_children = *num_children_or_err;
+
+ if (num_children) {
+ m_stream->PutChar('(');
+
+ bool did_print_children = false;
+ for (uint32_t idx = 0; idx < num_children; ++idx) {
+ lldb::ValueObjectSP child_sp(synth_valobj.GetChildAtIndex(idx));
+ if (child_sp)
+ child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
+ m_options.m_use_dynamic, m_options.m_use_synthetic);
+ if (child_sp) {
+ if (m_options.m_child_printing_decider &&
+ !m_options.m_child_printing_decider(child_sp->GetName()))
+ continue;
+ if (idx && did_print_children)
+ m_stream->PutCString(", ");
+ did_print_children = true;
+ if (!hide_names) {
+ const char *name = child_sp.get()->GetName().AsCString();
+ if (name && *name) {
+ m_stream->PutCString(name);
+ m_stream->PutCString(" = ");
+ }
+ }
+ child_sp->DumpPrintableRepresentation(
+ *m_stream, ValueObject::eValueObjectRepresentationStyleSummary,
+ m_options.m_format,
+ ValueObject::PrintableRepresentationSpecialCases::eDisable);
+ }
+ }
+
+ if (print_dotdotdot)
+ m_stream->PutCString(", ...)");
+ else
+ m_stream->PutChar(')');
+ }
+ return true;
+}
+
+llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,
+ bool summary_printed) {
+ auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed);
+ if (error)
+ return error;
+
+ ValueObject &valobj = GetMostSpecializedValue();
+
+ DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth;
+ const bool print_children = ShouldPrintChildren(curr_ptr_depth);
+ const bool print_oneline =
+ (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types ||
+ !m_options.m_allow_oneliner_mode || m_options.m_flat_output ||
+ (m_options.m_pointer_as_array) || m_options.m_show_location)
+ ? false
+ : DataVisualization::ShouldPrintAsOneLiner(valobj);
+ if (print_children && IsInstancePointer()) {
+ uint64_t instance_ptr_value = valobj.GetValueAsUnsigned(0);
+ if (m_printed_instance_pointers->count(instance_ptr_value)) {
+ // We already printed this instance-is-pointer thing, so don't expand it.
+ m_stream->PutCString(" {...}\n");
+ return llvm::Error::success();
+ } else {
+ // Remember this guy for future reference.
+ m_printed_instance_pointers->emplace(instance_ptr_value);
+ }
+ }
+
+ if (print_children) {
+ if (print_oneline) {
+ m_stream->PutChar(' ');
+ PrintChildrenOneLiner(false);
+ m_stream->EOL();
+ } else
+ PrintChildren(value_printed, summary_printed, curr_ptr_depth);
+ } else if (HasReachedMaximumDepth() && IsAggregate() &&
+ ShouldPrintValueObject()) {
+ m_stream->PutCString("{...}\n");
+ // The maximum child depth has been reached. If `m_max_depth` is the default
+ // (i.e. the user has _not_ customized it), then lldb presents a warning to
+ // the user. The warning tells the user that the limit has been reached, but
+ // more importantly tells them how to expand the limit if desired.
+ if (m_options.m_max_depth_is_default)
+ valobj.GetTargetSP()
+ ->GetDebugger()
+ .GetCommandInterpreter()
+ .SetReachedMaximumDepth();
+ } else
+ m_stream->EOL();
+ return llvm::Error::success();
+}
+
+bool ValueObjectPrinter::HasReachedMaximumDepth() {
+ return m_curr_depth >= m_options.m_max_depth;
+}
+
+bool ValueObjectPrinter::ShouldShowName() const {
+ if (m_curr_depth == 0)
+ return !m_options.m_hide_root_name && !m_options.m_hide_name;
+ return !m_options.m_hide_name;
+}
diff --git a/contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp b/contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp
new file mode 100644
index 000000000000..19de204c2435
--- /dev/null
+++ b/contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp
@@ -0,0 +1,335 @@
+//===-- VectorType.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 "lldb/DataFormatters/VectorType.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/Log.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+static CompilerType GetCompilerTypeForFormat(lldb::Format format,
+ CompilerType element_type,
+ TypeSystemSP type_system) {
+ lldbassert(type_system && "type_system needs to be not NULL");
+ if (!type_system)
+ return {};
+
+ switch (format) {
+ case lldb::eFormatAddressInfo:
+ case lldb::eFormatPointer:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(
+ eEncodingUint, 8 * type_system->GetPointerByteSize());
+
+ case lldb::eFormatBoolean:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeBool);
+
+ case lldb::eFormatBytes:
+ case lldb::eFormatBytesWithASCII:
+ case lldb::eFormatChar:
+ case lldb::eFormatCharArray:
+ case lldb::eFormatCharPrintable:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar);
+
+ case lldb::eFormatComplex /* lldb::eFormatComplexFloat */:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloatComplex);
+
+ case lldb::eFormatCString:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar)
+ .GetPointerType();
+
+ case lldb::eFormatFloat:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat);
+
+ case lldb::eFormatHex:
+ case lldb::eFormatHexUppercase:
+ case lldb::eFormatOctal:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeInt);
+
+ case lldb::eFormatHexFloat:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat);
+
+ case lldb::eFormatUnicode16:
+ case lldb::eFormatUnicode32:
+
+ case lldb::eFormatUnsigned:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt);
+
+ case lldb::eFormatVectorOfChar:
+ return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar);
+
+ case lldb::eFormatVectorOfFloat32:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754,
+ 32);
+
+ case lldb::eFormatVectorOfFloat64:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754,
+ 64);
+
+ case lldb::eFormatVectorOfSInt16:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 16);
+
+ case lldb::eFormatVectorOfSInt32:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32);
+
+ case lldb::eFormatVectorOfSInt64:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64);
+
+ case lldb::eFormatVectorOfSInt8:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 8);
+
+ case lldb::eFormatVectorOfUInt128:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 128);
+
+ case lldb::eFormatVectorOfUInt16:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16);
+
+ case lldb::eFormatVectorOfUInt32:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+
+ case lldb::eFormatVectorOfUInt64:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64);
+
+ case lldb::eFormatVectorOfUInt8:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8);
+
+ case lldb::eFormatDefault:
+ return element_type;
+
+ case lldb::eFormatBinary:
+ case lldb::eFormatComplexInteger:
+ case lldb::eFormatDecimal:
+ case lldb::eFormatEnum:
+ case lldb::eFormatInstruction:
+ case lldb::eFormatOSType:
+ case lldb::eFormatVoid:
+ default:
+ return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8);
+ }
+}
+
+static lldb::Format GetItemFormatForFormat(lldb::Format format,
+ CompilerType element_type) {
+ switch (format) {
+ case lldb::eFormatVectorOfChar:
+ return lldb::eFormatChar;
+
+ case lldb::eFormatVectorOfFloat32:
+ case lldb::eFormatVectorOfFloat64:
+ return lldb::eFormatFloat;
+
+ case lldb::eFormatVectorOfSInt16:
+ case lldb::eFormatVectorOfSInt32:
+ case lldb::eFormatVectorOfSInt64:
+ case lldb::eFormatVectorOfSInt8:
+ return lldb::eFormatDecimal;
+
+ case lldb::eFormatVectorOfUInt128:
+ case lldb::eFormatVectorOfUInt16:
+ case lldb::eFormatVectorOfUInt32:
+ case lldb::eFormatVectorOfUInt64:
+ case lldb::eFormatVectorOfUInt8:
+ return lldb::eFormatUnsigned;
+
+ case lldb::eFormatBinary:
+ case lldb::eFormatComplexInteger:
+ case lldb::eFormatDecimal:
+ case lldb::eFormatEnum:
+ case lldb::eFormatInstruction:
+ case lldb::eFormatOSType:
+ case lldb::eFormatVoid:
+ return eFormatHex;
+
+ case lldb::eFormatDefault: {
+ // special case the (default, char) combination to actually display as an
+ // integer value most often, you won't want to see the ASCII characters...
+ // (and if you do, eFormatChar is a keystroke away)
+ bool is_char = element_type.IsCharType();
+ bool is_signed = false;
+ element_type.IsIntegerType(is_signed);
+ return is_char ? (is_signed ? lldb::eFormatDecimal : eFormatHex) : format;
+ } break;
+
+ default:
+ return format;
+ }
+}
+
+/// Calculates the number of elements stored in a container (with
+/// element type 'container_elem_type') as if it had elements of type
+/// 'element_type'.
+///
+/// For example, a container of type
+/// `uint8_t __attribute__((vector_size(16)))` has 16 elements.
+/// But calling `CalculateNumChildren` with an 'element_type'
+/// of `float` (4-bytes) will return `4` because we are interpreting
+/// the byte-array as a `float32[]`.
+///
+/// \param[in] container_elem_type The type of the elements stored
+/// in the container we are calculating the children of.
+///
+/// \param[in] num_elements Number of 'container_elem_type's our
+/// container stores.
+///
+/// \param[in] element_type The type of elements we interpret
+/// container_type to contain for the purposes of calculating
+/// the number of children.
+///
+/// \returns The number of elements stored in a container of
+/// type 'element_type'. Returns a std::nullopt if the
+/// size of the container is not a multiple of 'element_type'
+/// or if an error occurs.
+static std::optional<size_t>
+CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements,
+ CompilerType element_type) {
+ std::optional<uint64_t> container_elem_size =
+ container_elem_type.GetByteSize(/* exe_scope */ nullptr);
+ if (!container_elem_size)
+ return {};
+
+ auto container_size = *container_elem_size * num_elements;
+
+ std::optional<uint64_t> element_size =
+ element_type.GetByteSize(/* exe_scope */ nullptr);
+ if (!element_size || !*element_size)
+ return {};
+
+ if (container_size % *element_size)
+ return {};
+
+ return container_size / *element_size;
+}
+
+namespace lldb_private {
+namespace formatters {
+
+class VectorTypeSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+ VectorTypeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp), m_child_type() {}
+
+ ~VectorTypeSyntheticFrontEnd() override = default;
+
+ llvm::Expected<uint32_t> CalculateNumChildren() override {
+ return m_num_children;
+ }
+
+ lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
+ auto num_children_or_err = CalculateNumChildren();
+ if (!num_children_or_err)
+ return ValueObjectConstResult::Create(
+ nullptr, Status(num_children_or_err.takeError()));
+ if (idx >= *num_children_or_err)
+ return {};
+ std::optional<uint64_t> size = m_child_type.GetByteSize(nullptr);
+ if (!size)
+ return {};
+ auto offset = idx * *size;
+ StreamString idx_name;
+ idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+ ValueObjectSP child_sp(m_backend.GetSyntheticChildAtOffset(
+ offset, m_child_type, true, ConstString(idx_name.GetString())));
+ if (!child_sp)
+ return child_sp;
+
+ child_sp->SetFormat(m_item_format);
+
+ return child_sp;
+ }
+
+ lldb::ChildCacheState Update() override {
+ m_parent_format = m_backend.GetFormat();
+ CompilerType parent_type(m_backend.GetCompilerType());
+ CompilerType element_type;
+ uint64_t num_elements;
+ parent_type.IsVectorType(&element_type, &num_elements);
+ m_child_type = ::GetCompilerTypeForFormat(
+ m_parent_format, element_type,
+ parent_type.GetTypeSystem().GetSharedPointer());
+ m_num_children =
+ ::CalculateNumChildren(element_type, num_elements, m_child_type)
+ .value_or(0);
+ m_item_format = GetItemFormatForFormat(m_parent_format, m_child_type);
+ return lldb::ChildCacheState::eRefetch;
+ }
+
+ bool MightHaveChildren() override { return true; }
+
+ size_t GetIndexOfChildWithName(ConstString name) override {
+ const char *item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
+ return UINT32_MAX;
+ return idx;
+ }
+
+private:
+ lldb::Format m_parent_format = eFormatInvalid;
+ lldb::Format m_item_format = eFormatInvalid;
+ CompilerType m_child_type;
+ size_t m_num_children = 0;
+};
+
+} // namespace formatters
+} // namespace lldb_private
+
+bool lldb_private::formatters::VectorTypeSummaryProvider(
+ ValueObject &valobj, Stream &s, const TypeSummaryOptions &) {
+ auto synthetic_children =
+ VectorTypeSyntheticFrontEndCreator(nullptr, valobj.GetSP());
+ if (!synthetic_children)
+ return false;
+
+ synthetic_children->Update();
+
+ s.PutChar('(');
+ bool first = true;
+
+ size_t idx = 0,
+ len = synthetic_children->CalculateNumChildrenIgnoringErrors();
+
+ for (; idx < len; idx++) {
+ auto child_sp = synthetic_children->GetChildAtIndex(idx);
+ if (!child_sp)
+ continue;
+ child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
+ lldb::eDynamicDontRunTarget, true);
+
+ const char *child_value = child_sp->GetValueAsCString();
+ if (child_value && *child_value) {
+ if (first) {
+ s.Printf("%s", child_value);
+ first = false;
+ } else {
+ s.Printf(", %s", child_value);
+ }
+ }
+ }
+
+ s.PutChar(')');
+
+ return true;
+}
+
+lldb_private::SyntheticChildrenFrontEnd *
+lldb_private::formatters::VectorTypeSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ if (!valobj_sp)
+ return nullptr;
+ return new VectorTypeSyntheticFrontEnd(valobj_sp);
+}