Skip to content

Commit 6e76c18

Browse files
committed
[lldb][DataFormatter] Simplify std::map formatter
Depends on: * llvm#97544 * llvm#97549 * llvm#97551 This patch tries to simplify the way in which the `std::map` formatter goes from the root `__tree` pointer to a specific key/value pair. Previously we would synthesize a structure that mimicked what `__iter_pointer` looked like in memory, then called `GetChildCompilerTypeAtIndex` on it to find the byte offset into that structure at which the pair was located at, and finally use that offset through a call to `GetSyntheticChildAtOffset` to retrieve that pair. Not only was this logic hard to follow, and encoded the libc++ layout in non-obvious ways, it was also fragile to alignment miscalculations (llvm#97443); this would break after the new layout of std::map landed as part of inhttps://github.com/llvm/issues/93069. Instead, this patch simply casts the `__iter_pointer` to the `__node_pointer` and uses a straightforward `GetChildMemberWithName("__value_")` to get to the key/value we care about. This allows us to get rid of some support infrastructure/class state. Ideally we would fix the underlying alignment issue, but this unblocks the libc++ refactor in the interim, while also benefitting the formatter in terms of readability (in my opinion).
1 parent 78fa7f2 commit 6e76c18

File tree

1 file changed

+40
-93
lines changed

1 file changed

+40
-93
lines changed

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

Lines changed: 40 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,30 @@
1919
#include "lldb/Utility/Stream.h"
2020
#include "lldb/lldb-forward.h"
2121
#include <cstdint>
22+
#include <locale>
2223
#include <optional>
2324

2425
using namespace lldb;
2526
using namespace lldb_private;
2627
using namespace lldb_private::formatters;
2728

29+
// The flattened layout of the std::__tree_iterator::__ptr_ looks
30+
// as follows:
31+
//
32+
// The following shows the contiguous block of memory:
33+
//
34+
// +-----------------------------+ class __tree_end_node
35+
// __ptr_ | pointer __left_; |
36+
// +-----------------------------+ class __tree_node_base
37+
// | pointer __right_; |
38+
// | __parent_pointer __parent_; |
39+
// | bool __is_black_; |
40+
// +-----------------------------+ class __tree_node
41+
// | __node_value_type __value_; | <<< our key/value pair
42+
// +-----------------------------+
43+
//
44+
// where __ptr_ has type __iter_pointer.
45+
2846
class MapEntry {
2947
public:
3048
MapEntry() = default;
@@ -183,10 +201,6 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
183201
size_t GetIndexOfChildWithName(ConstString name) override;
184202

185203
private:
186-
bool GetDataType();
187-
188-
std::optional<uint32_t> GetValueOffset();
189-
190204
/// Returns the ValueObject for the __tree_node type that
191205
/// holds the key/value pair of the node at index \ref idx.
192206
///
@@ -205,8 +219,7 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
205219

206220
ValueObject *m_tree = nullptr;
207221
ValueObject *m_root_node = nullptr;
208-
CompilerType m_element_type;
209-
uint32_t m_value_type_offset = UINT32_MAX;
222+
CompilerType m_node_ptr_type;
210223
size_t m_count = UINT32_MAX;
211224
std::map<size_t, MapIterator> m_iterators;
212225
};
@@ -215,7 +228,7 @@ class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
215228

216229
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
217230
LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
218-
: SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_iterators() {
231+
: SyntheticChildrenFrontEnd(*valobj_sp) {
219232
if (valobj_sp)
220233
Update();
221234
}
@@ -241,80 +254,6 @@ llvm::Expected<uint32_t> lldb_private::formatters::
241254
return m_count;
242255
}
243256

