xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp (revision b852fb1ec5fa15f0b913cc4988cbd09239b19904)
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