[Lldb-commits] [lldb] 9e9b117 - [lldb] Support new libc++ __compressed_pair layout (#96538)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Sep 16 02:11:53 PDT 2024
Author: Michael Buch
Date: 2024-09-16T10:11:49+01:00
New Revision: 9e9b1178ca435f690381ffe8241e4bf1bb7e60fb
URL: https://github.com/llvm/llvm-project/commit/9e9b1178ca435f690381ffe8241e4bf1bb7e60fb
DIFF: https://github.com/llvm/llvm-project/commit/9e9b1178ca435f690381ffe8241e4bf1bb7e60fb.diff
LOG: [lldb] Support new libc++ __compressed_pair layout (#96538)
This patch is in preparation for the `__compressed_pair` refactor in
https://github.com/llvm/llvm-project/pull/76756.
This is mostly reviewable now. With the new layout we no longer need to
unwrap the `__compressed_pair`. Instead, we just need to look for child
members. E.g., to get to the underlying pointer of `std::unique_ptr` we
no longer do,
```
GetFirstValueOfCXXCompressedPair(GetChildMemberWithName("__ptr_"))
```
but instead do
```
GetChildMemberWithName("__ptr_")
```
We need to be slightly careful because previously the
`__compressed_pair` had a member called `__value_`, whereas now
`__value_` might be a member of the class that used to hold the
`__compressed_pair`. So before unwrapping the pair, we added checks for
`isOldCompressedLayout` (not sure yet whether folding this check into
`GetFirstValueOfCXXCompressedPair` is better).
Added:
Modified:
lldb/examples/synthetic/libcxx.py
lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
Removed:
################################################################################
diff --git a/lldb/examples/synthetic/libcxx.py b/lldb/examples/synthetic/libcxx.py
index 474aaa428fa23a..b078a4eb2f6394 100644
--- a/lldb/examples/synthetic/libcxx.py
+++ b/lldb/examples/synthetic/libcxx.py
@@ -721,6 +721,12 @@ def _get_value_of_compressed_pair(self, pair):
def update(self):
logger = lldb.formatters.Logger.Logger()
try:
+ has_compressed_pair_layout = True
+ alloc_valobj = self.valobj.GetChildMemberWithName("__alloc_")
+ size_valobj = self.valobj.GetChildMemberWithName("__size_")
+ if alloc_valobj.IsValid() and size_valobj.IsValid():
+ has_compressed_pair_layout = False
+
# A deque is effectively a two-dim array, with fixed width.
# 'map' contains pointers to the rows of this array. The
# full memory area allocated by the deque is delimited
@@ -734,9 +740,13 @@ def update(self):
# variable tells which element in this NxM array is the 0th
# one, and the 'size' element gives the number of elements
# in the deque.
- count = self._get_value_of_compressed_pair(
- self.valobj.GetChildMemberWithName("__size_")
- )
+ if has_compressed_pair_layout:
+ count = self._get_value_of_compressed_pair(
+ self.valobj.GetChildMemberWithName("__size_")
+ )
+ else:
+ count = size_valobj.GetValueAsUnsigned(0)
+
# give up now if we cant access memory reliably
if self.block_size < 0:
logger.write("block_size < 0")
@@ -748,9 +758,15 @@ def update(self):
self.map_begin = map_.GetChildMemberWithName("__begin_")
map_begin = self.map_begin.GetValueAsUnsigned(0)
map_end = map_.GetChildMemberWithName("__end_").GetValueAsUnsigned(0)
- map_endcap = self._get_value_of_compressed_pair(
- map_.GetChildMemberWithName("__end_cap_")
- )
+
+ if has_compressed_pair_layout:
+ map_endcap = self._get_value_of_compressed_pair(
+ map_.GetChildMemberWithName("__end_cap_")
+ )
+ else:
+ map_endcap = map_.GetChildMemberWithName(
+ "__end_cap_"
+ ).GetValueAsUnsigned(0)
# check consistency
if not map_first <= map_begin <= map_end <= map_endcap:
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index feaa51a96843ab..7d3b2410a7296e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -27,6 +27,7 @@
#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
#include <optional>
#include <tuple>
@@ -34,6 +35,32 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
+static void consumeInlineNamespace(llvm::StringRef &name) {
+ // Delete past an inline namespace, if any: __[a-zA-Z0-9_]+::
+ auto scratch = name;
+ if (scratch.consume_front("__") && std::isalnum(scratch[0])) {
+ scratch = scratch.drop_while([](char c) { return std::isalnum(c); });
+ if (scratch.consume_front("::")) {
+ // Successfully consumed a namespace.
+ name = scratch;
+ }
+ }
+}
+
+bool lldb_private::formatters::isOldCompressedPairLayout(
+ ValueObject &pair_obj) {
+ return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
+}
+
+bool lldb_private::formatters::isStdTemplate(ConstString type_name,
+ llvm::StringRef type) {
+ llvm::StringRef name = type_name.GetStringRef();
+ // The type name may be prefixed with `std::__<inline-namespace>::`.
+ if (name.consume_front("std::"))
+ consumeInlineNamespace(name);
+ return name.consume_front(type) && name.starts_with("<");
+}
+
lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(
ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {
for (ConstString name : alternative_names) {
@@ -53,7 +80,7 @@ lldb_private::formatters::GetFirstValueOfLibCXXCompressedPair(
if (first_child)
value = first_child->GetChildMemberWithName("__value_");
if (!value) {
- // pre-r300140 member name
+ // pre-c88580c member name
value = pair.GetChildMemberWithName("__first_");
}
return value;
@@ -70,7 +97,7 @@ lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
}
}
if (!value) {
- // pre-r300140 member name
+ // pre-c88580c member name
value = pair.GetChildMemberWithName("__second_");
}
return value;
@@ -176,7 +203,9 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
if (!ptr_sp)
return false;
- ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
+ if (isOldCompressedPairLayout(*ptr_sp))
+ ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
+
if (!ptr_sp)
return false;
@@ -363,13 +392,22 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
// Retrieve the actual pointer and the deleter, and clone them to give them
// user-friendly names.
- ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
- if (value_pointer_sp)
- m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
+ if (isOldCompressedPairLayout(*ptr_sp)) {
+ if (ValueObjectSP value_pointer_sp =
+ GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
+ m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
+
+ if (ValueObjectSP deleter_sp =
+ GetSecondValueOfLibCXXCompressedPair(*ptr_sp))
+ m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+ } else {
+ m_value_ptr_sp = ptr_sp->Clone(ConstString("pointer"));
- ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
- if (deleter_sp)
- m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+ if (ValueObjectSP deleter_sp =
+ valobj_sp->GetChildMemberWithName("__deleter_"))
+ if (deleter_sp->GetNumChildrenIgnoringErrors() > 0)
+ m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
+ }
return lldb::ChildCacheState::eRefetch;
}
@@ -407,24 +445,27 @@ namespace {
enum class StringLayout { CSD, DSC };
}
+static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
+ if (auto rep_sp = valobj.GetChildMemberWithName("__rep_"))
+ return rep_sp;
+
+ ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
+ if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
+ return nullptr;
+
+ if (!isOldCompressedPairLayout(*valobj_r_sp))
+ return nullptr;
+
+ return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
+}
+
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
/// extract its data payload. Return the size + payload pair.
// TODO: Support big-endian architectures.
static std::optional<std::pair<uint64_t, ValueObjectSP>>
ExtractLibcxxStringInfo(ValueObject &valobj) {
- ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
- if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
- return {};
-
- // __r_ is a compressed_pair of the actual data and the allocator. The data we
- // want is in the first base class.
- ValueObjectSP valobj_r_base_sp = valobj_r_sp->GetChildAtIndex(0);
- if (!valobj_r_base_sp)
- return {};
-
- ValueObjectSP valobj_rep_sp =
- valobj_r_base_sp->GetChildMemberWithName("__value_");
- if (!valobj_rep_sp)
+ ValueObjectSP valobj_rep_sp = ExtractLibCxxStringData(valobj);
+ if (!valobj_rep_sp || !valobj_rep_sp->GetError().Success())
return {};
ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index 5307b5251ca843..dad033611b38de 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -25,7 +25,8 @@ GetChildMemberWithName(ValueObject &obj,
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
-
+bool isOldCompressedPairLayout(ValueObject &pair_obj);
+bool isStdTemplate(ConstString type_name, llvm::StringRef type);
bool LibcxxStringSummaryProviderASCII(
ValueObject &valobj, Stream &stream,
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
index d7cfeb30557c36..4479f592fc2d2e 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp
@@ -17,6 +17,7 @@
#include "lldb/Utility/Endian.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-enumerations.h"
using namespace lldb;
using namespace lldb_private;
@@ -294,12 +295,17 @@ lldb::ChildCacheState ForwardListFrontEnd::Update() {
ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
if (!impl_sp)
- return lldb::ChildCacheState::eRefetch;
- impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
+ return ChildCacheState::eRefetch;
+
+ if (isOldCompressedPairLayout(*impl_sp))
+ impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
+
if (!impl_sp)
- return lldb::ChildCacheState::eRefetch;
+ return ChildCacheState::eRefetch;
+
m_head = impl_sp->GetChildMemberWithName("__next_").get();
- return lldb::ChildCacheState::eRefetch;
+
+ return ChildCacheState::eRefetch;
}
ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
@@ -313,34 +319,42 @@ llvm::Expected<uint32_t> ListFrontEnd::CalculateNumChildren() {
return m_count;
if (!m_head || !m_tail || m_node_address == 0)
return 0;
- ValueObjectSP size_alloc(m_backend.GetChildMemberWithName("__size_alloc_"));
- if (size_alloc) {
- ValueObjectSP value = GetFirstValueOfLibCXXCompressedPair(*size_alloc);
- if (value) {
- m_count = value->GetValueAsUnsigned(UINT32_MAX);
- }
+
+ ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName("__size_"));
+ if (!size_node_sp) {
+ size_node_sp = m_backend.GetChildMemberWithName(
+ "__size_alloc_"); // pre-compressed_pair rework
+
+ if (!isOldCompressedPairLayout(*size_node_sp))
+ return llvm::createStringError("Unexpected std::list layout: expected "
+ "old __compressed_pair layout.");
+
+ size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
}
- if (m_count != UINT32_MAX) {
+
+ if (size_node_sp)
+ m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);
+
+ if (m_count != UINT32_MAX)
return m_count;
- } else {
- uint64_t next_val = m_head->GetValueAsUnsigned(0);
- uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
- if (next_val == 0 || prev_val == 0)
- return 0;
- if (next_val == m_node_address)
- return 0;
- if (next_val == prev_val)
- return 1;
- uint64_t size = 2;
- ListEntry current(m_head);
- while (current.next() && current.next().value() != m_node_address) {
- size++;
- current = current.next();
- if (size > m_list_capping_size)
- break;
- }
- return m_count = (size - 1);
+
+ uint64_t next_val = m_head->GetValueAsUnsigned(0);
+ uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
+ if (next_val == 0 || prev_val == 0)
+ return 0;
+ if (next_val == m_node_address)
+ return 0;
+ if (next_val == prev_val)
+ return 1;
+ uint64_t size = 2;
+ ListEntry current(m_head);
+ while (current.next() && current.next().value() != m_node_address) {
+ size++;
+ current = current.next();
+ if (size > m_list_capping_size)
+ break;
}
+ return m_count = (size - 1);
}
lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(uint32_t idx) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
index 5106a63d531f88..af3e41b0daf8a3 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp
@@ -202,6 +202,8 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
size_t GetIndexOfChildWithName(ConstString name) override;
private:
+ llvm::Expected<uint32_t> CalculateNumChildrenForOldCompressedPairLayout();
+
/// Returns the ValueObject for the __tree_node type that
/// holds the key/value pair of the node at index \ref idx.
///
@@ -254,6 +256,27 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
Update();
}
+llvm::Expected<uint32_t>
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
+ CalculateNumChildrenForOldCompressedPairLayout() {
+ ValueObjectSP node_sp(m_tree->GetChildMemberWithName("__pair3_"));
+ if (!node_sp)
+ return 0;
+
+ if (!isOldCompressedPairLayout(*node_sp))
+ return llvm::createStringError("Unexpected std::map layout: expected "
+ "old __compressed_pair layout.");
+
+ node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
+
+ if (!node_sp)
+ return 0;
+
+ m_count = node_sp->GetValueAsUnsigned(0);
+
+ return m_count;
+}
+
llvm::Expected<uint32_t> lldb_private::formatters::
LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren() {
if (m_count != UINT32_MAX)
@@ -262,17 +285,12 @@ llvm::Expected<uint32_t> lldb_private::formatters::
if (m_tree == nullptr)
return 0;
- ValueObjectSP size_node(m_tree->GetChildMemberWithName("__pair3_"));
- if (!size_node)
- return 0;
-
- size_node = GetFirstValueOfLibCXXCompressedPair(*size_node);
-
- if (!size_node)
- return 0;
+ if (auto node_sp = m_tree->GetChildMemberWithName("__size_")) {
+ m_count = node_sp->GetValueAsUnsigned(0);
+ return m_count;
+ }
- m_count = size_node->GetValueAsUnsigned(0);
- return m_count;
+ return CalculateNumChildrenForOldCompressedPairLayout();
}
ValueObjectSP
@@ -371,6 +389,7 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
m_tree = m_backend.GetChildMemberWithName("__tree_").get();
if (!m_tree)
return lldb::ChildCacheState::eRefetch;
+
m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get();
m_node_ptr_type =
m_tree->GetCompilerType().GetDirectNestedTypeWithName("__node_pointer");
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 93e7f4f4fd86c1..2f65c726aa51aa 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -19,6 +19,7 @@
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
using namespace lldb;
using namespace lldb_private;
@@ -44,6 +45,10 @@ class LibcxxStdUnorderedMapSyntheticFrontEnd
size_t GetIndexOfChildWithName(ConstString name) override;
private:
+ CompilerType GetNodeType();
+ CompilerType GetElementType(CompilerType node_type);
+ llvm::Expected<size_t> CalculateNumChildrenImpl(ValueObject &table);
+
CompilerType m_element_type;
CompilerType m_node_type;
ValueObject *m_tree = nullptr;
@@ -91,29 +96,53 @@ llvm::Expected<uint32_t> lldb_private::formatters::
return m_num_elements;
}
-static void consumeInlineNamespace(llvm::StringRef &name) {
- // Delete past an inline namespace, if any: __[a-zA-Z0-9_]+::
- auto scratch = name;
- if (scratch.consume_front("__") && std::isalnum(scratch[0])) {
- scratch = scratch.drop_while([](char c) { return std::isalnum(c); });
- if (scratch.consume_front("::")) {
- // Successfully consumed a namespace.
- name = scratch;
- }
- }
+static bool isUnorderedMap(ConstString type_name) {
+ return isStdTemplate(type_name, "unordered_map") ||
+ isStdTemplate(type_name, "unordered_multimap");
}
-static bool isStdTemplate(ConstString type_name, llvm::StringRef type) {
- llvm::StringRef name = type_name.GetStringRef();
- // The type name may be prefixed with `std::__<inline-namespace>::`.
- if (name.consume_front("std::"))
- consumeInlineNamespace(name);
- return name.consume_front(type) && name.starts_with("<");
+CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
+ GetElementType(CompilerType node_type) {
+ CompilerType element_type = node_type.GetTypeTemplateArgument(0);
+
+ // This synthetic provider is used for both unordered_(multi)map and
+ // unordered_(multi)set. For unordered_map, the element type has an
+ // additional type layer, an internal struct (`__hash_value_type`)
+ // that wraps a std::pair. Peel away the internal wrapper type - whose
+ // structure is of no value to users, to expose the std::pair. This
+ // matches the structure returned by the std::map synthetic provider.
+ if (isUnorderedMap(m_backend.GetTypeName())) {
+ std::string name;
+ CompilerType field_type =
+ element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr);
+ CompilerType actual_type = field_type.GetTypedefedType();
+ if (isStdTemplate(actual_type.GetTypeName(), "pair"))
+ element_type = actual_type;
+ }
+
+ return element_type;
}
-static bool isUnorderedMap(ConstString type_name) {
- return isStdTemplate(type_name, "unordered_map") ||
- isStdTemplate(type_name, "unordered_multimap");
+CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
+ GetNodeType() {
+ auto node_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"});
+
+ if (!node_sp) {
+ auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
+ if (!p1_sp)
+ return {};
+
+ if (!isOldCompressedPairLayout(*p1_sp))
+ return {};
+
+ node_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
+ if (!node_sp)
+ return {};
+ }
+
+ assert(node_sp);
+
+ return node_sp->GetCompilerType().GetTypeTemplateArgument(0).GetPointeeType();
}
lldb::ValueObjectSP lldb_private::formatters::
@@ -136,36 +165,12 @@ lldb::ValueObjectSP lldb_private::formatters::
ValueObjectSP hash_sp = node_sp->GetChildMemberWithName("__hash_");
if (!hash_sp || !value_sp) {
if (!m_element_type) {
- auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
- if (!p1_sp)
- return nullptr;
-
- ValueObjectSP first_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!first_sp)
+ m_node_type = GetNodeType();
+ if (!m_node_type)
return nullptr;
- m_element_type = first_sp->GetCompilerType();
- m_element_type = m_element_type.GetTypeTemplateArgument(0);
- m_element_type = m_element_type.GetPointeeType();
- m_node_type = m_element_type;
- m_element_type = m_element_type.GetTypeTemplateArgument(0);
- // This synthetic provider is used for both unordered_(multi)map and
- // unordered_(multi)set. For unordered_map, the element type has an
- // additional type layer, an internal struct (`__hash_value_type`)
- // that wraps a std::pair. Peel away the internal wrapper type - whose
- // structure is of no value to users, to expose the std::pair. This
- // matches the structure returned by the std::map synthetic provider.
- if (isUnorderedMap(m_backend.GetTypeName())) {
- std::string name;
- CompilerType field_type = m_element_type.GetFieldAtIndex(
- 0, name, nullptr, nullptr, nullptr);
- CompilerType actual_type = field_type.GetTypedefedType();
- if (isStdTemplate(actual_type.GetTypeName(), "pair"))
- m_element_type = actual_type;
- }
+ m_element_type = GetElementType(m_node_type);
}
- if (!m_node_type)
- return nullptr;
node_sp = m_next_element->Cast(m_node_type.GetPointerType())
->Dereference(error);
if (!node_sp || error.Fail())
@@ -217,6 +222,49 @@ lldb::ValueObjectSP lldb_private::formatters::
m_element_type);
}
+llvm::Expected<size_t>
+lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
+ CalculateNumChildrenImpl(ValueObject &table) {
+ if (auto size_sp = table.GetChildMemberWithName("__size_"))
+ return size_sp->GetValueAsUnsigned(0);
+
+ ValueObjectSP p2_sp = table.GetChildMemberWithName("__p2_");
+ if (!p2_sp)
+ return llvm::createStringError(
+ "Unexpected std::unordered_map layout: __p2_ member not found.");
+
+ if (!isOldCompressedPairLayout(*p2_sp))
+ return llvm::createStringError("Unexpected std::unordered_map layout: old "
+ "__compressed_pair layout not found.");
+
+ ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
+
+ if (!num_elements_sp)
+ return llvm::createStringError(
+ "Unexpected std::unordered_map layout: failed to retrieve first member "
+ "in old __compressed_pair layout.");
+
+ return num_elements_sp->GetValueAsUnsigned(0);
+}
+
+static ValueObjectSP GetTreePointer(ValueObject &table) {
+ ValueObjectSP tree_sp = table.GetChildMemberWithName("__first_node_");
+ if (!tree_sp) {
+ ValueObjectSP p1_sp = table.GetChildMemberWithName("__p1_");
+ if (!p1_sp)
+ return nullptr;
+
+ if (!isOldCompressedPairLayout(*p1_sp))
+ return nullptr;
+
+ tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
+ if (!tree_sp)
+ return nullptr;
+ }
+
+ return tree_sp->GetChildMemberWithName("__next_");
+}
+
lldb::ChildCacheState
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() {
m_num_elements = 0;
@@ -226,27 +274,19 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() {
if (!table_sp)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP p2_sp = table_sp->GetChildMemberWithName("__p2_");
- if (!p2_sp)
- return lldb::ChildCacheState::eRefetch;
-
- ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
- if (!num_elements_sp)
- return lldb::ChildCacheState::eRefetch;
-
- ValueObjectSP p1_sp = table_sp->GetChildMemberWithName("__p1_");
- if (!p1_sp)
+ ValueObjectSP tree_sp = GetTreePointer(*table_sp);
+ if (!tree_sp)
return lldb::ChildCacheState::eRefetch;
- ValueObjectSP value_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
- if (!value_sp)
- return lldb::ChildCacheState::eRefetch;
+ m_tree = tree_sp.get();
- m_tree = value_sp->GetChildMemberWithName("__next_").get();
- if (m_tree == nullptr)
+ if (auto num_elems_or_err = CalculateNumChildrenImpl(*table_sp))
+ m_num_elements = *num_elems_or_err;
+ else {
+ LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters),
+ num_elems_or_err.takeError(), "{0}");
return lldb::ChildCacheState::eRefetch;
-
- m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
+ }
if (m_num_elements > 0)
m_next_element = m_tree;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
index 461fed35164b4d..3609219e70551f 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp
@@ -11,6 +11,8 @@
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
#include <optional>
using namespace lldb;
@@ -116,20 +118,29 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
m_element_type);
}
+static ValueObjectSP GetDataPointer(ValueObject &root) {
+ if (auto cap_sp = root.GetChildMemberWithName("__cap_"))
+ return cap_sp;
+
+ ValueObjectSP cap_sp = root.GetChildMemberWithName("__end_cap_");
+ if (!cap_sp)
+ return nullptr;
+
+ if (!isOldCompressedPairLayout(*cap_sp))
+ return nullptr;
+
+ return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
+}
+
lldb::ChildCacheState
lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
m_start = m_finish = nullptr;
- ValueObjectSP data_type_finder_sp(
- m_backend.GetChildMemberWithName("__end_cap_"));
- if (!data_type_finder_sp)
- return lldb::ChildCacheState::eRefetch;
+ ValueObjectSP data_sp(GetDataPointer(m_backend));
- data_type_finder_sp =
- GetFirstValueOfLibCXXCompressedPair(*data_type_finder_sp);
- if (!data_type_finder_sp)
+ if (!data_sp)
return lldb::ChildCacheState::eRefetch;
- m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
+ m_element_type = data_sp->GetCompilerType().GetPointeeType();
if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
m_element_size = *size;
@@ -216,17 +227,6 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
return retval_sp;
}
-/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
- __begin_ = 0x00000001001000e0
- __size_ = 56
- __cap_alloc_ = {
- std::__1::__libcpp_compressed_pair_imp<unsigned long,
- std::__1::allocator<unsigned long> > = {
- __first_ = 1
- }
- }
- }*/
-
lldb::ChildCacheState
lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() {
m_children.clear();
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
index 270aab1b75122f..8546b1f3b6431b 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/list/TestDataFormatterGenericList.py
@@ -60,9 +60,7 @@ def cleanup():
self.runCmd("type format add -f hex int")
self.expect(
- "frame variable numbers_list --raw",
- matching=False,
- substrs=["size=0", "{}"],
+ "frame variable numbers_list --raw", matching=False, substrs=["size=0"]
)
if stdlib_type == USE_LIBSTDCPP:
More information about the lldb-commits
mailing list