15ffd83dbSDimitry Andric //===-- LibCxxMap.cpp -----------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "LibCxx.h" 100b57cec5SDimitry Andric 115ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 120b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h" 130b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h" 140b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h" 150b57cec5SDimitry Andric #include "lldb/Target/Target.h" 160b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 170b57cec5SDimitry Andric #include "lldb/Utility/Endian.h" 180b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 190b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 20*0fca6ea1SDimitry Andric #include "lldb/lldb-enumerations.h" 21*0fca6ea1SDimitry Andric #include "lldb/lldb-forward.h" 22*0fca6ea1SDimitry Andric #include <cstdint> 23*0fca6ea1SDimitry Andric #include <locale> 24*0fca6ea1SDimitry Andric #include <optional> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace lldb; 270b57cec5SDimitry Andric using namespace lldb_private; 280b57cec5SDimitry Andric using namespace lldb_private::formatters; 290b57cec5SDimitry Andric 30*0fca6ea1SDimitry Andric // The flattened layout of the std::__tree_iterator::__ptr_ looks 31*0fca6ea1SDimitry Andric // as follows: 32*0fca6ea1SDimitry Andric // 33*0fca6ea1SDimitry Andric // The following shows the contiguous block of memory: 34*0fca6ea1SDimitry Andric // 35*0fca6ea1SDimitry Andric // +-----------------------------+ class __tree_end_node 36*0fca6ea1SDimitry Andric // __ptr_ | pointer __left_; | 37*0fca6ea1SDimitry Andric // +-----------------------------+ class __tree_node_base 38*0fca6ea1SDimitry Andric // | pointer __right_; | 39*0fca6ea1SDimitry Andric // | __parent_pointer __parent_; | 40*0fca6ea1SDimitry Andric // | bool __is_black_; | 41*0fca6ea1SDimitry Andric // +-----------------------------+ class __tree_node 42*0fca6ea1SDimitry Andric // | __node_value_type __value_; | <<< our key/value pair 43*0fca6ea1SDimitry Andric // +-----------------------------+ 44*0fca6ea1SDimitry Andric // 45*0fca6ea1SDimitry Andric // where __ptr_ has type __iter_pointer. 46*0fca6ea1SDimitry Andric 470b57cec5SDimitry Andric class MapEntry { 480b57cec5SDimitry Andric public: 490b57cec5SDimitry Andric MapEntry() = default; 500b57cec5SDimitry Andric explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} 510b57cec5SDimitry Andric explicit MapEntry(ValueObject *entry) 520b57cec5SDimitry Andric : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric ValueObjectSP left() const { 550b57cec5SDimitry Andric if (!m_entry_sp) 560b57cec5SDimitry Andric return m_entry_sp; 570b57cec5SDimitry Andric return m_entry_sp->GetSyntheticChildAtOffset( 580b57cec5SDimitry Andric 0, m_entry_sp->GetCompilerType(), true); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric ValueObjectSP right() const { 620b57cec5SDimitry Andric if (!m_entry_sp) 630b57cec5SDimitry Andric return m_entry_sp; 640b57cec5SDimitry Andric return m_entry_sp->GetSyntheticChildAtOffset( 650b57cec5SDimitry Andric m_entry_sp->GetProcessSP()->GetAddressByteSize(), 660b57cec5SDimitry Andric m_entry_sp->GetCompilerType(), true); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric ValueObjectSP parent() const { 700b57cec5SDimitry Andric if (!m_entry_sp) 710b57cec5SDimitry Andric return m_entry_sp; 720b57cec5SDimitry Andric return m_entry_sp->GetSyntheticChildAtOffset( 730b57cec5SDimitry Andric 2 * m_entry_sp->GetProcessSP()->GetAddressByteSize(), 740b57cec5SDimitry Andric m_entry_sp->GetCompilerType(), true); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric uint64_t value() const { 780b57cec5SDimitry Andric if (!m_entry_sp) 790b57cec5SDimitry Andric return 0; 800b57cec5SDimitry Andric return m_entry_sp->GetValueAsUnsigned(0); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric bool error() const { 840b57cec5SDimitry Andric if (!m_entry_sp) 850b57cec5SDimitry Andric return true; 860b57cec5SDimitry Andric return m_entry_sp->GetError().Fail(); 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric bool null() const { return (value() == 0); } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric ValueObjectSP GetEntry() const { return m_entry_sp; } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric bool operator==(const MapEntry &rhs) const { 960b57cec5SDimitry Andric return (rhs.m_entry_sp.get() == m_entry_sp.get()); 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric private: 1000b57cec5SDimitry Andric ValueObjectSP m_entry_sp; 1010b57cec5SDimitry Andric }; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric class MapIterator { 1040b57cec5SDimitry Andric public: 1050b57cec5SDimitry Andric MapIterator(ValueObject *entry, size_t depth = 0) 1060b57cec5SDimitry Andric : m_entry(entry), m_max_depth(depth), m_error(false) {} 1070b57cec5SDimitry Andric 108*0fca6ea1SDimitry Andric MapIterator() = default; 109480093f4SDimitry Andric 1100b57cec5SDimitry Andric ValueObjectSP value() { return m_entry.GetEntry(); } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric ValueObjectSP advance(size_t count) { 1130b57cec5SDimitry Andric ValueObjectSP fail; 1140b57cec5SDimitry Andric if (m_error) 1150b57cec5SDimitry Andric return fail; 1160b57cec5SDimitry Andric size_t steps = 0; 1170b57cec5SDimitry Andric while (count > 0) { 1180b57cec5SDimitry Andric next(); 1190b57cec5SDimitry Andric count--, steps++; 1200b57cec5SDimitry Andric if (m_error || m_entry.null() || (steps > m_max_depth)) 1210b57cec5SDimitry Andric return fail; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric return m_entry.GetEntry(); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 126*0fca6ea1SDimitry Andric private: 127*0fca6ea1SDimitry Andric /// Mimicks libc++'s __tree_next algorithm, which libc++ uses 128*0fca6ea1SDimitry Andric /// in its __tree_iteartor::operator++. 1290b57cec5SDimitry Andric void next() { 1300b57cec5SDimitry Andric if (m_entry.null()) 1310b57cec5SDimitry Andric return; 1320b57cec5SDimitry Andric MapEntry right(m_entry.right()); 1330b57cec5SDimitry Andric if (!right.null()) { 1340b57cec5SDimitry Andric m_entry = tree_min(std::move(right)); 1350b57cec5SDimitry Andric return; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric size_t steps = 0; 1380b57cec5SDimitry Andric while (!is_left_child(m_entry)) { 1390b57cec5SDimitry Andric if (m_entry.error()) { 1400b57cec5SDimitry Andric m_error = true; 1410b57cec5SDimitry Andric return; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric m_entry.SetEntry(m_entry.parent()); 1440b57cec5SDimitry Andric steps++; 1450b57cec5SDimitry Andric if (steps > m_max_depth) { 1460b57cec5SDimitry Andric m_entry = MapEntry(); 1470b57cec5SDimitry Andric return; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric m_entry = MapEntry(m_entry.parent()); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 153*0fca6ea1SDimitry Andric /// Mimicks libc++'s __tree_min algorithm. 154fe6060f1SDimitry Andric MapEntry tree_min(MapEntry x) { 1550b57cec5SDimitry Andric if (x.null()) 1560b57cec5SDimitry Andric return MapEntry(); 1570b57cec5SDimitry Andric MapEntry left(x.left()); 1580b57cec5SDimitry Andric size_t steps = 0; 1590b57cec5SDimitry Andric while (!left.null()) { 1600b57cec5SDimitry Andric if (left.error()) { 1610b57cec5SDimitry Andric m_error = true; 1620b57cec5SDimitry Andric return MapEntry(); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric x = left; 1650b57cec5SDimitry Andric left.SetEntry(x.left()); 1660b57cec5SDimitry Andric steps++; 1670b57cec5SDimitry Andric if (steps > m_max_depth) 1680b57cec5SDimitry Andric return MapEntry(); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric return x; 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric bool is_left_child(const MapEntry &x) { 1740b57cec5SDimitry Andric if (x.null()) 1750b57cec5SDimitry Andric return false; 1760b57cec5SDimitry Andric MapEntry rhs(x.parent()); 1770b57cec5SDimitry Andric rhs.SetEntry(rhs.left()); 1780b57cec5SDimitry Andric return x.value() == rhs.value(); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric MapEntry m_entry; 182fcaf7f86SDimitry Andric size_t m_max_depth = 0; 183fcaf7f86SDimitry Andric bool m_error = false; 1840b57cec5SDimitry Andric }; 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric namespace lldb_private { 1870b57cec5SDimitry Andric namespace formatters { 1880b57cec5SDimitry Andric class LibcxxStdMapSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 1890b57cec5SDimitry Andric public: 1900b57cec5SDimitry Andric LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric ~LibcxxStdMapSyntheticFrontEnd() override = default; 1930b57cec5SDimitry Andric 194*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> CalculateNumChildren() override; 1950b57cec5SDimitry Andric 196*0fca6ea1SDimitry Andric lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 1970b57cec5SDimitry Andric 198*0fca6ea1SDimitry Andric lldb::ChildCacheState Update() override; 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric bool MightHaveChildren() override; 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric size_t GetIndexOfChildWithName(ConstString name) override; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric private: 205*0fca6ea1SDimitry Andric /// Returns the ValueObject for the __tree_node type that 206*0fca6ea1SDimitry Andric /// holds the key/value pair of the node at index \ref idx. 207*0fca6ea1SDimitry Andric /// 208*0fca6ea1SDimitry Andric /// \param[in] idx The child index that we're looking to get 209*0fca6ea1SDimitry Andric /// the key/value pair for. 210*0fca6ea1SDimitry Andric /// 211*0fca6ea1SDimitry Andric /// \param[in] max_depth The maximum search depth after which 212*0fca6ea1SDimitry Andric /// we stop trying to find the key/value 213*0fca6ea1SDimitry Andric /// pair for. 214*0fca6ea1SDimitry Andric /// 215*0fca6ea1SDimitry Andric /// \returns On success, returns the ValueObjectSP corresponding 216*0fca6ea1SDimitry Andric /// to the __tree_node's __value_ member (which holds 217*0fca6ea1SDimitry Andric /// the key/value pair the formatter wants to display). 218*0fca6ea1SDimitry Andric /// On failure, will return nullptr. 219*0fca6ea1SDimitry Andric ValueObjectSP GetKeyValuePair(size_t idx, size_t max_depth); 2200b57cec5SDimitry Andric 22181ad6265SDimitry Andric ValueObject *m_tree = nullptr; 22281ad6265SDimitry Andric ValueObject *m_root_node = nullptr; 223*0fca6ea1SDimitry Andric CompilerType m_node_ptr_type; 22481ad6265SDimitry Andric size_t m_count = UINT32_MAX; 2250b57cec5SDimitry Andric std::map<size_t, MapIterator> m_iterators; 2260b57cec5SDimitry Andric }; 227*0fca6ea1SDimitry Andric 228*0fca6ea1SDimitry Andric class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 229*0fca6ea1SDimitry Andric public: 230*0fca6ea1SDimitry Andric LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 231*0fca6ea1SDimitry Andric 232*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> CalculateNumChildren() override; 233*0fca6ea1SDimitry Andric 234*0fca6ea1SDimitry Andric lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 235*0fca6ea1SDimitry Andric 236*0fca6ea1SDimitry Andric lldb::ChildCacheState Update() override; 237*0fca6ea1SDimitry Andric 238*0fca6ea1SDimitry Andric bool MightHaveChildren() override; 239*0fca6ea1SDimitry Andric 240*0fca6ea1SDimitry Andric size_t GetIndexOfChildWithName(ConstString name) override; 241*0fca6ea1SDimitry Andric 242*0fca6ea1SDimitry Andric ~LibCxxMapIteratorSyntheticFrontEnd() override = default; 243*0fca6ea1SDimitry Andric 244*0fca6ea1SDimitry Andric private: 245*0fca6ea1SDimitry Andric ValueObjectSP m_pair_sp = nullptr; 246*0fca6ea1SDimitry Andric }; 2470b57cec5SDimitry Andric } // namespace formatters 2480b57cec5SDimitry Andric } // namespace lldb_private 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: 2510b57cec5SDimitry Andric LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 252*0fca6ea1SDimitry Andric : SyntheticChildrenFrontEnd(*valobj_sp) { 2530b57cec5SDimitry Andric if (valobj_sp) 2540b57cec5SDimitry Andric Update(); 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 257*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters:: 258*0fca6ea1SDimitry Andric LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren() { 2590b57cec5SDimitry Andric if (m_count != UINT32_MAX) 2600b57cec5SDimitry Andric return m_count; 261*0fca6ea1SDimitry Andric 2620b57cec5SDimitry Andric if (m_tree == nullptr) 2630b57cec5SDimitry Andric return 0; 264*0fca6ea1SDimitry Andric 265*0fca6ea1SDimitry Andric ValueObjectSP size_node(m_tree->GetChildMemberWithName("__pair3_")); 266*0fca6ea1SDimitry Andric if (!size_node) 2670b57cec5SDimitry Andric return 0; 2680b57cec5SDimitry Andric 269*0fca6ea1SDimitry Andric size_node = GetFirstValueOfLibCXXCompressedPair(*size_node); 2700b57cec5SDimitry Andric 271*0fca6ea1SDimitry Andric if (!size_node) 2720b57cec5SDimitry Andric return 0; 273*0fca6ea1SDimitry Andric 274*0fca6ea1SDimitry Andric m_count = size_node->GetValueAsUnsigned(0); 2750b57cec5SDimitry Andric return m_count; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric 278*0fca6ea1SDimitry Andric ValueObjectSP 279*0fca6ea1SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetKeyValuePair( 280*0fca6ea1SDimitry Andric size_t idx, size_t max_depth) { 281*0fca6ea1SDimitry Andric MapIterator iterator(m_root_node, max_depth); 282*0fca6ea1SDimitry Andric 283*0fca6ea1SDimitry Andric size_t advance_by = idx; 284*0fca6ea1SDimitry Andric if (idx > 0) { 285*0fca6ea1SDimitry Andric // If we have already created the iterator for the previous 286*0fca6ea1SDimitry Andric // index, we can start from there and advance by 1. 287*0fca6ea1SDimitry Andric auto cached_iterator = m_iterators.find(idx - 1); 288*0fca6ea1SDimitry Andric if (cached_iterator != m_iterators.end()) { 289*0fca6ea1SDimitry Andric iterator = cached_iterator->second; 290*0fca6ea1SDimitry Andric advance_by = 1; 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 294*0fca6ea1SDimitry Andric ValueObjectSP iterated_sp(iterator.advance(advance_by)); 295*0fca6ea1SDimitry Andric if (!iterated_sp) 296*0fca6ea1SDimitry Andric // this tree is garbage - stop 297*0fca6ea1SDimitry Andric return nullptr; 298*0fca6ea1SDimitry Andric 299*0fca6ea1SDimitry Andric if (!m_node_ptr_type.IsValid()) 300*0fca6ea1SDimitry Andric return nullptr; 301*0fca6ea1SDimitry Andric 302*0fca6ea1SDimitry Andric // iterated_sp is a __iter_pointer at this point. 303*0fca6ea1SDimitry Andric // We can cast it to a __node_pointer (which is what libc++ does). 304*0fca6ea1SDimitry Andric auto value_type_sp = iterated_sp->Cast(m_node_ptr_type); 305*0fca6ea1SDimitry Andric if (!value_type_sp) 306*0fca6ea1SDimitry Andric return nullptr; 307*0fca6ea1SDimitry Andric 308*0fca6ea1SDimitry Andric // Finally, get the key/value pair. 309*0fca6ea1SDimitry Andric value_type_sp = value_type_sp->GetChildMemberWithName("__value_"); 310*0fca6ea1SDimitry Andric if (!value_type_sp) 311*0fca6ea1SDimitry Andric return nullptr; 312*0fca6ea1SDimitry Andric 313*0fca6ea1SDimitry Andric m_iterators[idx] = iterator; 314*0fca6ea1SDimitry Andric 315*0fca6ea1SDimitry Andric return value_type_sp; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric lldb::ValueObjectSP 3190b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex( 320*0fca6ea1SDimitry Andric uint32_t idx) { 321bdd1243dSDimitry Andric static ConstString g_cc_("__cc_"), g_cc("__cc"); 32281ad6265SDimitry Andric static ConstString g_nc("__nc"); 323*0fca6ea1SDimitry Andric uint32_t num_children = CalculateNumChildrenIgnoringErrors(); 324*0fca6ea1SDimitry Andric if (idx >= num_children) 325*0fca6ea1SDimitry Andric return nullptr; 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric if (m_tree == nullptr || m_root_node == nullptr) 328*0fca6ea1SDimitry Andric return nullptr; 3290b57cec5SDimitry Andric 330*0fca6ea1SDimitry Andric ValueObjectSP key_val_sp = GetKeyValuePair(idx, /*max_depth=*/num_children); 331*0fca6ea1SDimitry Andric if (!key_val_sp) { 332*0fca6ea1SDimitry Andric // this will stop all future searches until an Update() happens 333*0fca6ea1SDimitry Andric m_tree = nullptr; 334*0fca6ea1SDimitry Andric return nullptr; 3350b57cec5SDimitry Andric } 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // at this point we have a valid 3380b57cec5SDimitry Andric // we need to copy current_sp into a new object otherwise we will end up with 3390b57cec5SDimitry Andric // all items named __value_ 3400b57cec5SDimitry Andric StreamString name; 3410b57cec5SDimitry Andric name.Printf("[%" PRIu64 "]", (uint64_t)idx); 342*0fca6ea1SDimitry Andric auto potential_child_sp = key_val_sp->Clone(ConstString(name.GetString())); 3430b57cec5SDimitry Andric if (potential_child_sp) { 344*0fca6ea1SDimitry Andric switch (potential_child_sp->GetNumChildrenIgnoringErrors()) { 3450b57cec5SDimitry Andric case 1: { 34606c3fb27SDimitry Andric auto child0_sp = potential_child_sp->GetChildAtIndex(0); 347bdd1243dSDimitry Andric if (child0_sp && 348bdd1243dSDimitry Andric (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc)) 3490b57cec5SDimitry Andric potential_child_sp = child0_sp->Clone(ConstString(name.GetString())); 3500b57cec5SDimitry Andric break; 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric case 2: { 35306c3fb27SDimitry Andric auto child0_sp = potential_child_sp->GetChildAtIndex(0); 35406c3fb27SDimitry Andric auto child1_sp = potential_child_sp->GetChildAtIndex(1); 355bdd1243dSDimitry Andric if (child0_sp && 356bdd1243dSDimitry Andric (child0_sp->GetName() == g_cc_ || child0_sp->GetName() == g_cc) && 357bdd1243dSDimitry Andric child1_sp && child1_sp->GetName() == g_nc) 3580b57cec5SDimitry Andric potential_child_sp = child0_sp->Clone(ConstString(name.GetString())); 3590b57cec5SDimitry Andric break; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric return potential_child_sp; 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric 366*0fca6ea1SDimitry Andric lldb::ChildCacheState 367*0fca6ea1SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() { 3680b57cec5SDimitry Andric m_count = UINT32_MAX; 3690b57cec5SDimitry Andric m_tree = m_root_node = nullptr; 3700b57cec5SDimitry Andric m_iterators.clear(); 37106c3fb27SDimitry Andric m_tree = m_backend.GetChildMemberWithName("__tree_").get(); 3720b57cec5SDimitry Andric if (!m_tree) 373*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 37406c3fb27SDimitry Andric m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get(); 375*0fca6ea1SDimitry Andric m_node_ptr_type = 376*0fca6ea1SDimitry Andric m_tree->GetCompilerType().GetDirectNestedTypeWithName("__node_pointer"); 377*0fca6ea1SDimitry Andric 378*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: 3820b57cec5SDimitry Andric MightHaveChildren() { 3830b57cec5SDimitry Andric return true; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: 3870b57cec5SDimitry Andric GetIndexOfChildWithName(ConstString name) { 3880b57cec5SDimitry Andric return ExtractIndexFromString(name.GetCString()); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric SyntheticChildrenFrontEnd * 3920b57cec5SDimitry Andric lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator( 3930b57cec5SDimitry Andric CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 3940b57cec5SDimitry Andric return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr); 3950b57cec5SDimitry Andric } 396*0fca6ea1SDimitry Andric 397*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 398*0fca6ea1SDimitry Andric LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 399*0fca6ea1SDimitry Andric : SyntheticChildrenFrontEnd(*valobj_sp) { 400*0fca6ea1SDimitry Andric if (valobj_sp) 401*0fca6ea1SDimitry Andric Update(); 402*0fca6ea1SDimitry Andric } 403*0fca6ea1SDimitry Andric 404*0fca6ea1SDimitry Andric lldb::ChildCacheState 405*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { 406*0fca6ea1SDimitry Andric m_pair_sp.reset(); 407*0fca6ea1SDimitry Andric 408*0fca6ea1SDimitry Andric ValueObjectSP valobj_sp = m_backend.GetSP(); 409*0fca6ea1SDimitry Andric if (!valobj_sp) 410*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 411*0fca6ea1SDimitry Andric 412*0fca6ea1SDimitry Andric TargetSP target_sp(valobj_sp->GetTargetSP()); 413*0fca6ea1SDimitry Andric if (!target_sp) 414*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 415*0fca6ea1SDimitry Andric 416*0fca6ea1SDimitry Andric // m_backend is a std::map::iterator 417*0fca6ea1SDimitry Andric // ...which is a __map_iterator<__tree_iterator<..., __node_pointer, ...>> 418*0fca6ea1SDimitry Andric // 419*0fca6ea1SDimitry Andric // Then, __map_iterator::__i_ is a __tree_iterator 420*0fca6ea1SDimitry Andric auto tree_iter_sp = valobj_sp->GetChildMemberWithName("__i_"); 421*0fca6ea1SDimitry Andric if (!tree_iter_sp) 422*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 423*0fca6ea1SDimitry Andric 424*0fca6ea1SDimitry Andric // Type is __tree_iterator::__node_pointer 425*0fca6ea1SDimitry Andric // (We could alternatively also get this from the template argument) 426*0fca6ea1SDimitry Andric auto node_pointer_type = 427*0fca6ea1SDimitry Andric tree_iter_sp->GetCompilerType().GetDirectNestedTypeWithName( 428*0fca6ea1SDimitry Andric "__node_pointer"); 429*0fca6ea1SDimitry Andric if (!node_pointer_type.IsValid()) 430*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 431*0fca6ea1SDimitry Andric 432*0fca6ea1SDimitry Andric // __ptr_ is a __tree_iterator::__iter_pointer 433*0fca6ea1SDimitry Andric auto iter_pointer_sp = tree_iter_sp->GetChildMemberWithName("__ptr_"); 434*0fca6ea1SDimitry Andric if (!iter_pointer_sp) 435*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 436*0fca6ea1SDimitry Andric 437*0fca6ea1SDimitry Andric // Cast the __iter_pointer to a __node_pointer (which stores our key/value 438*0fca6ea1SDimitry Andric // pair) 439*0fca6ea1SDimitry Andric auto node_pointer_sp = iter_pointer_sp->Cast(node_pointer_type); 440*0fca6ea1SDimitry Andric if (!node_pointer_sp) 441*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 442*0fca6ea1SDimitry Andric 443*0fca6ea1SDimitry Andric auto key_value_sp = node_pointer_sp->GetChildMemberWithName("__value_"); 444*0fca6ea1SDimitry Andric if (!key_value_sp) 445*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric // Create the synthetic child, which is a pair where the key and value can be 448*0fca6ea1SDimitry Andric // retrieved by querying the synthetic frontend for 449*0fca6ea1SDimitry Andric // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second") 450*0fca6ea1SDimitry Andric // respectively. 451*0fca6ea1SDimitry Andric // 452*0fca6ea1SDimitry Andric // std::map stores the actual key/value pair in value_type::__cc_ (or 453*0fca6ea1SDimitry Andric // previously __cc). 454*0fca6ea1SDimitry Andric key_value_sp = key_value_sp->Clone(ConstString("pair")); 455*0fca6ea1SDimitry Andric if (key_value_sp->GetNumChildrenIgnoringErrors() == 1) { 456*0fca6ea1SDimitry Andric auto child0_sp = key_value_sp->GetChildAtIndex(0); 457*0fca6ea1SDimitry Andric if (child0_sp && 458*0fca6ea1SDimitry Andric (child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc")) 459*0fca6ea1SDimitry Andric key_value_sp = child0_sp->Clone(ConstString("pair")); 460*0fca6ea1SDimitry Andric } 461*0fca6ea1SDimitry Andric 462*0fca6ea1SDimitry Andric m_pair_sp = key_value_sp; 463*0fca6ea1SDimitry Andric 464*0fca6ea1SDimitry Andric return lldb::ChildCacheState::eRefetch; 465*0fca6ea1SDimitry Andric } 466*0fca6ea1SDimitry Andric 467*0fca6ea1SDimitry Andric llvm::Expected<uint32_t> lldb_private::formatters:: 468*0fca6ea1SDimitry Andric LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren() { 469*0fca6ea1SDimitry Andric return 2; 470*0fca6ea1SDimitry Andric } 471*0fca6ea1SDimitry Andric 472*0fca6ea1SDimitry Andric lldb::ValueObjectSP 473*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( 474*0fca6ea1SDimitry Andric uint32_t idx) { 475*0fca6ea1SDimitry Andric if (!m_pair_sp) 476*0fca6ea1SDimitry Andric return nullptr; 477*0fca6ea1SDimitry Andric 478*0fca6ea1SDimitry Andric return m_pair_sp->GetChildAtIndex(idx); 479*0fca6ea1SDimitry Andric } 480*0fca6ea1SDimitry Andric 481*0fca6ea1SDimitry Andric bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 482*0fca6ea1SDimitry Andric MightHaveChildren() { 483*0fca6ea1SDimitry Andric return true; 484*0fca6ea1SDimitry Andric } 485*0fca6ea1SDimitry Andric 486*0fca6ea1SDimitry Andric size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: 487*0fca6ea1SDimitry Andric GetIndexOfChildWithName(ConstString name) { 488*0fca6ea1SDimitry Andric if (!m_pair_sp) 489*0fca6ea1SDimitry Andric return UINT32_MAX; 490*0fca6ea1SDimitry Andric 491*0fca6ea1SDimitry Andric return m_pair_sp->GetIndexOfChildWithName(name); 492*0fca6ea1SDimitry Andric } 493*0fca6ea1SDimitry Andric 494*0fca6ea1SDimitry Andric SyntheticChildrenFrontEnd * 495*0fca6ea1SDimitry Andric lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( 496*0fca6ea1SDimitry Andric CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 497*0fca6ea1SDimitry Andric return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) 498*0fca6ea1SDimitry Andric : nullptr); 499*0fca6ea1SDimitry Andric } 500