1a3488755SMark de Wever //===-- LibCxxProxyArray.cpp-----------------------------------------------===// 2a3488755SMark de Wever // 3a3488755SMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a3488755SMark de Wever // See https://llvm.org/LICENSE.txt for license information. 5a3488755SMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a3488755SMark de Wever // 7a3488755SMark de Wever //===----------------------------------------------------------------------===// 8a3488755SMark de Wever 9a3488755SMark de Wever #include "LibCxx.h" 10a3488755SMark de Wever 11a3488755SMark de Wever #include "lldb/DataFormatters/FormattersHelpers.h" 12*b852fb1eSJonas Devlieghere #include "lldb/ValueObject/ValueObject.h" 13a3488755SMark de Wever #include <optional> 14a3488755SMark de Wever 15a3488755SMark de Wever using namespace lldb; 16a3488755SMark de Wever using namespace lldb_private; 17a3488755SMark de Wever using namespace lldb_private::formatters; 18a3488755SMark de Wever 19a3488755SMark de Wever namespace lldb_private { 20a3488755SMark de Wever namespace formatters { 21a3488755SMark de Wever 22a3488755SMark de Wever /// Data formatter for libc++'s std::"proxy_array". 23a3488755SMark de Wever /// 24a3488755SMark de Wever /// A proxy_array's are created by using: 25a3488755SMark de Wever /// std::gslice_array operator[](const std::gslice& gslicearr); 26a3488755SMark de Wever /// std::mask_array operator[](const std::valarray<bool>& boolarr); 27a3488755SMark de Wever /// std::indirect_array operator[](const std::valarray<std::size_t>& indarr); 28a3488755SMark de Wever /// 29a3488755SMark de Wever /// These arrays have the following members: 30a3488755SMark de Wever /// - __vp_ points to std::valarray::__begin_ 31a3488755SMark de Wever /// - __1d_ an array of offsets of the elements from @a __vp_ 32a3488755SMark de Wever class LibcxxStdProxyArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { 33a3488755SMark de Wever public: 34a3488755SMark de Wever LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 35a3488755SMark de Wever 36a3488755SMark de Wever ~LibcxxStdProxyArraySyntheticFrontEnd() override; 37a3488755SMark de Wever 38a3488755SMark de Wever llvm::Expected<uint32_t> CalculateNumChildren() override; 39a3488755SMark de Wever 40a3488755SMark de Wever lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; 41a3488755SMark de Wever 42a3488755SMark de Wever lldb::ChildCacheState Update() override; 43a3488755SMark de Wever 44a3488755SMark de Wever bool MightHaveChildren() override; 45a3488755SMark de Wever 46a3488755SMark de Wever size_t GetIndexOfChildWithName(ConstString name) override; 47a3488755SMark de Wever 48a3488755SMark de Wever private: 49a3488755SMark de Wever /// A non-owning pointer to the array's __vp_. 50a3488755SMark de Wever ValueObject *m_base = nullptr; 51a3488755SMark de Wever /// The type of the array's template argument T. 52a3488755SMark de Wever CompilerType m_element_type; 53a3488755SMark de Wever /// The sizeof the array's template argument T. 54a3488755SMark de Wever uint32_t m_element_size = 0; 55a3488755SMark de Wever 56a3488755SMark de Wever /// A non-owning pointer to the array's __1d_.__begin_. 57a3488755SMark de Wever ValueObject *m_start = nullptr; 58a3488755SMark de Wever /// A non-owning pointer to the array's __1d_.__end_. 59a3488755SMark de Wever ValueObject *m_finish = nullptr; 60a3488755SMark de Wever /// The type of the __1d_ array's template argument T (size_t). 61a3488755SMark de Wever CompilerType m_element_type_size_t; 62a3488755SMark de Wever /// The sizeof the __1d_ array's template argument T (size_t) 63a3488755SMark de Wever uint32_t m_element_size_size_t = 0; 64a3488755SMark de Wever }; 65a3488755SMark de Wever 66a3488755SMark de Wever } // namespace formatters 67a3488755SMark de Wever } // namespace lldb_private 68a3488755SMark de Wever 69a3488755SMark de Wever lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: 70a3488755SMark de Wever LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 71a3488755SMark de Wever : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { 72a3488755SMark de Wever if (valobj_sp) 73a3488755SMark de Wever Update(); 74a3488755SMark de Wever } 75a3488755SMark de Wever 76a3488755SMark de Wever lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: 77a3488755SMark de Wever ~LibcxxStdProxyArraySyntheticFrontEnd() { 78a3488755SMark de Wever // these need to stay around because they are child objects who will follow 79a3488755SMark de Wever // their parent's life cycle 80a3488755SMark de Wever // delete m_base; 81a3488755SMark de Wever } 82a3488755SMark de Wever 83a3488755SMark de Wever llvm::Expected<uint32_t> lldb_private::formatters:: 84a3488755SMark de Wever LibcxxStdProxyArraySyntheticFrontEnd::CalculateNumChildren() { 85a3488755SMark de Wever 86a3488755SMark de Wever if (!m_start || !m_finish) 87a3488755SMark de Wever return 0; 88a3488755SMark de Wever uint64_t start_val = m_start->GetValueAsUnsigned(0); 89a3488755SMark de Wever uint64_t finish_val = m_finish->GetValueAsUnsigned(0); 90a3488755SMark de Wever 91a3488755SMark de Wever if (start_val == 0 || finish_val == 0) 92a3488755SMark de Wever return 0; 93a3488755SMark de Wever 94a3488755SMark de Wever if (start_val >= finish_val) 95a3488755SMark de Wever return 0; 96a3488755SMark de Wever 97a3488755SMark de Wever size_t num_children = (finish_val - start_val); 98a3488755SMark de Wever if (num_children % m_element_size_size_t) 99a3488755SMark de Wever return 0; 100a3488755SMark de Wever return num_children / m_element_size_size_t; 101a3488755SMark de Wever } 102a3488755SMark de Wever 103a3488755SMark de Wever lldb::ValueObjectSP 104a3488755SMark de Wever lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex( 105a3488755SMark de Wever uint32_t idx) { 106a3488755SMark de Wever if (!m_base) 107a3488755SMark de Wever return lldb::ValueObjectSP(); 108a3488755SMark de Wever 109a3488755SMark de Wever uint64_t offset = idx * m_element_size_size_t; 110a3488755SMark de Wever offset = offset + m_start->GetValueAsUnsigned(0); 111a3488755SMark de Wever 112a3488755SMark de Wever lldb::ValueObjectSP indirect = CreateValueObjectFromAddress( 113a3488755SMark de Wever "", offset, m_backend.GetExecutionContextRef(), m_element_type_size_t); 114a3488755SMark de Wever if (!indirect) 115a3488755SMark de Wever return lldb::ValueObjectSP(); 116a3488755SMark de Wever 117a3488755SMark de Wever const size_t value = indirect->GetValueAsUnsigned(0); 118a3488755SMark de Wever if (!value) 119a3488755SMark de Wever return lldb::ValueObjectSP(); 120a3488755SMark de Wever 121a3488755SMark de Wever offset = value * m_element_size; 122a3488755SMark de Wever offset = offset + m_base->GetValueAsUnsigned(0); 123a3488755SMark de Wever 124a3488755SMark de Wever StreamString name; 125a3488755SMark de Wever name.Printf("[%" PRIu64 "] -> [%zu]", (uint64_t)idx, value); 126a3488755SMark de Wever return CreateValueObjectFromAddress(name.GetString(), offset, 127a3488755SMark de Wever m_backend.GetExecutionContextRef(), 128a3488755SMark de Wever m_element_type); 129a3488755SMark de Wever } 130a3488755SMark de Wever 131a3488755SMark de Wever lldb::ChildCacheState 132a3488755SMark de Wever lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::Update() { 133a3488755SMark de Wever m_base = nullptr; 134a3488755SMark de Wever m_start = nullptr; 135a3488755SMark de Wever m_finish = nullptr; 136a3488755SMark de Wever 137a3488755SMark de Wever CompilerType type = m_backend.GetCompilerType(); 138a3488755SMark de Wever if (type.GetNumTemplateArguments() == 0) 139a3488755SMark de Wever return ChildCacheState::eRefetch; 140a3488755SMark de Wever 141a3488755SMark de Wever m_element_type = type.GetTypeTemplateArgument(0); 142a3488755SMark de Wever if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) 143a3488755SMark de Wever m_element_size = *size; 144a3488755SMark de Wever 145a3488755SMark de Wever if (m_element_size == 0) 146a3488755SMark de Wever return ChildCacheState::eRefetch; 147a3488755SMark de Wever 148a3488755SMark de Wever ValueObjectSP vector = m_backend.GetChildMemberWithName("__1d_"); 149a3488755SMark de Wever if (!vector) 150a3488755SMark de Wever return ChildCacheState::eRefetch; 151a3488755SMark de Wever 152a3488755SMark de Wever type = vector->GetCompilerType(); 153a3488755SMark de Wever if (type.GetNumTemplateArguments() == 0) 154a3488755SMark de Wever return ChildCacheState::eRefetch; 155a3488755SMark de Wever 156a3488755SMark de Wever m_element_type_size_t = type.GetTypeTemplateArgument(0); 157a3488755SMark de Wever if (std::optional<uint64_t> size = m_element_type_size_t.GetByteSize(nullptr)) 158a3488755SMark de Wever m_element_size_size_t = *size; 159a3488755SMark de Wever 160a3488755SMark de Wever if (m_element_size_size_t == 0) 161a3488755SMark de Wever return ChildCacheState::eRefetch; 162a3488755SMark de Wever 163a3488755SMark de Wever ValueObjectSP base = m_backend.GetChildMemberWithName("__vp_"); 164a3488755SMark de Wever ValueObjectSP start = vector->GetChildMemberWithName("__begin_"); 165a3488755SMark de Wever ValueObjectSP finish = vector->GetChildMemberWithName("__end_"); 166a3488755SMark de Wever if (!base || !start || !finish) 167a3488755SMark de Wever return ChildCacheState::eRefetch; 168a3488755SMark de Wever 169a3488755SMark de Wever m_base = base.get(); 170a3488755SMark de Wever m_start = start.get(); 171a3488755SMark de Wever m_finish = finish.get(); 172a3488755SMark de Wever 173a3488755SMark de Wever return ChildCacheState::eRefetch; 174a3488755SMark de Wever } 175a3488755SMark de Wever 176a3488755SMark de Wever bool lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: 177a3488755SMark de Wever MightHaveChildren() { 178a3488755SMark de Wever return true; 179a3488755SMark de Wever } 180a3488755SMark de Wever 181a3488755SMark de Wever size_t lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: 182a3488755SMark de Wever GetIndexOfChildWithName(ConstString name) { 183a3488755SMark de Wever if (!m_base) 184a3488755SMark de Wever return std::numeric_limits<size_t>::max(); 185a3488755SMark de Wever return ExtractIndexFromString(name.GetCString()); 186a3488755SMark de Wever } 187a3488755SMark de Wever 188a3488755SMark de Wever lldb_private::SyntheticChildrenFrontEnd * 189a3488755SMark de Wever lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator( 190a3488755SMark de Wever CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 191a3488755SMark de Wever if (!valobj_sp) 192a3488755SMark de Wever return nullptr; 193a3488755SMark de Wever return new LibcxxStdProxyArraySyntheticFrontEnd(valobj_sp); 194a3488755SMark de Wever } 195