Skip to content

Commit b83cf1e

Browse files
committed
[lldb][DataFormatters] Support newer _LIBCPP_COMPRESSED_PAIR layout (llvm#155153)
Starting with llvm#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. (cherry picked from commit 20dd053) (cherry picked from commit f3ec20b)
1 parent e669149 commit b83cf1e

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/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)
@@ -382,13 +416,14 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {
382416
if (!valobj_sp)
383417
return lldb::ChildCacheState::eRefetch;
384418

385-
ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));
419+
auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
420+
*valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");
386421
if (!ptr_sp)
387422
return lldb::ChildCacheState::eRefetch;
388423

389424
// Retrieve the actual pointer and the deleter, and clone them to give them
390425
// user-friendly names.
391-
if (isOldCompressedPairLayout(*ptr_sp)) {
426+
if (is_compressed_pair) {
392427
if (ValueObjectSP value_pointer_sp =
393428
GetFirstValueOfLibCXXCompressedPair(*ptr_sp))
394429
m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));
@@ -442,17 +477,15 @@ enum class StringLayout { CSD, DSC };
442477
}
443478

444479
static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {
445-
if (auto rep_sp = valobj.GetChildMemberWithName("__rep_"))
446-
return rep_sp;
447-
448-
ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");
449-
if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
480+
auto [valobj_r_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
481+
valobj, /*anon_struct_idx=*/0, "__rep_", "__r_");
482+
if (!valobj_r_sp)
450483
return nullptr;
451484

452-
if (!isOldCompressedPairLayout(*valobj_r_sp))
453-
return nullptr;
485+
if (is_compressed_pair)
486+
return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
454487

455-
return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);
488+
return valobj_r_sp;
456489
}
457490

458491
/// 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/LibCxxList.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,18 @@ lldb::ChildCacheState ForwardListFrontEnd::Update() {
293293
if (err.Fail() || !backend_addr)
294294
return lldb::ChildCacheState::eRefetch;
295295

296-
ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_"));
296+
auto list_base_sp = m_backend.GetChildAtIndex(0);
297+
if (!list_base_sp)
298+
return lldb::ChildCacheState::eRefetch;
299+
300+
// Anonymous strucutre index is in base class at index 0.
301+
auto [impl_sp, is_compressed_pair] =
302+
GetValueOrOldCompressedPair(*list_base_sp, /*anon_struct_idx=*/0,
303+
"__before_begin_", "__before_begin_");
297304
if (!impl_sp)
298305
return ChildCacheState::eRefetch;
299306

300-
if (isOldCompressedPairLayout(*impl_sp))
307+
if (is_compressed_pair)
301308
impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
302309

303310
if (!impl_sp)
@@ -320,17 +327,10 @@ llvm::Expected<uint32_t> ListFrontEnd::CalculateNumChildren() {
320327
if (!m_head || !m_tail || m_node_address == 0)
321328
return 0;
322329

323-
ValueObjectSP size_node_sp(m_backend.GetChildMemberWithName("__size_"));
324-
if (!size_node_sp) {
325-
size_node_sp = m_backend.GetChildMemberWithName(
326-
"__size_alloc_"); // pre-compressed_pair rework
327-
328-
if (!isOldCompressedPairLayout(*size_node_sp))
329-
return llvm::createStringError("Unexpected std::list layout: expected "
330-
"old __compressed_pair layout.");
331-
330+
auto [size_node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
331+
m_backend, /*anon_struct_idx=*/1, "__size_", "__size_alloc_");
332+
if (is_compressed_pair)
332333
size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
333-
}
334334

335335
if (size_node_sp)
336336
m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
202202
size_t GetIndexOfChildWithName(ConstString name) override;
203203

204204
private:
205-
llvm::Expected<uint32_t> CalculateNumChildrenForOldCompressedPairLayout();
205+
llvm::Expected<uint32_t>
206+
CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair);
206207

207208
/// Returns the ValueObject for the __tree_node type that
208209
/// holds the key/value pair of the node at index \ref idx.
@@ -258,16 +259,8 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
258259

259260
llvm::Expected<uint32_t>
260261
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
261-
CalculateNumChildrenForOldCompressedPairLayout() {
262-
ValueObjectSP node_sp(m_tree->GetChildMemberWithName("__pair3_"));
263-
if (!node_sp)
264-
return 0;
265-
266-
if (!isOldCompressedPairLayout(*node_sp))
267-
return llvm::createStringError("Unexpected std::map layout: expected "
268-
"old __compressed_pair layout.");
269-
270-
node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
262+
CalculateNumChildrenForOldCompressedPairLayout(ValueObject &pair) {
263+
auto node_sp = GetFirstValueOfLibCXXCompressedPair(pair);
271264

272265
if (!node_sp)
273266
return 0;
@@ -285,12 +278,16 @@ llvm::Expected<uint32_t> lldb_private::formatters::
285278
if (m_tree == nullptr)
286279
return 0;
287280

288-
if (auto node_sp = m_tree->GetChildMemberWithName("__size_")) {
289-
m_count = node_sp->GetValueAsUnsigned(0);
290-
return m_count;
291-
}
281+
auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
282+
*m_tree, /*anon_struct_idx=*/2, "__size_", "__pair3_");
283+
if (!size_sp)
284+
return llvm::createStringError("Unexpected std::map layout");
292285

293-
return CalculateNumChildrenForOldCompressedPairLayout();
286+
if (is_compressed_pair)
287+
return CalculateNumChildrenForOldCompressedPairLayout(*size_sp);
288+
289+
m_count = size_sp->GetValueAsUnsigned(0);
290+
return m_count;
294291
}
295292