244-
bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
245-
if (m_element_type.IsValid())
246-
return true;
247-
m_element_type.Clear();
248-
ValueObjectSP deref;
249-
Status error;
250-
deref = m_root_node->Dereference(error);
251-
if (!deref || error.Fail())
252-
return false;
253-
deref = deref->GetChildMemberWithName("__value_");
254-
if (deref) {
255-
m_element_type = deref->GetCompilerType();
256-
return true;
257-
}
258-
deref = m_backend.GetChildAtNamePath({"__tree_", "__pair3_"});
259-
if (!deref)
260-
return false;
261-
m_element_type = deref->GetCompilerType()
262-
.GetTypeTemplateArgument(1)
263-
.GetTypeTemplateArgument(1);
264-
if (m_element_type) {
265-
std::string name;
266-
uint64_t bit_offset_ptr;
267-
uint32_t bitfield_bit_size_ptr;
268-
bool is_bitfield_ptr;
269-
m_element_type = m_element_type.GetFieldAtIndex(
270-
0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
271-
m_element_type = m_element_type.GetTypedefedType();
272-
return m_element_type.IsValid();
273-
} else {
274-
m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
275-
return m_element_type.IsValid();
276-
}
277-
}
278-
279-
std::optional<uint32_t>
280-
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset() {
281-
if (!m_tree)
282-
return std::nullopt;
283-
284-
auto ast_ctx = m_tree->GetCompilerType()
285-
.GetTypeSystem()
286-
.dyn_cast_or_null<TypeSystemClang>();
287-
if (!ast_ctx)
288-
return std::nullopt;
289-
290-
CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
291-
llvm::StringRef(),
292-
{{"ptr0", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
293-
{"ptr1", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
294-
{"ptr2", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
295-
{"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
296-
{"payload", (m_element_type.GetCompleteType(), m_element_type)}});
297-
std::string child_name;
298-
uint32_t child_byte_size;
299-
int32_t child_byte_offset = 0;
300-
uint32_t child_bitfield_bit_size;
301-
uint32_t child_bitfield_bit_offset;
302-
bool child_is_base_class;
303-
bool child_is_deref_of_parent;
304-
uint64_t language_flags;
305-
auto child_type =
306-
llvm::expectedToStdOptional(tree_node_type.GetChildCompilerTypeAtIndex(
307-
nullptr, 4, true, true, true, child_name, child_byte_size,
308-
child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset,
309-
child_is_base_class, child_is_deref_of_parent, nullptr,
310-
language_flags));
311-
312-
if (!child_type || !child_type->IsValid())
313-
return std::nullopt;
314-
315-
return child_byte_offset;
316-
}
317-
318257
ValueObjectSP
319258
lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetKeyValuePair(
320259
size_t idx, size_t max_depth) {
@@ -336,26 +275,31 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetKeyValuePair(
336275
// this tree is garbage - stop
337276
return nullptr;
338277

339-
if (!GetDataType())
278+
if (!m_node_ptr_type.IsValid())
340279
return nullptr;
341280

342-
if (m_value_type_offset == UINT32_MAX) {
343-
if (auto offset = GetValueOffset())
344-
m_value_type_offset = *offset;
345-
else
346-
return nullptr;
347-
}
281+
// iterated_sp is a __iter_pointer at this point.
282+
// We can cast it to a __node_pointer (which is what libc++ does).
283+
auto value_type_sp = iterated_sp->Cast(m_node_ptr_type);
284+
if (!value_type_sp)
285+
return nullptr;
348286

349-
assert(m_value_type_offset != UINT32_MAX);
287+
// After dereferencing the __node_pointer, we will have a handle to
288+
// a std::__1::__tree_node<void *>, which has the __value_ member
289+
// we are looking for.
290+
Status s;
291+
value_type_sp = value_type_sp->Dereference(s);
292+
if (!value_type_sp || s.Fail())
293+
return nullptr;
350294

351-
iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_value_type_offset,
352-
m_element_type, true);
353-
if (!iterated_sp)
295+
// Finally, get the key/value pair.
296+
value_type_sp = value_type_sp->GetChildMemberWithName("__value_");
297+
if (!value_type_sp)
354298
return nullptr;
355299

356300
m_iterators[idx] = iterator;
357301

358-
return iterated_sp;
302+
return value_type_sp;
359303
}
360304

361305
lldb::ValueObjectSP
@@ -415,6 +359,9 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
415359
if (!m_tree)
416360
return lldb::ChildCacheState::eRefetch;
417361
m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get();
362+
m_node_ptr_type =
363+
m_tree->GetCompilerType().GetDirectNestedTypeWithName("__node_pointer");
364+
418365
return lldb::ChildCacheState::eRefetch;
419366
}
420367

0 commit comments

Comments
 (0)