Skip to content

Commit 20dd053

Browse files
authored
[lldb][DataFormatters] Support newer _LIBCPP_COMPRESSED_PAIR layout (#155153)
Starting with #154686 the compressed_pair children are now wrapped in an anonymous structure. This patch adjusts the LLDB data-formatters to support that. Outstanding questions: 1. Should GetChildMemberWithName look through anonymous structures? That will break users most likely. But maybe introducing a new API is worth it? Then we wouldnt have to do this awkward passing around of `anon_struct_index` 2. Do we support the layout without the anonymous structure? It's not too much added complexity. And we did release that version of libc++, so there is code out there compiled against it. But there is no great way of testing it (some of our macOS matrix bots do test it i suppose, but not in a targeted way). We have the layout "simulator" tests for some of the STL types which I will adjust.
1 parent 8ab917a commit 20dd053

File tree

12 files changed

+150
-100
lines changed

12 files changed

+150
-100
lines changed

lldb/packages/Python/lldbsuite/test/make/libcxx-simulators-common/compressed_pair.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
// 0 -> Post-c88580c layout
99
// 1 -> Post-27c83382d83dc layout
1010
// 2 -> Post-769c42f4a552a layout
11-
// 3 -> padding-less no_unique_address-based layout (introduced in 27c83382d83dc)
11+
// 3 -> Post-f5e687d7bf49c layout
12+
// 4 -> padding-less no_unique_address-based layout (introduced in
13+
// 27c83382d83dc)
1214

1315
namespace std {
1416
namespace __lldb {
@@ -42,7 +44,7 @@ template <class _ToPad> class __compressed_pair_padding {
4244
? 0
4345
: sizeof(_ToPad) - __datasizeof_v<_ToPad>];
4446
};
45-
#elif COMPRESSED_PAIR_REV > 1 && COMPRESSED_PAIR_REV < 3
47+
#elif COMPRESSED_PAIR_REV > 1 && COMPRESSED_PAIR_REV < 4
4648
template <class _ToPad>
4749
inline const bool __is_reference_or_unpadded_object =
4850
(std::is_empty<_ToPad>::value && !__lldb_is_final<_ToPad>::value) ||
@@ -125,6 +127,27 @@ class __compressed_pair : private __compressed_pair_elem<_T1, 0>,
125127
_LLDB_NO_UNIQUE_ADDRESS T3 Initializer3; \
126128
_LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding<T3> __padding3_;
127129
#elif COMPRESSED_PAIR_REV == 3
130+
#define _LLDB_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \
131+
struct { \
132+
[[__gnu__::__aligned__( \
133+
alignof(T2))]] _LLDB_NO_UNIQUE_ADDRESS T1 Initializer1; \
134+
_LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding<T1> __padding1_; \
135+
_LLDB_NO_UNIQUE_ADDRESS T2 Initializer2; \
136+
_LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding<T2> __padding2_; \
137+
}
138+
139+
#define _LLDB_COMPRESSED_TRIPLE(T1, Initializer1, T2, Initializer2, T3, \
140+
Initializer3) \
141+
struct { \
142+
[[using __gnu__: __aligned__(alignof(T2)), \
143+
__aligned__(alignof(T3))]] _LLDB_NO_UNIQUE_ADDRESS T1 Initializer1; \
144+
_LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding<T1> __padding1_; \
145+
_LLDB_NO_UNIQUE_ADDRESS T2 Initializer2; \
146+
_LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding<T2> __padding2_; \
147+
_LLDB_NO_UNIQUE_ADDRESS T3 Initializer3; \
148+
_LLDB_NO_UNIQUE_ADDRESS __compressed_pair_padding<T3> __padding3_; \
149+
}
150+
#elif COMPRESSED_PAIR_REV == 4
128151
#define _LLDB_COMPRESSED_PAIR(T1, Name1, T2, Name2) \
129152
_LLDB_NO_UNIQUE_ADDRESS T1 Name1; \
130153
_LLDB_NO_UNIQUE_ADDRESS T2 Name2

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,18 @@ lldb::ChildCacheState LibCxxForwardListFrontEnd::Update() {
339339
if (err.Fail() || !backend_addr)
340340
return lldb::ChildCacheState::eRefetch;
341341

342-
ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
342+
auto list_base_sp = m_backend.GetChildAtIndex(0);
343+
if (!list_base_sp)
344+
return lldb::ChildCacheState::eRefetch;
345+
346+
// Anonymous strucutre index is in base class at index 0.
347+
auto [impl_sp, is_compressed_pair] =
348+
GetValueOrOldCompressedPair(*list_base_sp, /*anon_struct_idx=*/0,
349+
"__before_begin_", "__before_begin_");
343350
if (!impl_sp)
344351
return ChildCacheState::eRefetch;
345352

346-
if (isOldCompressedPairLayout(*impl_sp))
353+
if (is_compressed_pair)
347354
impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
348355

349356
if (!impl_sp)
@@ -366,17 +373,10 @@ llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
366373
if (!m_head || !m_tail || m_node_address == 0)
367374
return 0;
368375

369-
ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName("__size_"));
370-
if (!size_node_sp) {
371-
size_node_sp = m_backend.GetChildMemberWithName(
372-
"__size_alloc_"); // pre-compressed_pair rework
373-
374-
if (!isOldCompressedPairLayout(*size_node_sp))
375-
return llvm::createStringError("Unexpected std::list layout: expected "
376-
"old __compressed_pair layout.");
377-
376+
auto [size_node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
377+
m_backend, /*anon_struct_idx=*/1, "__size_", "__size_alloc_");
378+
if (is_compressed_pair)
378379
size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
379-
}
380380

381381
if (size_node_sp)
382382
m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);

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

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,6 @@ static void consumeInlineNamespace(llvm::StringRef &name) {
4949
}
5050
}
5151

