180814287SRaphael Isemann //===-- LibCxxMap.cpp -----------------------------------------------------===//
233e97e63SEnrico Granata //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633e97e63SEnrico Granata //
733e97e63SEnrico Granata //===----------------------------------------------------------------------===//
833e97e63SEnrico Granata 
933e97e63SEnrico Granata #include "LibCxx.h"
1033e97e63SEnrico Granata 
118be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
1233e97e63SEnrico Granata #include "lldb/Core/ValueObject.h"
1333e97e63SEnrico Granata #include "lldb/Core/ValueObjectConstResult.h"
1433e97e63SEnrico Granata #include "lldb/DataFormatters/FormattersHelpers.h"
1533e97e63SEnrico Granata #include "lldb/Target/Target.h"
16666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
1701c3243fSZachary Turner #include "lldb/Utility/Endian.h"
1897206d57SZachary Turner #include "lldb/Utility/Status.h"
19bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2033e97e63SEnrico Granata 
2133e97e63SEnrico Granata using namespace lldb;
2233e97e63SEnrico Granata using namespace lldb_private;
2333e97e63SEnrico Granata using namespace lldb_private::formatters;
2433e97e63SEnrico Granata 
25b9c1b51eSKate Stone class MapEntry {
2633e97e63SEnrico Granata public:
278d15f33bSEugene Zelenko   MapEntry() = default;
MapEntry(ValueObjectSP entry_sp)2833e97e63SEnrico Granata   explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
MapEntry(ValueObject * entry)29b9c1b51eSKate Stone   explicit MapEntry(ValueObject *entry)
30b9c1b51eSKate Stone       : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
3133e97e63SEnrico Granata 
left() const32b9c1b51eSKate Stone   ValueObjectSP left() const {
3333e97e63SEnrico Granata     static ConstString g_left("__left_");
3433e97e63SEnrico Granata     if (!m_entry_sp)
3533e97e63SEnrico Granata       return m_entry_sp;
36038aadd8SEnrico Granata     return m_entry_sp->GetSyntheticChildAtOffset(
37038aadd8SEnrico Granata         0, m_entry_sp->GetCompilerType(), true);
3833e97e63SEnrico Granata   }
3933e97e63SEnrico Granata 
right() const40b9c1b51eSKate Stone   ValueObjectSP right() const {
4133e97e63SEnrico Granata     static ConstString g_right("__right_");
4233e97e63SEnrico Granata     if (!m_entry_sp)
4333e97e63SEnrico Granata       return m_entry_sp;
44038aadd8SEnrico Granata     return m_entry_sp->GetSyntheticChildAtOffset(
45038aadd8SEnrico Granata         m_entry_sp->GetProcessSP()->GetAddressByteSize(),
46038aadd8SEnrico Granata         m_entry_sp->GetCompilerType(), true);
4733e97e63SEnrico Granata   }
4833e97e63SEnrico Granata 
parent() const49b9c1b51eSKate Stone   ValueObjectSP parent() const {
5033e97e63SEnrico Granata     static ConstString g_parent("__parent_");
5133e97e63SEnrico Granata     if (!m_entry_sp)
5233e97e63SEnrico Granata       return m_entry_sp;
53038aadd8SEnrico Granata     return m_entry_sp->GetSyntheticChildAtOffset(
54038aadd8SEnrico Granata         2 * m_entry_sp->GetProcessSP()->GetAddressByteSize(),
55038aadd8SEnrico Granata         m_entry_sp->GetCompilerType(), true);
5633e97e63SEnrico Granata   }
5733e97e63SEnrico Granata 
value() const58b9c1b51eSKate Stone   uint64_t value() const {
5933e97e63SEnrico Granata     if (!m_entry_sp)
6033e97e63SEnrico Granata       return 0;
6133e97e63SEnrico Granata     return m_entry_sp->GetValueAsUnsigned(0);
6233e97e63SEnrico Granata   }
6333e97e63SEnrico Granata 
error() const64b9c1b51eSKate Stone   bool error() const {
6533e97e63SEnrico Granata     if (!m_entry_sp)
6633e97e63SEnrico Granata       return true;
6733e97e63SEnrico Granata     return m_entry_sp->GetError().Fail();
6833e97e63SEnrico Granata   }
6933e97e63SEnrico Granata 
null() const70b9c1b51eSKate Stone   bool null() const { return (value() == 0); }
7133e97e63SEnrico Granata 
GetEntry() const72b9c1b51eSKate Stone   ValueObjectSP GetEntry() const { return m_entry_sp; }
7333e97e63SEnrico Granata 
SetEntry(ValueObjectSP entry)74b9c1b51eSKate Stone   void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
7533e97e63SEnrico Granata 
operator ==(const MapEntry & rhs) const76b9c1b51eSKate Stone   bool operator==(const MapEntry &rhs) const {
7733e97e63SEnrico Granata     return (rhs.m_entry_sp.get() == m_entry_sp.get());
7833e97e63SEnrico Granata   }
7933e97e63SEnrico Granata 
8033e97e63SEnrico Granata private:
8133e97e63SEnrico Granata   ValueObjectSP m_entry_sp;
8233e97e63SEnrico Granata };
8333e97e63SEnrico Granata 
84b9c1b51eSKate Stone class MapIterator {
8533e97e63SEnrico Granata public:
868d15f33bSEugene Zelenko   MapIterator() = default;
MapIterator(MapEntry entry,size_t depth=0)87b9c1b51eSKate Stone   MapIterator(MapEntry entry, size_t depth = 0)
886dc2a6a8SDavid Blaikie       : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {}
MapIterator(ValueObjectSP entry,size_t depth=0)89b9c1b51eSKate Stone   MapIterator(ValueObjectSP entry, size_t depth = 0)
906dc2a6a8SDavid Blaikie       : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {}
MapIterator(const MapIterator & rhs)91b9c1b51eSKate Stone   MapIterator(const MapIterator &rhs)
92b9c1b51eSKate Stone       : m_entry(rhs.m_entry), m_max_depth(rhs.m_max_depth), m_error(false) {}
MapIterator(ValueObject * entry,size_t depth=0)93b9c1b51eSKate Stone   MapIterator(ValueObject *entry, size_t depth = 0)
94b9c1b51eSKate Stone       : m_entry(entry), m_max_depth(depth), m_error(false) {}
9533e97e63SEnrico Granata 
965312139fSEric Christopher   MapIterator &operator=(const MapIterator &) = default;
975312139fSEric Christopher 
value()98b9c1b51eSKate Stone   ValueObjectSP value() { return m_entry.GetEntry(); }
9933e97e63SEnrico Granata 
advance(size_t count)100b9c1b51eSKate Stone   ValueObjectSP advance(size_t count) {
101bbd16815SEugene Zelenko     ValueObjectSP fail;
10233e97e63SEnrico Granata     if (m_error)
10333e97e63SEnrico Granata       return fail;
10433e97e63SEnrico Granata     size_t steps = 0;
105b9c1b51eSKate Stone     while (count > 0) {
10633e97e63SEnrico Granata       next();
10733e97e63SEnrico Granata       count--, steps++;
108b9c1b51eSKate Stone       if (m_error || m_entry.null() || (steps > m_max_depth))
10933e97e63SEnrico Granata         return fail;
11033e97e63SEnrico Granata     }
11133e97e63SEnrico Granata     return m_entry.GetEntry();
11233e97e63SEnrico Granata   }
1138d15f33bSEugene Zelenko 
11433e97e63SEnrico Granata protected:
next()115b9c1b51eSKate Stone   void next() {
11633e97e63SEnrico Granata     if (m_entry.null())
11733e97e63SEnrico Granata       return;
11833e97e63SEnrico Granata     MapEntry right(m_entry.right());
119b9c1b51eSKate Stone     if (!right.null()) {
12033e97e63SEnrico Granata       m_entry = tree_min(std::move(right));
12133e97e63SEnrico Granata       return;
12233e97e63SEnrico Granata     }
12333e97e63SEnrico Granata     size_t steps = 0;
124b9c1b51eSKate Stone     while (!is_left_child(m_entry)) {
125b9c1b51eSKate Stone       if (m_entry.error()) {
12633e97e63SEnrico Granata         m_error = true;
12733e97e63SEnrico Granata         return;
12833e97e63SEnrico Granata       }
12933e97e63SEnrico Granata       m_entry.SetEntry(m_entry.parent());
13033e97e63SEnrico Granata       steps++;
131b9c1b51eSKate Stone       if (steps > m_max_depth) {
13233e97e63SEnrico Granata         m_entry = MapEntry();
13333e97e63SEnrico Granata         return;
13433e97e63SEnrico Granata       }
13533e97e63SEnrico Granata     }
13633e97e63SEnrico Granata     m_entry = MapEntry(m_entry.parent());
13733e97e63SEnrico Granata   }
13833e97e63SEnrico Granata 
13933e97e63SEnrico Granata private:
tree_min(MapEntry x)1406dc2a6a8SDavid Blaikie   MapEntry tree_min(MapEntry x) {
14133e97e63SEnrico Granata     if (x.null())
14233e97e63SEnrico Granata       return MapEntry();
14333e97e63SEnrico Granata     MapEntry left(x.left());
14433e97e63SEnrico Granata     size_t steps = 0;
145b9c1b51eSKate Stone     while (!left.null()) {
146b9c1b51eSKate Stone       if (left.error()) {
14733e97e63SEnrico Granata         m_error = true;
14833e97e63SEnrico Granata         return MapEntry();
14933e97e63SEnrico Granata       }
15033e97e63SEnrico Granata       x = left;
15133e97e63SEnrico Granata       left.SetEntry(x.left());
15233e97e63SEnrico Granata       steps++;
15333e97e63SEnrico Granata       if (steps > m_max_depth)
15433e97e63SEnrico Granata         return MapEntry();
15533e97e63SEnrico Granata     }
15633e97e63SEnrico Granata     return x;
15733e97e63SEnrico Granata   }
15833e97e63SEnrico Granata 
is_left_child(const MapEntry & x)159b9c1b51eSKate Stone   bool is_left_child(const MapEntry &x) {
16033e97e63SEnrico Granata     if (x.null())
16133e97e63SEnrico Granata       return false;
16233e97e63SEnrico Granata     MapEntry rhs(x.parent());
16333e97e63SEnrico Granata     rhs.SetEntry(rhs.left());
16433e97e63SEnrico Granata     return x.value() == rhs.value();
16533e97e63SEnrico Granata   }
16633e97e63SEnrico Granata 
16733e97e63SEnrico Granata   MapEntry m_entry;
168*459cfa5eSSlava Gurevich   size_t m_max_depth = 0;
169*459cfa5eSSlava Gurevich   bool m_error = false;
17033e97e63SEnrico Granata };
17133e97e63SEnrico Granata 
172a0b75d7eSEnrico Granata namespace lldb_private {
173a0b75d7eSEnrico Granata namespace formatters {
174b9c1b51eSKate Stone class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
175a0b75d7eSEnrico Granata public:
176a0b75d7eSEnrico Granata   LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
177a0b75d7eSEnrico Granata 
178a0b75d7eSEnrico Granata   ~LibcxxStdMapSyntheticFrontEnd() override = default;
179a0b75d7eSEnrico Granata 
180b9c1b51eSKate Stone   size_t CalculateNumChildren() override;
181a0b75d7eSEnrico Granata 
182b9c1b51eSKate Stone   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
183a0b75d7eSEnrico Granata 
184b9c1b51eSKate Stone   bool Update() override;
185a0b75d7eSEnrico Granata 
186b9c1b51eSKate Stone   bool MightHaveChildren() override;
187a0b75d7eSEnrico Granata 
1880e4c4821SAdrian Prantl   size_t GetIndexOfChildWithName(ConstString name) override;
189a0b75d7eSEnrico Granata 
190a0b75d7eSEnrico Granata private:
191b9c1b51eSKate Stone   bool GetDataType();
192a0b75d7eSEnrico Granata 
193b9c1b51eSKate Stone   void GetValueOffset(const lldb::ValueObjectSP &node);
194a0b75d7eSEnrico Granata 
19528c878aeSShafik Yaghmour   ValueObject *m_tree = nullptr;
19628c878aeSShafik Yaghmour   ValueObject *m_root_node = nullptr;
197a0b75d7eSEnrico Granata   CompilerType m_element_type;
19828c878aeSShafik Yaghmour   uint32_t m_skip_size = UINT32_MAX;
19928c878aeSShafik Yaghmour   size_t m_count = UINT32_MAX;
200a0b75d7eSEnrico Granata   std::map<size_t, MapIterator> m_iterators;
201a0b75d7eSEnrico Granata };
202a0b75d7eSEnrico Granata } // namespace formatters
203a0b75d7eSEnrico Granata } // namespace lldb_private
204a0b75d7eSEnrico Granata 
205b9c1b51eSKate Stone lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)206b9c1b51eSKate Stone     LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
20728c878aeSShafik Yaghmour     : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_iterators() {
20833e97e63SEnrico Granata   if (valobj_sp)
20933e97e63SEnrico Granata     Update();
21033e97e63SEnrico Granata }
21133e97e63SEnrico Granata 
212b9c1b51eSKate Stone size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
CalculateNumChildren()213b9c1b51eSKate Stone     CalculateNumChildren() {
21480a11e08SShafik Yaghmour   static ConstString g_pair3_("__pair3_");
21580a11e08SShafik Yaghmour   static ConstString g_first_("__first_");
21680a11e08SShafik Yaghmour   static ConstString g_value_("__value_");
2174c2bf568SEnrico Granata 
21833e97e63SEnrico Granata   if (m_count != UINT32_MAX)
21933e97e63SEnrico Granata     return m_count;
220bbd16815SEugene Zelenko   if (m_tree == nullptr)
22133e97e63SEnrico Granata     return 0;
22280a11e08SShafik Yaghmour   ValueObjectSP m_item(m_tree->GetChildMemberWithName(g_pair3_, true));
22333e97e63SEnrico Granata   if (!m_item)
22433e97e63SEnrico Granata     return 0;
2256cc3354dSLang Hames 
2266cc3354dSLang Hames   switch (m_item->GetCompilerType().GetNumDirectBaseClasses()) {
2276cc3354dSLang Hames   case 1:
2286cc3354dSLang Hames     // Assume a pre llvm r300140 __compressed_pair implementation:
22980a11e08SShafik Yaghmour     m_item = m_item->GetChildMemberWithName(g_first_, true);
2306cc3354dSLang Hames     break;
2316cc3354dSLang Hames   case 2: {
2326cc3354dSLang Hames     // Assume a post llvm r300140 __compressed_pair implementation:
2336cc3354dSLang Hames     ValueObjectSP first_elem_parent = m_item->GetChildAtIndex(0, true);
23480a11e08SShafik Yaghmour     m_item = first_elem_parent->GetChildMemberWithName(g_value_, true);
2356cc3354dSLang Hames     break;
2366cc3354dSLang Hames   }
2376cc3354dSLang Hames   default:
2386cc3354dSLang Hames     return false;
2396cc3354dSLang Hames   }
2406cc3354dSLang Hames 
24133e97e63SEnrico Granata   if (!m_item)
24233e97e63SEnrico Granata     return 0;
24333e97e63SEnrico Granata   m_count = m_item->GetValueAsUnsigned(0);
24433e97e63SEnrico Granata   return m_count;
24533e97e63SEnrico Granata }
24633e97e63SEnrico Granata 
GetDataType()247b9c1b51eSKate Stone bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
24880a11e08SShafik Yaghmour   static ConstString g_value_("__value_");
249be3be28bSEnrico Granata   static ConstString g_tree_("__tree_");
250be3be28bSEnrico Granata   static ConstString g_pair3("__pair3_");
2514c2bf568SEnrico Granata 
25233e97e63SEnrico Granata   if (m_element_type.GetOpaqueQualType() && m_element_type.GetTypeSystem())
25333e97e63SEnrico Granata     return true;
25433e97e63SEnrico Granata   m_element_type.Clear();
25533e97e63SEnrico Granata   ValueObjectSP deref;
25697206d57SZachary Turner   Status error;
25733e97e63SEnrico Granata   deref = m_root_node->Dereference(error);
25833e97e63SEnrico Granata   if (!deref || error.Fail())
25933e97e63SEnrico Granata     return false;
26080a11e08SShafik Yaghmour   deref = deref->GetChildMemberWithName(g_value_, true);
261be3be28bSEnrico Granata   if (deref) {
26233e97e63SEnrico Granata     m_element_type = deref->GetCompilerType();
26333e97e63SEnrico Granata     return true;
26433e97e63SEnrico Granata   }
265be3be28bSEnrico Granata   deref = m_backend.GetChildAtNamePath({g_tree_, g_pair3});
266be3be28bSEnrico Granata   if (!deref)
267be3be28bSEnrico Granata     return false;
268769b21eaSPavel Labath   m_element_type = deref->GetCompilerType()
269769b21eaSPavel Labath                        .GetTypeTemplateArgument(1)
270769b21eaSPavel Labath                        .GetTypeTemplateArgument(1);
271038aadd8SEnrico Granata   if (m_element_type) {
272038aadd8SEnrico Granata     std::string name;
273038aadd8SEnrico Granata     uint64_t bit_offset_ptr;
274038aadd8SEnrico Granata     uint32_t bitfield_bit_size_ptr;
275038aadd8SEnrico Granata     bool is_bitfield_ptr;
276038aadd8SEnrico Granata     m_element_type = m_element_type.GetFieldAtIndex(
277038aadd8SEnrico Granata         0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
278be3be28bSEnrico Granata     m_element_type = m_element_type.GetTypedefedType();
279be3be28bSEnrico Granata     return m_element_type.IsValid();
280038aadd8SEnrico Granata   } else {
281769b21eaSPavel Labath     m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
282038aadd8SEnrico Granata     return m_element_type.IsValid();
283038aadd8SEnrico Granata   }
284be3be28bSEnrico Granata }
28533e97e63SEnrico Granata 
GetValueOffset(const lldb::ValueObjectSP & node)286b9c1b51eSKate Stone void lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset(
287b9c1b51eSKate Stone     const lldb::ValueObjectSP &node) {
28833e97e63SEnrico Granata   if (m_skip_size != UINT32_MAX)
28933e97e63SEnrico Granata     return;
29033e97e63SEnrico Granata   if (!node)
29133e97e63SEnrico Granata     return;
29233e97e63SEnrico Granata   CompilerType node_type(node->GetCompilerType());
29333e97e63SEnrico Granata   uint64_t bit_offset;
294be3be28bSEnrico Granata   if (node_type.GetIndexOfFieldWithName("__value_", nullptr, &bit_offset) !=
295be3be28bSEnrico Granata       UINT32_MAX) {
29633e97e63SEnrico Granata     m_skip_size = bit_offset / 8u;
297038aadd8SEnrico Granata   } else {
2986e3b0cc2SRaphael Isemann     TypeSystemClang *ast_ctx =
2996e3b0cc2SRaphael Isemann         llvm::dyn_cast_or_null<TypeSystemClang>(node_type.GetTypeSystem());
300be3be28bSEnrico Granata     if (!ast_ctx)
301be3be28bSEnrico Granata       return;
302038aadd8SEnrico Granata     CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
303038aadd8SEnrico Granata         ConstString(),
304038aadd8SEnrico Granata         {{"ptr0", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
305be3be28bSEnrico Granata          {"ptr1", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
306be3be28bSEnrico Granata          {"ptr2", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
307be3be28bSEnrico Granata          {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
308038aadd8SEnrico Granata          {"payload", (m_element_type.GetCompleteType(), m_element_type)}});
309be3be28bSEnrico Granata     std::string child_name;
310be3be28bSEnrico Granata     uint32_t child_byte_size;
311be3be28bSEnrico Granata     int32_t child_byte_offset = 0;
312be3be28bSEnrico Granata     uint32_t child_bitfield_bit_size;
313be3be28bSEnrico Granata     uint32_t child_bitfield_bit_offset;
314be3be28bSEnrico Granata     bool child_is_base_class;
315be3be28bSEnrico Granata     bool child_is_deref_of_parent;
316be3be28bSEnrico Granata     uint64_t language_flags;
317038aadd8SEnrico Granata     if (tree_node_type
318038aadd8SEnrico Granata             .GetChildCompilerTypeAtIndex(
319038aadd8SEnrico Granata                 nullptr, 4, true, true, true, child_name, child_byte_size,
320038aadd8SEnrico Granata                 child_byte_offset, child_bitfield_bit_size,
321038aadd8SEnrico Granata                 child_bitfield_bit_offset, child_is_base_class,
322038aadd8SEnrico Granata                 child_is_deref_of_parent, nullptr, language_flags)
323038aadd8SEnrico Granata             .IsValid())
324be3be28bSEnrico Granata       m_skip_size = (uint32_t)child_byte_offset;
325be3be28bSEnrico Granata   }
326be3be28bSEnrico Granata }
32733e97e63SEnrico Granata 
32833e97e63SEnrico Granata lldb::ValueObjectSP
GetChildAtIndex(size_t idx)329b9c1b51eSKate Stone lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
330b9c1b51eSKate Stone     size_t idx) {
33180a11e08SShafik Yaghmour   static ConstString g_cc("__cc");
33280a11e08SShafik Yaghmour   static ConstString g_nc("__nc");
33380a11e08SShafik Yaghmour   static ConstString g_value_("__value_");
33433e97e63SEnrico Granata 
33533e97e63SEnrico Granata   if (idx >= CalculateNumChildren())
33633e97e63SEnrico Granata     return lldb::ValueObjectSP();
337bbd16815SEugene Zelenko   if (m_tree == nullptr || m_root_node == nullptr)
33833e97e63SEnrico Granata     return lldb::ValueObjectSP();
33933e97e63SEnrico Granata 
34033e97e63SEnrico Granata   MapIterator iterator(m_root_node, CalculateNumChildren());
341a0b75d7eSEnrico Granata 
342a0b75d7eSEnrico Granata   const bool need_to_skip = (idx > 0);
343a0b75d7eSEnrico Granata   size_t actual_advancde = idx;
344b9c1b51eSKate Stone   if (need_to_skip) {
345a0b75d7eSEnrico Granata     auto cached_iterator = m_iterators.find(idx - 1);
346b9c1b51eSKate Stone     if (cached_iterator != m_iterators.end()) {
347a0b75d7eSEnrico Granata       iterator = cached_iterator->second;
348a0b75d7eSEnrico Granata       actual_advancde = 1;
349a0b75d7eSEnrico Granata     }
350a0b75d7eSEnrico Granata   }
351a0b75d7eSEnrico Granata 
352a0b75d7eSEnrico Granata   ValueObjectSP iterated_sp(iterator.advance(actual_advancde));
353b9c1b51eSKate Stone   if (!iterated_sp) {
35433e97e63SEnrico Granata     // this tree is garbage - stop
355b9c1b51eSKate Stone     m_tree =
356b9c1b51eSKate Stone         nullptr; // this will stop all future searches until an Update() happens
35733e97e63SEnrico Granata     return iterated_sp;
35833e97e63SEnrico Granata   }
359b9c1b51eSKate Stone   if (GetDataType()) {
360b9c1b51eSKate Stone     if (!need_to_skip) {
36197206d57SZachary Turner       Status error;
36233e97e63SEnrico Granata       iterated_sp = iterated_sp->Dereference(error);
363b9c1b51eSKate Stone       if (!iterated_sp || error.Fail()) {
364bbd16815SEugene Zelenko         m_tree = nullptr;
36533e97e63SEnrico Granata         return lldb::ValueObjectSP();
36633e97e63SEnrico Granata       }
36733e97e63SEnrico Granata       GetValueOffset(iterated_sp);
36880a11e08SShafik Yaghmour       auto child_sp = iterated_sp->GetChildMemberWithName(g_value_, true);
369be3be28bSEnrico Granata       if (child_sp)
370be3be28bSEnrico Granata         iterated_sp = child_sp;
371be3be28bSEnrico Granata       else
372be3be28bSEnrico Granata         iterated_sp = iterated_sp->GetSyntheticChildAtOffset(
373be3be28bSEnrico Granata             m_skip_size, m_element_type, true);
374b9c1b51eSKate Stone       if (!iterated_sp) {
375bbd16815SEugene Zelenko         m_tree = nullptr;
37633e97e63SEnrico Granata         return lldb::ValueObjectSP();
37733e97e63SEnrico Granata       }
378b9c1b51eSKate Stone     } else {
37905097246SAdrian Prantl       // because of the way our debug info is made, we need to read item 0
38005097246SAdrian Prantl       // first so that we can cache information used to generate other elements
38133e97e63SEnrico Granata       if (m_skip_size == UINT32_MAX)
38233e97e63SEnrico Granata         GetChildAtIndex(0);
383b9c1b51eSKate Stone       if (m_skip_size == UINT32_MAX) {
384bbd16815SEugene Zelenko         m_tree = nullptr;
38533e97e63SEnrico Granata         return lldb::ValueObjectSP();
38633e97e63SEnrico Granata       }
387b9c1b51eSKate Stone       iterated_sp = iterated_sp->GetSyntheticChildAtOffset(
388b9c1b51eSKate Stone           m_skip_size, m_element_type, true);
389b9c1b51eSKate Stone       if (!iterated_sp) {
390bbd16815SEugene Zelenko         m_tree = nullptr;
39133e97e63SEnrico Granata         return lldb::ValueObjectSP();
39233e97e63SEnrico Granata       }
39333e97e63SEnrico Granata     }
394b9c1b51eSKate Stone   } else {
395bbd16815SEugene Zelenko     m_tree = nullptr;
39633e97e63SEnrico Granata     return lldb::ValueObjectSP();
39733e97e63SEnrico Granata   }
39833e97e63SEnrico Granata   // at this point we have a valid
399b9c1b51eSKate Stone   // we need to copy current_sp into a new object otherwise we will end up with
400b9c1b51eSKate Stone   // all items named __value_
40133e97e63SEnrico Granata   DataExtractor data;
40297206d57SZachary Turner   Status error;
40333e97e63SEnrico Granata   iterated_sp->GetData(data, error);
404b9c1b51eSKate Stone   if (error.Fail()) {
405bbd16815SEugene Zelenko     m_tree = nullptr;
40633e97e63SEnrico Granata     return lldb::ValueObjectSP();
40733e97e63SEnrico Granata   }
40833e97e63SEnrico Granata   StreamString name;
40933e97e63SEnrico Granata   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
410b9c1b51eSKate Stone   auto potential_child_sp = CreateValueObjectFromData(
411c156427dSZachary Turner       name.GetString(), data, m_backend.GetExecutionContextRef(),
412c156427dSZachary Turner       m_element_type);
413b9c1b51eSKate Stone   if (potential_child_sp) {
414b9c1b51eSKate Stone     switch (potential_child_sp->GetNumChildren()) {
415b9c1b51eSKate Stone     case 1: {
41633e97e63SEnrico Granata       auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
41780a11e08SShafik Yaghmour       if (child0_sp && child0_sp->GetName() == g_cc)
4184fbb55b7STamas Berghammer         potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
41933e97e63SEnrico Granata       break;
42033e97e63SEnrico Granata     }
421b9c1b51eSKate Stone     case 2: {
42233e97e63SEnrico Granata       auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
42333e97e63SEnrico Granata       auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
42480a11e08SShafik Yaghmour       if (child0_sp && child0_sp->GetName() == g_cc && child1_sp &&
42580a11e08SShafik Yaghmour           child1_sp->GetName() == g_nc)
4264fbb55b7STamas Berghammer         potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
42733e97e63SEnrico Granata       break;
42833e97e63SEnrico Granata     }
42933e97e63SEnrico Granata     }
43033e97e63SEnrico Granata   }
431a0b75d7eSEnrico Granata   m_iterators[idx] = iterator;
432106aae51SEnrico Granata   return potential_child_sp;
43333e97e63SEnrico Granata }
43433e97e63SEnrico Granata 
Update()435b9c1b51eSKate Stone bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
43680a11e08SShafik Yaghmour   static ConstString g_tree_("__tree_");
43780a11e08SShafik Yaghmour   static ConstString g_begin_node_("__begin_node_");
43833e97e63SEnrico Granata   m_count = UINT32_MAX;
439bbd16815SEugene Zelenko   m_tree = m_root_node = nullptr;
440a0b75d7eSEnrico Granata   m_iterators.clear();
44180a11e08SShafik Yaghmour   m_tree = m_backend.GetChildMemberWithName(g_tree_, true).get();
44233e97e63SEnrico Granata   if (!m_tree)
44333e97e63SEnrico Granata     return false;
44480a11e08SShafik Yaghmour   m_root_node = m_tree->GetChildMemberWithName(g_begin_node_, true).get();
44533e97e63SEnrico Granata   return false;
44633e97e63SEnrico Granata }
44733e97e63SEnrico Granata 
448b9c1b51eSKate Stone bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
MightHaveChildren()449b9c1b51eSKate Stone     MightHaveChildren() {
45033e97e63SEnrico Granata   return true;
45133e97e63SEnrico Granata }
45233e97e63SEnrico Granata 
453b9c1b51eSKate Stone size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)4540e4c4821SAdrian Prantl     GetIndexOfChildWithName(ConstString name) {
45533e97e63SEnrico Granata   return ExtractIndexFromString(name.GetCString());
45633e97e63SEnrico Granata }
45733e97e63SEnrico Granata 
45833e97e63SEnrico Granata SyntheticChildrenFrontEnd *
LibcxxStdMapSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)459b9c1b51eSKate Stone lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator(
460b9c1b51eSKate Stone     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
461bbd16815SEugene Zelenko   return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr);
46233e97e63SEnrico Granata }
463