Skip to content

Commit 3b4d962

Browse files
committed
[lldb] Support new libc++ __compressed_pair layout
This patch is in preparation for the `__compressed_pair` refactor in llvm#76756. This gets the formatter tests to at least pass. Currently in draft because there's still some cleanup to be done.
1 parent 62baf21 commit 3b4d962

File tree

9 files changed

+256
-106
lines changed

9 files changed

+256
-106
lines changed

lldb/examples/synthetic/libcxx.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,12 @@ def _get_value_of_compressed_pair(self, pair):
721721
def update(self):
722722
logger = lldb.formatters.Logger.Logger()
723723
try:
724+
has_compressed_pair_layout = True
725+
alloc_valobj = self.valobj.GetChildMemberWithName("__alloc_")
726+
size_valobj = self.valobj.GetChildMemberWithName("__size_")
727+
if alloc_valobj.IsValid() and size_valobj.IsValid():
728+
has_compressed_pair_layout = False
729+
724730
# A deque is effectively a two-dim array, with fixed width.
725731
# 'map' contains pointers to the rows of this array. The
726732
# full memory area allocated by the deque is delimited
@@ -734,9 +740,13 @@ def update(self):
734740
# variable tells which element in this NxM array is the 0th
735741
# one, and the 'size' element gives the number of elements
736742
# in the deque.
737-
count = self._get_value_of_compressed_pair(
738-
self.valobj.GetChildMemberWithName("__size_")
739-
)
743+
if has_compressed_pair_layout:
744+
count = self._get_value_of_compressed_pair(
745+
self.valobj.GetChildMemberWithName("__size_")
746+
)
747+
else:
748+
count = size_valobj.GetValueAsUnsigned(0)
749+
740750
# give up now if we cant access memory reliably
741751
if self.block_size < 0:
742752
logger.write("block_size < 0")
@@ -748,9 +758,13 @@ def update(self):
748758
self.map_begin = map_.GetChildMemberWithName("__begin_")
749759
map_begin = self.map_begin.GetValueAsUnsigned(0)
750760
map_end = map_.GetChildMemberWithName("__end_").GetValueAsUnsigned(0)
751-
map_endcap = self._get_value_of_compressed_pair(
752-
map_.GetChildMemberWithName("__end_cap_")
753-
)
761+
762+
if has_compressed_pair_layout:
763+
map_endcap = self._get_value_of_compressed_pair(
764+
map_.GetChildMemberWithName("__end_cap_")
765+
)
766+
else:
767+
map_endcap = map_.GetChildMemberWithName("__end_cap_").GetValueAsUnsigned(0)
754768

755769
# check consistency
756770
if not map_first <= map_begin <= map_end <= map_endcap:

lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
2828
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
2929
#include "lldb/lldb-enumerations.h"
30+
#include "lldb/lldb-forward.h"
3031
#include <optional>
3132
#include <tuple>
3233

@@ -176,9 +177,9 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
176177
if (!ptr_sp)
177178
return false;
178179

179-
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
180-
if (!ptr_sp)
181-
return false;
180+
if (ValueObjectSP compressed_pair_value__sp =
181+
GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
182+
ptr_sp = std::move(compressed_pair_value__sp);
182183

183184
if (ptr_sp->GetValueAsUnsigned(0) == 0) {
184185
stream.Printf("nullptr");
@@ -701,15 +702,28 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
701702
if (!ptr_sp)
702703
return lldb::ChildCacheState::eRefetch;
703704

705+
bool has_compressed_pair_layout = true;
706+
ValueObjectSP deleter_sp(valobj_sp->GetChildMemberWithName("__deleter_"));
707+
if (deleter_sp)
708+
has_compressed_pair_layout = false;
709+
704710
// Retrieve the actual pointer and the deleter, and clone them to give them
705711
// user-friendly names.
706-
ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
707-
if (value_pointer_sp)
708-
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
709-
710-
ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
711-
if (deleter_sp)
712+
if (has_compressed_pair_layout) {
713+
ValueObjectSP value_pointer_sp =
714+
GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
715+
if (value_pointer_sp)
716+
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
717+
718+
ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);
719+
if (deleter_sp)
720+
m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
721+
} else {
722+
// TODO: with the new layout, deleter is always a member, so empty deleters
723+
// will be displayed
724+
m_value_ptr_sp = ptr_sp->Clone(ConstString("pointer"));
712725
m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));
726+
}
713727

714728
return lldb::ChildCacheState::eRefetch;
715729
}
@@ -747,11 +761,7 @@ namespace {
747761
enum class StringLayout { CSD, DSC };
748762
}
749763