296293
ValueObjectSP

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

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

135135
CompilerType lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
136136
GetNodeType() {
137-
auto node_sp = m_backend.GetChildAtNamePath({"__table_", "__first_node_"});
138-
139-
if (!node_sp) {
140-
auto p1_sp = m_backend.GetChildAtNamePath({"__table_", "__p1_"});
141-
if (!p1_sp)
142-
return {};
137+
auto table_sp = m_backend.GetChildMemberWithName("__table_");
138+
if (!table_sp)
139+
return {};
143140

144-
if (!isOldCompressedPairLayout(*p1_sp))
145-
return {};
141+
auto [node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
142+
*table_sp, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
143+
if (is_compressed_pair)
144+
node_sp = GetFirstValueOfLibCXXCompressedPair(*node_sp);
146145

147-
node_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
148-
if (!node_sp)
149-
return {};
150-
}
151-
152-
assert(node_sp);
146+
if (!node_sp)
147+
return {};
153148

154149
return node_sp->GetCompilerType().GetTypeTemplateArgument(0).GetPointeeType();
155150
}
@@ -227,19 +222,15 @@ lldb::ValueObjectSP lldb_private::formatters::
227222
llvm::Expected<size_t>
228223
lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
229224
CalculateNumChildrenImpl(ValueObject &table) {
230-
if (auto size_sp = table.GetChildMemberWithName("__size_"))
225+
auto [size_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
226+
table, /*anon_struct_idx=*/2, "__size_", "__p2_");
227+
if (!is_compressed_pair && size_sp)
231228
return size_sp->GetValueAsUnsigned(0);
232229

233-
ValueObjectSP p2_sp = table.GetChildMemberWithName("__p2_");
234-
if (!p2_sp)
235-
return llvm::createStringError(
236-
"Unexpected std::unordered_map layout: __p2_ member not found.");
230+
if (!is_compressed_pair)
231+
return llvm::createStringError("Unsupported std::unordered_map layout.");
237232

238-
if (!isOldCompressedPairLayout(*p2_sp))
239-
return llvm::createStringError("Unexpected std::unordered_map layout: old "
240-
"__compressed_pair layout not found.");
241-
242-
ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp);
233+
ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*size_sp);
243234

244235
if (!num_elements_sp)
245236
return llvm::createStringError(
@@ -250,19 +241,13 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
250241
}
251242

252243
static ValueObjectSP GetTreePointer(ValueObject &table) {
253-
ValueObjectSP tree_sp = table.GetChildMemberWithName("__first_node_");
254-
if (!tree_sp) {
255-
ValueObjectSP p1_sp = table.GetChildMemberWithName("__p1_");
256-
if (!p1_sp)
257-
return nullptr;
258-
259-
if (!isOldCompressedPairLayout(*p1_sp))
260-
return nullptr;
261-
262-
tree_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp);
263-
if (!tree_sp)
264-
return nullptr;
265-
}
244+
auto [tree_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
245+
table, /*anon_struct_idx=*/1, "__first_node_", "__p1_");
246+
if (is_compressed_pair)
247+
tree_sp = GetFirstValueOfLibCXXCompressedPair(*tree_sp);
248+
249+
if (!tree_sp)
250+
return nullptr;
266251

267252
return tree_sp->GetChildMemberWithName("__next_");
268253
}

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

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

132132
static ValueObjectSP GetDataPointer(ValueObject &root) {
133-
if (auto cap_sp = root.GetChildMemberWithName("__cap_"))
134-
return cap_sp;
135-
136-
ValueObjectSP cap_sp = root.GetChildMemberWithName("__end_cap_");
133+
auto [cap_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
134+
root, /*anon_struct_idx=*/2, "__cap_", "__end_cap_");
137135
if (!cap_sp)
138136
return nullptr;
139137

140-
if (!isOldCompressedPairLayout(*cap_sp))
141-
return nullptr;
138+
if (is_compressed_pair)
139+
return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
142140

143-
return GetFirstValueOfLibCXXCompressedPair(*cap_sp);
141+
return cap_sp;
144142
}
145143

146144
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)