diff options
Diffstat (limited to 'lldb/source')
7 files changed, 281 insertions, 21 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index 5905d9b..e1dd5bf 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -36,6 +36,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN MsvcStl.cpp MsvcStlSmartPointer.cpp MsvcStlTuple.cpp + MsvcStlVariant.cpp MsvcStlVector.cpp MSVCUndecoratedNameParser.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index a8ebde0..481fe61 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1449,11 +1449,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdForwardListSynthProvider"))); - cpp_category_sp->AddTypeSynthetic( - "^std::variant<.+>$", eFormatterMatchRegex, - SyntheticChildrenSP(new ScriptedSyntheticChildren( - stl_synth_flags, - "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider"))); stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); @@ -1509,9 +1504,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { TypeSummaryImplSP(new ScriptSummaryFormat( stl_summary_flags, "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider"))); - AddCXXSummary(cpp_category_sp, LibStdcppVariantSummaryProvider, - "libstdc++ std::variant summary provider", "^std::variant<.+>$", - stl_summary_flags, true); AddCXXSynthetic( cpp_category_sp, @@ -1545,20 +1537,10 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "std::bitset synthetic child", "^std::(__debug::)?bitset<.+>(( )?&)?$", stl_deref_flags, true); - AddCXXSynthetic( - cpp_category_sp, - lldb_private::formatters::LibStdcppOptionalSyntheticFrontEndCreator, - "std::optional synthetic child", "^std::optional<.+>(( )?&)?$", - stl_deref_flags, true); - AddCXXSummary(cpp_category_sp, lldb_private::formatters::StdlibCoroutineHandleSummaryProvider, "libstdc++ std::coroutine_handle summary provider", libstdcpp_std_coroutine_handle_regex, stl_summary_flags, true); - AddCXXSummary(cpp_category_sp, - lldb_private::formatters::GenericOptionalSummaryProvider, - "libstd++ std::optional summary provider", - "^std::optional<.+>(( )?&)?$", stl_summary_flags, true); } static lldb_private::SyntheticChildrenFrontEnd * @@ -1648,6 +1630,36 @@ GenericForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *children, *valobj_sp); } +static SyntheticChildrenFrontEnd * +GenericOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *children, + lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + + if (IsMsvcStlOptional(*valobj_sp)) + return MsvcStlOptionalSyntheticFrontEndCreator(children, valobj_sp); + return LibStdcppOptionalSyntheticFrontEndCreator(children, valobj_sp); +} + +static SyntheticChildrenFrontEnd * +GenericVariantSyntheticFrontEndCreator(CXXSyntheticChildren *children, + lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + + if (IsMsvcStlVariant(*valobj_sp)) + return MsvcStlVariantSyntheticFrontEndCreator(children, valobj_sp); + return new ScriptedSyntheticChildren::FrontEnd( + "lldb.formatters.cpp.gnu_libstdcpp.VariantSynthProvider", *valobj_sp); +} + +static bool GenericVariantSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + if (IsMsvcStlVariant(valobj)) + return MsvcStlVariantSummaryProvider(valobj, stream, options); + return LibStdcppVariantSummaryProvider(valobj, stream, options); +} + /// Load formatters that are formatting types from more than one STL static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) @@ -1712,6 +1724,15 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic(cpp_category_sp, GenericForwardListSyntheticFrontEndCreator, "std::forward_list synthetic children", "^std::forward_list<.+>(( )?&)?$", stl_synth_flags, true); + AddCXXSynthetic(cpp_category_sp, GenericVariantSyntheticFrontEndCreator, + "std::variant synthetic children", "^std::variant<.*>$", + stl_synth_flags, true); + + SyntheticChildren::Flags stl_deref_flags = stl_synth_flags; + stl_deref_flags.SetFrontEndWantsDereference(); + AddCXXSynthetic(cpp_category_sp, GenericOptionalSyntheticFrontEndCreator, + "std::optional synthetic children", + "^std::optional<.+>(( )?&)?$", stl_deref_flags, true); AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider, "MSVC STL/libstdc++ std::shared_ptr summary provider", @@ -1739,6 +1760,12 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { TypeSummaryImplSP(new ScriptSummaryFormat( stl_summary_flags, "lldb.formatters.cpp.gnu_libstdcpp.ForwardListSummaryProvider"))); + AddCXXSummary(cpp_category_sp, GenericOptionalSummaryProvider, + "MSVC STL/libstd++ std::optional summary provider", + "^std::optional<.+>(( )?&)?$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, GenericVariantSummaryProvider, + "MSVC STL/libstdc++ std::variant summary provider", + "^std::variant<.*>$", stl_summary_flags, true); } static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp index c041f39..7fc6eb55 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp @@ -9,6 +9,7 @@ #include "Generic.h" #include "LibCxx.h" #include "LibStdcpp.h" +#include "MsvcStl.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Target/Target.h" @@ -32,6 +33,7 @@ public: enum class StdLib { LibCxx, LibStdcpp, + MsvcStl, }; GenericOptionalFrontend(ValueObject &valobj, StdLib stdlib); @@ -77,7 +79,8 @@ lldb::ChildCacheState GenericOptionalFrontend::Update() { else if (m_stdlib == StdLib::LibStdcpp) { if (ValueObjectSP payload = m_backend.GetChildMemberWithName("_M_payload")) engaged_sp = payload->GetChildMemberWithName("_M_engaged"); - } + } else if (m_stdlib == StdLib::MsvcStl) + engaged_sp = m_backend.GetChildMemberWithName("_Has_value"); if (!engaged_sp) return lldb::ChildCacheState::eRefetch; @@ -114,7 +117,12 @@ ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) { ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value"); if (candidate) val_sp = candidate; - } + } else if (m_stdlib == StdLib::MsvcStl) + // Same issue as with LibCxx + val_sp = m_backend.GetChildMemberWithName("_Has_value") + ->GetParent() + ->GetChildAtIndex(0) + ->GetChildMemberWithName("_Value"); if (!val_sp) return ValueObjectSP(); @@ -143,3 +151,17 @@ SyntheticChildrenFrontEnd *formatters::LibcxxOptionalSyntheticFrontEndCreator( GenericOptionalFrontend::StdLib::LibCxx); return nullptr; } + +bool formatters::IsMsvcStlOptional(ValueObject &valobj) { + if (auto valobj_sp = valobj.GetNonSyntheticValue()) + return valobj_sp->GetChildMemberWithName("_Has_value") != nullptr; + return false; +} + +SyntheticChildrenFrontEnd *formatters::MsvcStlOptionalSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + if (valobj_sp) + return new GenericOptionalFrontend( + *valobj_sp, GenericOptionalFrontend::StdLib::MsvcStl); + return nullptr; +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h index 8d2025e..429142f6 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h @@ -61,6 +61,9 @@ SyntheticChildrenFrontEnd * LibStdcppUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +bool LibStdcppVariantSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + } // namespace formatters } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h index 0f3db4b..9058d2e 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h @@ -65,6 +65,20 @@ SyntheticChildrenFrontEnd * MsvcStlListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp); +// MSVC STL std::optional<> +bool IsMsvcStlOptional(ValueObject &valobj); +SyntheticChildrenFrontEnd * +MsvcStlOptionalSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); + +// MSVC STL std::variant<> +bool IsMsvcStlVariant(ValueObject &valobj); +bool MsvcStlVariantSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); +SyntheticChildrenFrontEnd * +MsvcStlVariantSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); + } // namespace formatters } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp new file mode 100644 index 0000000..52a3d98 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp @@ -0,0 +1,188 @@ +//===-- MsvcStlVariant.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 "MsvcStl.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Symbol/CompilerType.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; + +namespace { + +// A variant when using DWARF looks as follows: +// (lldb) fr v -R v1 +// (std::variant<int, double, char>) v1 = { +// std::_SMF_control<std::_Variant_base<int, double, char>, int, double, char> +// = { +// std::_Variant_storage<int, double, char> = { +// = { +// _Head = 0 +// _Tail = { +// = { +// _Head = 2 +// _Tail = { +// = { +// _Head = '\0' +// _Tail = {} +// } +// } +// } +// } +// } +// } +// _Which = '\x01' +// } +// } + +ValueObjectSP GetStorageMember(ValueObject &valobj, llvm::StringRef name) { + // Find the union + ValueObjectSP union_sp = valobj.GetChildAtIndex(0); + if (!union_sp) + return nullptr; + return union_sp->GetChildMemberWithName(name); +} + +ValueObjectSP GetHead(ValueObject &valobj) { + return GetStorageMember(valobj, "_Head"); +} +ValueObjectSP GetTail(ValueObject &valobj) { + return GetStorageMember(valobj, "_Tail"); +} + +std::optional<int64_t> GetIndexValue(ValueObject &valobj) { + ValueObjectSP index_sp = valobj.GetChildMemberWithName("_Which"); + if (!index_sp) + return std::nullopt; + + return {index_sp->GetValueAsSigned(-1)}; +} + +ValueObjectSP GetNthStorage(ValueObject &outer, int64_t index) { + // We need to find the std::_Variant_storage base class. + + // -> std::_SMF_control (typedef to std::_Variant_base) + ValueObjectSP container_sp = outer.GetSP()->GetChildAtIndex(0); + if (!container_sp) + return nullptr; + // -> std::_Variant_storage + container_sp = container_sp->GetChildAtIndex(0); + if (!container_sp) + return nullptr; + + for (int64_t i = 0; i < index; i++) { + container_sp = GetTail(*container_sp); + if (!container_sp) + return nullptr; + } + return container_sp; +} + +} // namespace + +bool formatters::IsMsvcStlVariant(ValueObject &valobj) { + if (auto valobj_sp = valobj.GetNonSyntheticValue()) { + return valobj_sp->GetChildMemberWithName("_Which") != nullptr; + } + return false; +} + +bool formatters::MsvcStlVariantSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + auto index = GetIndexValue(*valobj_sp); + if (!index) + return false; + + if (*index < 0) { + stream.Printf(" No Value"); + return true; + } + + ValueObjectSP storage = GetNthStorage(*valobj_sp, *index); + if (!storage) + return false; + CompilerType storage_type = storage->GetCompilerType(); + if (!storage_type) + return false; + // Resolve the typedef + if (storage_type.IsTypedefType()) + storage_type = storage_type.GetTypedefedType(); + + CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true); + if (!active_type) + return false; + + stream << " Active Type = " << active_type.GetDisplayTypeName() << " "; + return true; +} + +namespace { +class VariantFrontEnd : public SyntheticChildrenFrontEnd { +public: + VariantFrontEnd(ValueObject &valobj) : SyntheticChildrenFrontEnd(valobj) { + Update(); + } + + llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override { + auto optional_idx = formatters::ExtractIndexFromString(name.GetCString()); + if (!optional_idx) { + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); + } + return *optional_idx; + } + + lldb::ChildCacheState Update() override; + llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; } + ValueObjectSP GetChildAtIndex(uint32_t idx) override; + +private: + size_t m_size = 0; +}; +} // namespace + +lldb::ChildCacheState VariantFrontEnd::Update() { + m_size = 0; + + auto index = GetIndexValue(m_backend); + if (index && *index >= 0) + m_size = 1; + + return lldb::ChildCacheState::eRefetch; +} + +ValueObjectSP VariantFrontEnd::GetChildAtIndex(uint32_t idx) { + if (idx >= m_size) + return nullptr; + + auto index = GetIndexValue(m_backend); + if (!index) + return nullptr; + + ValueObjectSP storage_sp = GetNthStorage(m_backend, *index); + if (!storage_sp) + return nullptr; + + ValueObjectSP head_sp = GetHead(*storage_sp); + if (!head_sp) + return nullptr; + + return head_sp->Clone(ConstString("Value")); +} + +SyntheticChildrenFrontEnd *formatters::MsvcStlVariantSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + if (valobj_sp) + return new VariantFrontEnd(*valobj_sp); + return nullptr; +} diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 7f56917..86ae7dd 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1987,8 +1987,11 @@ size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst, size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, Status &error, bool force_live_memory, - lldb::addr_t *load_addr_ptr) { + lldb::addr_t *load_addr_ptr, + bool *did_read_live_memory) { error.Clear(); + if (did_read_live_memory) + *did_read_live_memory = false; Address fixed_addr = addr; if (ProcessIsValid()) @@ -2086,6 +2089,8 @@ size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, if (bytes_read) { if (load_addr_ptr) *load_addr_ptr = load_addr; + if (did_read_live_memory) + *did_read_live_memory = true; return bytes_read; } } |