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