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