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