750-
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
751-
/// extract its data payload. Return the size + payload pair.
752-
// TODO: Support big-endian architectures.
753-
static std::optional<std::pair<uint64_t, ValueObjectSP>>
754-
ExtractLibcxxStringInfo(ValueObject &valobj) {
764+
static ValueObjectSP ExtractLibCxxStringDataV1(ValueObject &valobj) {
755765
ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
756766
if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
757767
return {};
@@ -767,6 +777,29 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
767777
if (!valobj_rep_sp)
768778
return {};
769779

780+
return valobj_rep_sp;
781+
}
782+
783+
static ValueObjectSP ExtractLibCxxStringDataV2(ValueObject &valobj) {
784+
return valobj.GetChildMemberWithName("__rep_");
785+
}
786+
787+
static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
788+
if (ValueObjectSP ret = ExtractLibCxxStringDataV1(valobj))
789+
return ret;
790+
791+
return ExtractLibCxxStringDataV2(valobj);
792+
}
793+
794+
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
795+
/// extract its data payload. Return the size + payload pair.
796+
// TODO: Support big-endian architectures.
797+
static std::optional<std::pair<uint64_t, ValueObjectSP>>
798+
ExtractLibcxxStringInfo(ValueObject &valobj) {
799+
ValueObjectSP valobj_rep_sp = ExtractLibCxxStringData(valobj);
800+
if (!valobj_rep_sp || !valobj_rep_sp->GetError().Success())
801+
return {};
802+
770803
ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");
771804
if (!l)
772805
return {};

lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "lldb/Utility/Endian.h"
1818
#include "lldb/Utility/Status.h"
1919
#include "lldb/Utility/Stream.h"
20+
#include "lldb/lldb-enumerations.h"
2021

2122
using namespace lldb;
2223
using namespace lldb_private;
@@ -294,12 +295,19 @@ lldb::ChildCacheState ForwardListFrontEnd::Update() {
294295

295296
ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
296297
if (!impl_sp)
297-
return lldb::ChildCacheState::eRefetch;
298-
impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
299-
if (!impl_sp)
300-
return lldb::ChildCacheState::eRefetch;
298+
return ChildCacheState::eRefetch;
299+
301300
m_head = impl_sp->GetChildMemberWithName("__next_").get();
302-
return lldb::ChildCacheState::eRefetch;
301+
302+
// TODO: we have to do this in this order because __before_begin_ has a
303+
// __value_ member, as does compressed_pair. Is this a problem elsewhere too?
304+
if (!m_head) {
305+
impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
306+
if (impl_sp)
307+
m_head = impl_sp->GetChildMemberWithName("__next_").get();
308+
}
309+
310+
return ChildCacheState::eRefetch;
303311
}
304312

305313
ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp)
@@ -313,34 +321,49 @@ llvm::Expected<uint32_t> ListFrontEnd::CalculateNumChildren() {
313321
return m_count;
314322
if (!m_head || !m_tail || m_node_address == 0)
315323
return 0;
316-
ValueObjectSP size_alloc(m_backend.GetChildMemberWithName("__size_alloc_"));
317-
if (size_alloc) {
318-
ValueObjectSP value = GetFirstValueOfLibCXXCompressedPair(*size_alloc);
319-
if (value) {
320-
m_count = value->GetValueAsUnsigned(UINT32_MAX);
321-
}
324+
325+
bool has_compressed_pair_layout = false;
326+
// ValueObjectSP
327+
// node_alloc(m_backend.GetChildMemberWithName("__node_alloc_")); if
328+
// (!node_alloc)
329+
// has_compressed_pair_layout = true;
330+
331+
ValueObjectSP size_node(m_backend.GetChildMemberWithName("__size_"));
332+
if (!size_node) {
333+
size_node = m_backend.GetChildMemberWithName(
334+
"__size_alloc_"); // pre-compressed_pair rework
335+
if (size_node)
336+
has_compressed_pair_layout = true;
322337
}
323-
if (m_count != UINT32_MAX) {
338+
339+
if (size_node) {
340+
if (has_compressed_pair_layout)
341+
if (ValueObjectSP value = GetFirstValueOfLibCXXCompressedPair(*size_node))
342+
size_node = std::move(value);
343+
344+
m_count = size_node->GetValueAsUnsigned(UINT32_MAX);
345+
}
346+
347+
if (m_count != UINT32_MAX)
324348
return m_count;
325-
} else {
326-
uint64_t next_val = m_head->GetValueAsUnsigned(0);
327-
uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
328-
if (next_val == 0 || prev_val == 0)
329-
return 0;
330-
if (next_val == m_node_address)
331-
return 0;
332-
if (next_val == prev_val)
333-
return 1;
334-
uint64_t size = 2;
335-
ListEntry current(m_head);
336-
while (current.next() && current.next().value() != m_node_address) {
337-
size++;
338-
current = current.next();
339-
if (size > m_list_capping_size)
340-
break;
341-
}
342-
return m_count = (size - 1);
349+
350+
uint64_t next_val = m_head->GetValueAsUnsigned(0);
351+
uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
352+
if (next_val == 0 || prev_val == 0)
353+
return 0;
354+
if (next_val == m_node_address)
355+
return 0;
356+
if (next_val == prev_val)
357+
return 1;
358+
uint64_t size = 2;
359+
ListEntry current(m_head);
360+
while (current.next() && current.next().value() != m_node_address) {
361+
size++;
362+
current = current.next();
363+
if (size > m_list_capping_size)
364+
break;
343365
}
366+
return m_count = (size - 1);
344367
}
345368

346369
lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(uint32_t idx) {

lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
188188
size_t GetIndexOfChildWithName(ConstString name) override;
189189

190190
private:
191+
size_t CalculateNumChildrenV1();
192+
size_t CalculateNumChildrenV2();
193+
191194
bool GetDataType();
192195

193196
void GetValueOffset(const lldb::ValueObjectSP &node);
@@ -198,6 +201,7 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
198201
uint32_t m_skip_size = UINT32_MAX;
199202
size_t m_count = UINT32_MAX;
200203
std::map<size_t, MapIterator> m_iterators;
204+
bool m_has_compressed_pair_layout = false;
201205
};
202206
} // namespace formatters
203207
} // namespace lldb_private
@@ -209,6 +213,31 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
209213
Update();
210214
}
211215