52-
bool lldb_private::formatters::isOldCompressedPairLayout(
53-
ValueObject &pair_obj) {
54-
return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
55-
}
56-
5752
bool lldb_private::formatters::isStdTemplate(ConstString type_name,
5853
llvm::StringRef type) {
5954
llvm::StringRef name = type_name.GetStringRef();
@@ -105,6 +100,44 @@ lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(
105100
return value;
106101
}
107102

103+
std::pair<lldb::ValueObjectSP, bool>
104+
lldb_private::formatters::GetValueOrOldCompressedPair(
105+
ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name,
106+
llvm::StringRef compressed_pair_name) {
107+
auto is_old_compressed_pair = [](ValueObject &pair_obj) -> bool {
108+
return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");
109+
};
110+
111+
// Try searching the child member in an anonymous structure first.
112+
if (auto unwrapped = obj.GetChildAtIndex(anon_struct_idx)) {
113+
ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
114+
if (node_sp)
115+
return {node_sp, is_old_compressed_pair(*node_sp)};
116+
}
117+
118+
// Older versions of libc++ don't wrap the children in anonymous structures.
119+
// Try that instead.
120+
ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));
121+
if (node_sp)
122+
return {node_sp, is_old_compressed_pair(*node_sp)};
123+
124+
// Try the even older __compressed_pair layout.
125+
126+
assert(!compressed_pair_name.empty());
127+
128+
node_sp = obj.GetChildMemberWithName(compressed_pair_name);
129+
130+
// Unrecognized layout (possibly older than LLDB supports).
131+
if (!node_sp)
132+
return {nullptr, false};
133+
134+
// Expected old compressed_pair layout, but got something else.
135+
if (!is_old_compressed_pair(*node_sp))
136+
return {nullptr, false};
137+
138+
return {node_sp, true};
139+
}
140+
108141
bool lldb_private::formatters::LibcxxFunctionSummaryProvider(
109142
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
110143

@@ -205,11 +238,12 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(
205238
if (!valobj_sp)
206239
return false;
207240

208-
ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
241+
auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
242+
*valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
209243
if (!ptr_sp)
210244
return false;
211245

212-
if (isOldCompressedPairLayout(*ptr_sp))
246+
if (is_compressed_pair)
213247
ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);
214248

215249
if (!ptr_sp)
@@ -379,13 +413,14 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
379413
if (!valobj_sp)
380414
return lldb::ChildCacheState::eRefetch;
381415

382-
ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
416+
auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
417+
*valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
383418
if (!ptr_sp)
384419
return lldb::ChildCacheState::eRefetch;
385420

386421
// Retrieve the actual pointer and the deleter, and clone them to give them
387422
// user-friendly names.
388-
if (isOldCompressedPairLayout(*ptr_sp)) {
423+
if (is_compressed_pair) {
389424
if (ValueObjectSP value_pointer_sp =
390425
GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
391426
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
@@ -424,17 +459,15 @@ enum class StringLayout { CSD, DSC };
424459
}
425460

426461
static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
427-
if (auto rep_sp = valobj.GetChildMemberWithName("__rep_"))
428-
return rep_sp;
429-
430-
ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
431-
if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
462+
auto [valobj_r_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
463+
valobj, /*anon_struct_idx=*/0, "__rep_", "__r_");
464+
if (!valobj_r_sp)
432465
return nullptr;
433466

434-
if (!isOldCompressedPairLayout(*valobj_r_sp))
435-
return nullptr;
467+
if (is_compressed_pair)
468+
return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
436469

437-
return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
470+
return valobj_r_sp;
438471
}
439472

440473
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,22 @@ GetChildMemberWithName(ValueObject &obj,
2525

2626
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair);
2727
lldb::ValueObjectSP GetSecondValueOfLibCXXCompressedPair(ValueObject &pair);
28-
bool isOldCompressedPairLayout(ValueObject &pair_obj);
28+
29+
/// Returns the ValueObjectSP of the child of \c obj. If \c obj has no
30+
/// child named \c child_name, returns the __compressed_pair child instead
31+
/// with \c compressed_pair_name, if one exists.
32+
///
33+
/// Latest libc++ wrap the compressed children in an anonymous structure.
34+
/// The \c anon_struct_idx indicates the location of this struct.
35+
///
36+
/// The returned boolean is \c true if the returned child was has an old-style
37+
/// libc++ __compressed_pair layout.
38+
///
39+
/// If no child was found returns a nullptr.
40+
std::pair<lldb::ValueObjectSP, bool>
41+
GetValueOrOldCompressedPair(ValueObject &obj, size_t anon_struct_idx,
42+
llvm::StringRef child_name,
43+
llvm::StringRef compressed_pair_name);
2944
bool isStdTemplate(ConstString type_name, llvm::StringRef type);
3045

3146
bool LibcxxStringSummaryProviderASCII(

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,8 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
200200
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
201201

202202
private:
203-
llvm::Expected<uint32_t> CalculateNumChildrenForOldCompressedPairLayout();
203+
llvm::Expected<uint32_t>
204+
CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair);
204205

205206
/// Returns the ValueObject for the __tree_node type that
206207
/// holds the key/value pair of the node at index \ref idx.
@@ -254,16 +255,8 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
254255

255256
llvm::Expected<uint32_t>
256257
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
257-
CalculateNumChildrenForOldCompressedPairLayout() {
258-
ValueObjectSP node_sp(m_tree->GetChildMemberWithName("__pair3_"));
259-
if (!node_sp)
260-
return 0;
261-
262-
if (!isOldCompressedPairLayout(*node_sp))
263-
return llvm::createStringError("Unexpected std::map layout: expected "
264-
"old __compressed_pair layout.");
265-
266-
node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
258+
CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair) {
259+
auto node_sp = GetFirstValueOfLibCXXCompressedPair(pair);
267260

268261
if (!node_sp)
269262
return 0;
@@ -281,12 +274,16 @@ llvm::Expected<uint32_t> lldb_private::formatters::
281274
if (m_tree == nullptr)
282275
return 0;
283276

284-
if (auto node_sp = m_tree->GetChildMemberWithName("__size_")) {
285-
m_count = node_sp->GetValueAsUnsigned(0);
286-
return m_count;
287-
}
277+
auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
278+
*m_tree, /*anon_struct_idx=*/2, "__size_", "__pair3_");
279+
if (!size_sp)
280+
return llvm::createStringError("Unexpected std::map layout");
288281

289-
return CalculateNumChildrenForOldCompressedPairLayout();
282+
if (is_compressed_pair)
283+
return CalculateNumChildrenForOldCompressedPairLayout(*size_sp);
284+
285+
m_count = size_sp->GetValueAsUnsigned(0);
286+
return m_count;
290287
}
291288

292289
ValueObjectSP

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

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -130,22 +130,17 @@ CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
130130

131131
CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
132132
GetNodeType() {
133-
auto node_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"});
134-
135-
if (!node_sp) {
136-
auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
137-
if (!p1_sp)
138-
return {};
133+
auto table_sp = m_backend.GetChildMemberWithName("__table_");
134+
if (!table_sp)
135+
return {};
139136

140-
if (!isOldCompressedPairLayout(*p1_sp))
141-
return {};
137+
auto [node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
138+
*table_sp, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
139+
if (is_compressed_pair)
140+
node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
142141

143-
node_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
144-
if (!node_sp)
145-
return {};
146-
}
147-
148-
assert(node_sp);
142+
if (!node_sp)
143+
return {};
149144

150145
return node_sp->GetCompilerType().GetTypeTemplateArgument(0).GetPointeeType();
151146
}
@@ -223,19 +218,15 @@ lldb::ValueObjectSP lldb_private::formatters::
223218
llvm::Expected<size_t>
224219
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
225220
CalculateNumChildrenImpl(ValueObject &table) {
226-
if (auto size_sp = table.GetChildMemberWithName("__size_"))
221+
auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
222+
table, /*anon_struct_idx=*/2, "__size_", "__p2_");
223+
if (!is_compressed_pair && size_sp)
227224
return size_sp->GetValueAsUnsigned(0);
228225

229-
ValueObjectSP p2_sp = table.GetChildMemberWithName("__p2_");
230-
if (!p2_sp)
231-
return llvm::createStringError(
232-
"Unexpected std::unordered_map layout: __p2_ member not found.");
226+
if (!is_compressed_pair)
227+
return llvm::createStringError("Unsupported std::unordered_map layout.");
233228

234-
if (!isOldCompressedPairLayout(*p2_sp))
235-
return llvm::createStringError("Unexpected std::unordered_map layout: old "
236-
"__compressed_pair layout not found.");
237-
238-
ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
229+
ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*size_sp);
239230

240231
if (!num_elements_sp)
241232
return llvm::createStringError(
@@ -246,19 +237,13 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
246237
}
247238

248239
static ValueObjectSP GetTreePointer(ValueObject &table) {
249-
ValueObjectSP tree_sp = table.GetChildMemberWithName("__first_node_");
250-
if (!tree_sp) {
251-
ValueObjectSP p1_sp = table.GetChildMemberWithName("__p1_");
252-
if (!p1_sp)
253-
return nullptr;
254-
255-
if (!isOldCompressedPairLayout(*p1_sp))
256-
return nullptr;
257-
258-
tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
259-
if (!tree_sp)
260-
return nullptr;
261-
}
240+
auto [tree_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
241+
table, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
242+
if (is_compressed_pair)
243+
tree_sp = GetFirstValueOfLibCXXCompressedPair(*tree_sp);
244+
245+
if (!tree_sp)
246+
return nullptr;
262247

263248
return tree_sp->GetChildMemberWithName("__next_");
264249
}

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,15 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
126126
}
127127

128128
static ValueObjectSP GetDataPointer(ValueObject &root) {
129-
if (auto cap_sp = root.GetChildMemberWithName("__cap_"))
130-
return cap_sp;
131-
132-
ValueObjectSP cap_sp = root.GetChildMemberWithName("__end_cap_");
129+
auto [cap_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
130+
root, /*anon_struct_idx=*/2, "__cap_", "__end_cap_");
133131
if (!cap_sp)
134132
return nullptr;
135133

136-
if (!isOldCompressedPairLayout(*cap_sp))
137-
return nullptr;
134+
if (is_compressed_pair)
135+
return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
138136

139-
return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
137+
return cap_sp;
140138
}
141139

142140
lldb::ChildCacheState

lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx-simulators/invalid-vector/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#define COMPRESSED_PAIR_REV 3
1+
#define COMPRESSED_PAIR_REV 4
22
#include <libcxx-simulators-common/compressed_pair.h>
33

44
namespace std {

0 commit comments

Comments
 (0)