1dda28197Spatrick //===-- LibCxxMap.cpp -----------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "LibCxx.h"
10061da546Spatrick 
11dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12061da546Spatrick #include "lldb/Core/ValueObject.h"
13061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
14061da546Spatrick #include "lldb/DataFormatters/FormattersHelpers.h"
15061da546Spatrick #include "lldb/Target/Target.h"
16061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
17061da546Spatrick #include "lldb/Utility/Endian.h"
18061da546Spatrick #include "lldb/Utility/Status.h"
19061da546Spatrick #include "lldb/Utility/Stream.h"
20061da546Spatrick 
21061da546Spatrick using namespace lldb;
22061da546Spatrick using namespace lldb_private;
23061da546Spatrick using namespace lldb_private::formatters;
24061da546Spatrick 
25061da546Spatrick class MapEntry {
26061da546Spatrick public:
27061da546Spatrick   MapEntry() = default;
MapEntry(ValueObjectSP entry_sp)28061da546Spatrick   explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
MapEntry(ValueObject * entry)29061da546Spatrick   explicit MapEntry(ValueObject *entry)
30061da546Spatrick       : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
31061da546Spatrick 
left() const32061da546Spatrick   ValueObjectSP left() const {
33061da546Spatrick     static ConstString g_left("__left_");
34061da546Spatrick     if (!m_entry_sp)
35061da546Spatrick       return m_entry_sp;
36061da546Spatrick     return m_entry_sp->GetSyntheticChildAtOffset(
37061da546Spatrick         0, m_entry_sp->GetCompilerType(), true);
38061da546Spatrick   }
39061da546Spatrick 
right() const40061da546Spatrick   ValueObjectSP right() const {
41061da546Spatrick     static ConstString g_right("__right_");
42061da546Spatrick     if (!m_entry_sp)
43061da546Spatrick       return m_entry_sp;
44061da546Spatrick     return m_entry_sp->GetSyntheticChildAtOffset(
45061da546Spatrick         m_entry_sp->GetProcessSP()->GetAddressByteSize(),
46061da546Spatrick         m_entry_sp->GetCompilerType(), true);
47061da546Spatrick   }
48061da546Spatrick 
parent() const49061da546Spatrick   ValueObjectSP parent() const {
50061da546Spatrick     static ConstString g_parent("__parent_");
51061da546Spatrick     if (!m_entry_sp)
52061da546Spatrick       return m_entry_sp;
53061da546Spatrick     return m_entry_sp->GetSyntheticChildAtOffset(
54061da546Spatrick         2 * m_entry_sp->GetProcessSP()->GetAddressByteSize(),
55061da546Spatrick         m_entry_sp->GetCompilerType(), true);
56061da546Spatrick   }
57061da546Spatrick 
value() const58061da546Spatrick   uint64_t value() const {
59061da546Spatrick     if (!m_entry_sp)
60061da546Spatrick       return 0;
61061da546Spatrick     return m_entry_sp->GetValueAsUnsigned(0);
62061da546Spatrick   }
63061da546Spatrick 
error() const64061da546Spatrick   bool error() const {
65061da546Spatrick     if (!m_entry_sp)
66061da546Spatrick       return true;
67061da546Spatrick     return m_entry_sp->GetError().Fail();
68061da546Spatrick   }
69061da546Spatrick 
null() const70061da546Spatrick   bool null() const { return (value() == 0); }
71061da546Spatrick 
GetEntry() const72061da546Spatrick   ValueObjectSP GetEntry() const { return m_entry_sp; }
73061da546Spatrick 
SetEntry(ValueObjectSP entry)74061da546Spatrick   void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
75061da546Spatrick 
operator ==(const MapEntry & rhs) const76061da546Spatrick   bool operator==(const MapEntry &rhs) const {
77061da546Spatrick     return (rhs.m_entry_sp.get() == m_entry_sp.get());
78061da546Spatrick   }
79061da546Spatrick 
80061da546Spatrick private:
81061da546Spatrick   ValueObjectSP m_entry_sp;
82061da546Spatrick };
83061da546Spatrick 
84061da546Spatrick class MapIterator {
85061da546Spatrick public:
86061da546Spatrick   MapIterator() = default;
MapIterator(MapEntry entry,size_t depth=0)87061da546Spatrick   MapIterator(MapEntry entry, size_t depth = 0)
88be691f3bSpatrick       : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {}
MapIterator(ValueObjectSP entry,size_t depth=0)89061da546Spatrick   MapIterator(ValueObjectSP entry, size_t depth = 0)
90be691f3bSpatrick       : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {}
MapIterator(const MapIterator & rhs)91061da546Spatrick   MapIterator(const MapIterator &rhs)
92061da546Spatrick       : m_entry(rhs.m_entry), m_max_depth(rhs.m_max_depth), m_error(false) {}
MapIterator(ValueObject * entry,size_t depth=0)93061da546Spatrick   MapIterator(ValueObject *entry, size_t depth = 0)
94061da546Spatrick       : m_entry(entry), m_max_depth(depth), m_error(false) {}
95061da546Spatrick 
96061da546Spatrick   MapIterator &operator=(const MapIterator &) = default;
97061da546Spatrick 
value()98061da546Spatrick   ValueObjectSP value() { return m_entry.GetEntry(); }
99061da546Spatrick 
advance(size_t count)100061da546Spatrick   ValueObjectSP advance(size_t count) {
101061da546Spatrick     ValueObjectSP fail;
102061da546Spatrick     if (m_error)
103061da546Spatrick       return fail;
104061da546Spatrick     size_t steps = 0;
105061da546Spatrick     while (count > 0) {
106061da546Spatrick       next();
107061da546Spatrick       count--, steps++;
108061da546Spatrick       if (m_error || m_entry.null() || (steps > m_max_depth))
109061da546Spatrick         return fail;
110061da546Spatrick     }
111061da546Spatrick     return m_entry.GetEntry();
112061da546Spatrick   }
113061da546Spatrick 
114061da546Spatrick protected:
next()115061da546Spatrick   void next() {
116061da546Spatrick     if (m_entry.null())
117061da546Spatrick       return;
118061da546Spatrick     MapEntry right(m_entry.right());
119061da546Spatrick     if (!right.null()) {
120061da546Spatrick       m_entry = tree_min(std::move(right));
121061da546Spatrick       return;
122061da546Spatrick     }
123061da546Spatrick     size_t steps = 0;
124061da546Spatrick     while (!is_left_child(m_entry)) {
125061da546Spatrick       if (m_entry.error()) {
126061da546Spatrick         m_error = true;
127061da546Spatrick         return;
128061da546Spatrick       }
129061da546Spatrick       m_entry.SetEntry(m_entry.parent());
130061da546Spatrick       steps++;
131061da546Spatrick       if (steps > m_max_depth) {
132061da546Spatrick         m_entry = MapEntry();
133061da546Spatrick         return;
134061da546Spatrick       }
135061da546Spatrick     }
136061da546Spatrick     m_entry = MapEntry(m_entry.parent());
137061da546Spatrick   }
138061da546Spatrick 
139061da546Spatrick private:
tree_min(MapEntry x)140be691f3bSpatrick   MapEntry tree_min(MapEntry x) {
141061da546Spatrick     if (x.null())
142061da546Spatrick       return MapEntry();
143061da546Spatrick     MapEntry left(x.left());
144061da546Spatrick     size_t steps = 0;
145061da546Spatrick     while (!left.null()) {
146061da546Spatrick       if (left.error()) {
147061da546Spatrick         m_error = true;
148061da546Spatrick         return MapEntry();
149061da546Spatrick       }
150061da546Spatrick       x = left;
151061da546Spatrick       left.SetEntry(x.left());
152061da546Spatrick       steps++;
153061da546Spatrick       if (steps > m_max_depth)
154061da546Spatrick         return MapEntry();
155061da546Spatrick     }
156061da546Spatrick     return x;
157061da546Spatrick   }
158061da546Spatrick 
is_left_child(const MapEntry & x)159061da546Spatrick   bool is_left_child(const MapEntry &x) {
160061da546Spatrick     if (x.null())
161061da546Spatrick       return false;
162061da546Spatrick     MapEntry rhs(x.parent());
163061da546Spatrick     rhs.SetEntry(rhs.left());
164061da546Spatrick     return x.value() == rhs.value();
165061da546Spatrick   }
166061da546Spatrick 
167061da546Spatrick   MapEntry m_entry;
168*f6aab3d8Srobert   size_t m_max_depth = 0;
169*f6aab3d8Srobert   bool m_error = false;
170061da546Spatrick };
171061da546Spatrick 
172061da546Spatrick namespace lldb_private {
173061da546Spatrick namespace formatters {
174061da546Spatrick class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
175061da546Spatrick public:
176061da546Spatrick   LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
177061da546Spatrick 
178061da546Spatrick   ~LibcxxStdMapSyntheticFrontEnd() override = default;
179061da546Spatrick 
180061da546Spatrick   size_t CalculateNumChildren() override;
181061da546Spatrick 
182061da546Spatrick   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
183061da546Spatrick 
184061da546Spatrick   bool Update() override;
185061da546Spatrick 
186061da546Spatrick   bool MightHaveChildren() override;
187061da546Spatrick 
188061da546Spatrick   size_t GetIndexOfChildWithName(ConstString name) override;
189061da546Spatrick 
190061da546Spatrick private:
191061da546Spatrick   bool GetDataType();
192061da546Spatrick 
193061da546Spatrick   void GetValueOffset(const lldb::ValueObjectSP &node);
194061da546Spatrick 
195*f6aab3d8Srobert   ValueObject *m_tree = nullptr;
196*f6aab3d8Srobert   ValueObject *m_root_node = nullptr;
197061da546Spatrick   CompilerType m_element_type;
198*f6aab3d8Srobert   uint32_t m_skip_size = UINT32_MAX;
199*f6aab3d8Srobert   size_t m_count = UINT32_MAX;
200061da546Spatrick   std::map<size_t, MapIterator> m_iterators;
201061da546Spatrick };
202061da546Spatrick } // namespace formatters
203061da546Spatrick } // namespace lldb_private
204061da546Spatrick 
205061da546Spatrick lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)206061da546Spatrick     LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
207*f6aab3d8Srobert     : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_iterators() {
208061da546Spatrick   if (valobj_sp)
209061da546Spatrick     Update();
210061da546Spatrick }
211061da546Spatrick 
212061da546Spatrick size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
CalculateNumChildren()213061da546Spatrick     CalculateNumChildren() {
214*f6aab3d8Srobert   static ConstString g_pair3_("__pair3_");
215*f6aab3d8Srobert   static ConstString g_first_("__first_");
216*f6aab3d8Srobert   static ConstString g_value_("__value_");
217061da546Spatrick 
218061da546Spatrick   if (m_count != UINT32_MAX)
219061da546Spatrick     return m_count;
220061da546Spatrick   if (m_tree == nullptr)
221061da546Spatrick     return 0;
222*f6aab3d8Srobert   ValueObjectSP m_item(m_tree->GetChildMemberWithName(g_pair3_, true));
223061da546Spatrick   if (!m_item)
224061da546Spatrick     return 0;
225061da546Spatrick 
226061da546Spatrick   switch (m_item->GetCompilerType().GetNumDirectBaseClasses()) {
227061da546Spatrick   case 1:
228061da546Spatrick     // Assume a pre llvm r300140 __compressed_pair implementation:
229*f6aab3d8Srobert     m_item = m_item->GetChildMemberWithName(g_first_, true);
230061da546Spatrick     break;
231061da546Spatrick   case 2: {
232061da546Spatrick     // Assume a post llvm r300140 __compressed_pair implementation:
233061da546Spatrick     ValueObjectSP first_elem_parent = m_item->GetChildAtIndex(0, true);
234*f6aab3d8Srobert     m_item = first_elem_parent->GetChildMemberWithName(g_value_, true);
235061da546Spatrick     break;
236061da546Spatrick   }
237061da546Spatrick   default:
238061da546Spatrick     return false;
239061da546Spatrick   }
240061da546Spatrick 
241061da546Spatrick   if (!m_item)
242061da546Spatrick     return 0;
243061da546Spatrick   m_count = m_item->GetValueAsUnsigned(0);
244061da546Spatrick   return m_count;
245061da546Spatrick }
246061da546Spatrick 
GetDataType()247061da546Spatrick bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() {
248*f6aab3d8Srobert   static ConstString g_value_("__value_");
249061da546Spatrick   static ConstString g_tree_("__tree_");
250061da546Spatrick   static ConstString g_pair3("__pair3_");
251061da546Spatrick 
252*f6aab3d8Srobert   if (m_element_type.IsValid())
253061da546Spatrick     return true;
254061da546Spatrick   m_element_type.Clear();
255061da546Spatrick   ValueObjectSP deref;
256061da546Spatrick   Status error;
257061da546Spatrick   deref = m_root_node->Dereference(error);
258061da546Spatrick   if (!deref || error.Fail())
259061da546Spatrick     return false;
260*f6aab3d8Srobert   deref = deref->GetChildMemberWithName(g_value_, true);
261061da546Spatrick   if (deref) {
262061da546Spatrick     m_element_type = deref->GetCompilerType();
263061da546Spatrick     return true;
264061da546Spatrick   }
265061da546Spatrick   deref = m_backend.GetChildAtNamePath({g_tree_, g_pair3});
266061da546Spatrick   if (!deref)
267061da546Spatrick     return false;
268061da546Spatrick   m_element_type = deref->GetCompilerType()
269061da546Spatrick                        .GetTypeTemplateArgument(1)
270061da546Spatrick                        .GetTypeTemplateArgument(1);
271061da546Spatrick   if (m_element_type) {
272061da546Spatrick     std::string name;
273061da546Spatrick     uint64_t bit_offset_ptr;
274061da546Spatrick     uint32_t bitfield_bit_size_ptr;
275061da546Spatrick     bool is_bitfield_ptr;
276061da546Spatrick     m_element_type = m_element_type.GetFieldAtIndex(
277061da546Spatrick         0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
278061da546Spatrick     m_element_type = m_element_type.GetTypedefedType();
279061da546Spatrick     return m_element_type.IsValid();
280061da546Spatrick   } else {
281061da546Spatrick     m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
282061da546Spatrick     return m_element_type.IsValid();
283061da546Spatrick   }
284061da546Spatrick }
285061da546Spatrick 
GetValueOffset(const lldb::ValueObjectSP & node)286061da546Spatrick void lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset(
287061da546Spatrick     const lldb::ValueObjectSP &node) {
288061da546Spatrick   if (m_skip_size != UINT32_MAX)
289061da546Spatrick     return;
290061da546Spatrick   if (!node)
291061da546Spatrick     return;
292061da546Spatrick   CompilerType node_type(node->GetCompilerType());
293061da546Spatrick   uint64_t bit_offset;
294061da546Spatrick   if (node_type.GetIndexOfFieldWithName("__value_", nullptr, &bit_offset) !=
295061da546Spatrick       UINT32_MAX) {
296061da546Spatrick     m_skip_size = bit_offset / 8u;
297061da546Spatrick   } else {
298*f6aab3d8Srobert     auto ast_ctx = node_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
299061da546Spatrick     if (!ast_ctx)
300061da546Spatrick       return;
301061da546Spatrick     CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
302061da546Spatrick         ConstString(),
303061da546Spatrick         {{"ptr0", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
304061da546Spatrick          {"ptr1", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
305061da546Spatrick          {"ptr2", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
306061da546Spatrick          {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
307061da546Spatrick          {"payload", (m_element_type.GetCompleteType(), m_element_type)}});
308061da546Spatrick     std::string child_name;
309061da546Spatrick     uint32_t child_byte_size;
310061da546Spatrick     int32_t child_byte_offset = 0;
311061da546Spatrick     uint32_t child_bitfield_bit_size;
312061da546Spatrick     uint32_t child_bitfield_bit_offset;
313061da546Spatrick     bool child_is_base_class;
314061da546Spatrick     bool child_is_deref_of_parent;
315061da546Spatrick     uint64_t language_flags;
316061da546Spatrick     if (tree_node_type
317061da546Spatrick             .GetChildCompilerTypeAtIndex(
318061da546Spatrick                 nullptr, 4, true, true, true, child_name, child_byte_size,
319061da546Spatrick                 child_byte_offset, child_bitfield_bit_size,
320061da546Spatrick                 child_bitfield_bit_offset, child_is_base_class,
321061da546Spatrick                 child_is_deref_of_parent, nullptr, language_flags)
322061da546Spatrick             .IsValid())
323061da546Spatrick       m_skip_size = (uint32_t)child_byte_offset;
324061da546Spatrick   }
325061da546Spatrick }
326061da546Spatrick 
327061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)328061da546Spatrick lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex(
329061da546Spatrick     size_t idx) {
330*f6aab3d8Srobert   static ConstString g_cc_("__cc_"), g_cc("__cc");
331*f6aab3d8Srobert   static ConstString g_nc("__nc");
332*f6aab3d8Srobert   static ConstString g_value_("__value_");
333061da546Spatrick 
334061da546Spatrick   if (idx >= CalculateNumChildren())
335061da546Spatrick     return lldb::ValueObjectSP();
336061da546Spatrick   if (m_tree == nullptr || m_root_node == nullptr)
337061da546Spatrick     return lldb::ValueObjectSP();
338061da546Spatrick 
339061da546Spatrick   MapIterator iterator(m_root_node, CalculateNumChildren());
340061da546Spatrick 
341061da546Spatrick   const bool need_to_skip = (idx > 0);
342061da546Spatrick   size_t actual_advancde = idx;
343061da546Spatrick   if (need_to_skip) {
344061da546Spatrick     auto cached_iterator = m_iterators.find(idx - 1);
345061da546Spatrick     if (cached_iterator != m_iterators.end()) {
346061da546Spatrick       iterator = cached_iterator->second;
347061da546Spatrick       actual_advancde = 1;
348061da546Spatrick     }
349061da546Spatrick   }
350061da546Spatrick 
351061da546Spatrick   ValueObjectSP iterated_sp(iterator.advance(actual_advancde));
352061da546Spatrick   if (!iterated_sp) {
353061da546Spatrick     // this tree is garbage - stop
354061da546Spatrick     m_tree =
355061da546Spatrick         nullptr; // this will stop all future searches until an Update() happens
356061da546Spatrick     return iterated_sp;
357061da546Spatrick   }
358061da546Spatrick   if (GetDataType()) {
359061da546Spatrick     if (!need_to_skip) {
360061da546Spatrick       Status error;
361061da546Spatrick       iterated_sp = iterated_sp->Dereference(error);
362061da546Spatrick       if (!iterated_sp || error.Fail()) {
363061da546Spatrick         m_tree = nullptr;
364061da546Spatrick         return lldb::ValueObjectSP();
365061da546Spatrick       }
366061da546Spatrick       GetValueOffset(iterated_sp);
367*f6aab3d8Srobert       auto child_sp = iterated_sp->GetChildMemberWithName(g_value_, true);
368061da546Spatrick       if (child_sp)
369061da546Spatrick         iterated_sp = child_sp;
370061da546Spatrick       else
371061da546Spatrick         iterated_sp = iterated_sp->GetSyntheticChildAtOffset(
372061da546Spatrick             m_skip_size, m_element_type, true);
373061da546Spatrick       if (!iterated_sp) {
374061da546Spatrick         m_tree = nullptr;
375061da546Spatrick         return lldb::ValueObjectSP();
376061da546Spatrick       }
377061da546Spatrick     } else {
378061da546Spatrick       // because of the way our debug info is made, we need to read item 0
379061da546Spatrick       // first so that we can cache information used to generate other elements
380061da546Spatrick       if (m_skip_size == UINT32_MAX)
381061da546Spatrick         GetChildAtIndex(0);
382061da546Spatrick       if (m_skip_size == UINT32_MAX) {
383061da546Spatrick         m_tree = nullptr;
384061da546Spatrick         return lldb::ValueObjectSP();
385061da546Spatrick       }
386061da546Spatrick       iterated_sp = iterated_sp->GetSyntheticChildAtOffset(
387061da546Spatrick           m_skip_size, m_element_type, true);
388061da546Spatrick       if (!iterated_sp) {
389061da546Spatrick         m_tree = nullptr;
390061da546Spatrick         return lldb::ValueObjectSP();
391061da546Spatrick       }
392061da546Spatrick     }
393061da546Spatrick   } else {
394061da546Spatrick     m_tree = nullptr;
395061da546Spatrick     return lldb::ValueObjectSP();
396061da546Spatrick   }
397061da546Spatrick   // at this point we have a valid
398061da546Spatrick   // we need to copy current_sp into a new object otherwise we will end up with
399061da546Spatrick   // all items named __value_
400061da546Spatrick   DataExtractor data;
401061da546Spatrick   Status error;
402061da546Spatrick   iterated_sp->GetData(data, error);
403061da546Spatrick   if (error.Fail()) {
404061da546Spatrick     m_tree = nullptr;
405061da546Spatrick     return lldb::ValueObjectSP();
406061da546Spatrick   }
407061da546Spatrick   StreamString name;
408061da546Spatrick   name.Printf("[%" PRIu64 "]", (uint64_t)idx);
409061da546Spatrick   auto potential_child_sp = CreateValueObjectFromData(
410061da546Spatrick       name.GetString(), data, m_backend.GetExecutionContextRef(),
411061da546Spatrick       m_element_type);
412061da546Spatrick   if (potential_child_sp) {
413061da546Spatrick     switch (potential_child_sp->GetNumChildren()) {
414061da546Spatrick     case 1: {
415061da546Spatrick       auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
416*f6aab3d8Srobert       if (child0_sp &&
417*f6aab3d8Srobert           (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc))
418061da546Spatrick         potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
419061da546Spatrick       break;
420061da546Spatrick     }
421061da546Spatrick     case 2: {
422061da546Spatrick       auto child0_sp = potential_child_sp->GetChildAtIndex(0, true);
423061da546Spatrick       auto child1_sp = potential_child_sp->GetChildAtIndex(1, true);
424*f6aab3d8Srobert       if (child0_sp &&
425*f6aab3d8Srobert           (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc) &&
426*f6aab3d8Srobert           child1_sp && child1_sp->GetName() == g_nc)
427061da546Spatrick         potential_child_sp = child0_sp->Clone(ConstString(name.GetString()));
428061da546Spatrick       break;
429061da546Spatrick     }
430061da546Spatrick     }
431061da546Spatrick   }
432061da546Spatrick   m_iterators[idx] = iterator;
433061da546Spatrick   return potential_child_sp;
434061da546Spatrick }
435061da546Spatrick 
Update()436061da546Spatrick bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() {
437*f6aab3d8Srobert   static ConstString g_tree_("__tree_");
438*f6aab3d8Srobert   static ConstString g_begin_node_("__begin_node_");
439061da546Spatrick   m_count = UINT32_MAX;
440061da546Spatrick   m_tree = m_root_node = nullptr;
441061da546Spatrick   m_iterators.clear();
442*f6aab3d8Srobert   m_tree = m_backend.GetChildMemberWithName(g_tree_, true).get();
443061da546Spatrick   if (!m_tree)
444061da546Spatrick     return false;
445*f6aab3d8Srobert   m_root_node = m_tree->GetChildMemberWithName(g_begin_node_, true).get();
446061da546Spatrick   return false;
447061da546Spatrick }
448061da546Spatrick 
449061da546Spatrick bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
MightHaveChildren()450061da546Spatrick     MightHaveChildren() {
451061da546Spatrick   return true;
452061da546Spatrick }
453061da546Spatrick 
454061da546Spatrick size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)455061da546Spatrick     GetIndexOfChildWithName(ConstString name) {
456061da546Spatrick   return ExtractIndexFromString(name.GetCString());
457061da546Spatrick }
458061da546Spatrick 
459061da546Spatrick SyntheticChildrenFrontEnd *
LibcxxStdMapSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)460061da546Spatrick lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator(
461061da546Spatrick     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
462061da546Spatrick   return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr);
463061da546Spatrick }
464