216+
size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
217+
CalculateNumChildrenV2() {
218+
ValueObjectSP node(m_tree->GetChildMemberWithName("__size_"));
219+
if (!node)
220+
return 0;
221+
222+
m_count = node->GetValueAsUnsigned(0);
223+
return m_count;
224+
}
225+
226+
size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
227+
CalculateNumChildrenV1() {
228+
ValueObjectSP node(m_tree->GetChildMemberWithName("__pair3_"));
229+
if (!node)
230+
return 0;
231+
232+
node = formatters::GetFirstValueOfLibCXXCompressedPair(*node);
233+
234+
if (!node)
235+
return 0;
236+
237+
m_count = node->GetValueAsUnsigned(0);
238+
return m_count;
239+
}
240+
212241
llvm::Expected<uint32_t> lldb_private::formatters::
213242
LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren() {
214243
if (m_count != UINT32_MAX)
@@ -217,17 +246,10 @@ llvm::Expected<uint32_t> lldb_private::formatters::
217246
if (m_tree == nullptr)
218247
return 0;
219248

220-
ValueObjectSP size_node(m_tree->GetChildMemberWithName("__pair3_"));
221-
if (!size_node)
222-
return 0;
249+
if (m_has_compressed_pair_layout)
250+
return CalculateNumChildrenV1();
223251

224-
size_node = GetFirstValueOfLibCXXCompressedPair(*size_node);
225-
226-
if (!size_node)
227-
return 0;
228-
229-
m_count = size_node->GetValueAsUnsigned(0);
230-
return m_count;
252+
return CalculateNumChildrenV2();
231253
}
232254

233255
bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
@@ -244,12 +266,22 @@ bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
244266
m_element_type = deref->GetCompilerType();
245267
return true;
246268
}
247-
deref = m_backend.GetChildAtNamePath({"__tree_", "__pair3_"});
248-
if (!deref)
249-
return false;
250-
m_element_type = deref->GetCompilerType()
251-
.GetTypeTemplateArgument(1)
252-
.GetTypeTemplateArgument(1);
269+
270+
if (m_has_compressed_pair_layout) {
271+
deref = m_backend.GetChildAtNamePath({"__tree_", "__pair3_"});
272+
273+
if (!deref)
274+
return false;
275+
m_element_type = deref->GetCompilerType()
276+
.GetTypeTemplateArgument(1)
277+
.GetTypeTemplateArgument(1);
278+
} else {
279+
deref = m_backend.GetChildAtNamePath({"__tree_", "__value_comp_"});
280+
if (!deref)
281+
return false;
282+
m_element_type = deref->GetCompilerType().GetTypeTemplateArgument(1);
283+
}
284+
253285
if (m_element_type) {
254286
std::string name;
255287
uint64_t bit_offset_ptr;
@@ -413,6 +445,10 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
413445
m_tree = m_backend.GetChildMemberWithName("__tree_").get();
414446
if (!m_tree)
415447
return lldb::ChildCacheState::eRefetch;
448+
449+
m_has_compressed_pair_layout =
450+
m_tree->GetChildMemberWithName("__pair1_") != nullptr;
451+
416452
m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get();
417453
return lldb::ChildCacheState::eRefetch;
418454
}

0 commit comments

Comments
 (0)