1 //===-- LibCxxValarray.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 class LibcxxStdValarraySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
22 public:
23 LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
24
25 ~LibcxxStdValarraySyntheticFrontEnd() override;
26
27 llvm::Expected<uint32_t> CalculateNumChildren() override;
28
29 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
30
31 lldb::ChildCacheState Update() override;
32
33 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
34
35 private:
36 /// A non-owning pointer to valarray's __begin_ member.
37 ValueObject *m_start = nullptr;
38 /// A non-owning pointer to valarray's __end_ member.
39 ValueObject *m_finish = nullptr;
40 /// The type of valarray's template argument T.
41 CompilerType m_element_type;
42 /// The sizeof valarray's template argument T.
43 uint32_t m_element_size = 0;
44 };
45
46 } // namespace formatters
47 } // namespace lldb_private
48
49 lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)50 LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
51 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
52 if (valobj_sp)
53 Update();
54 }
55
56 lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
~LibcxxStdValarraySyntheticFrontEnd()57 ~LibcxxStdValarraySyntheticFrontEnd() {
58 // these need to stay around because they are child objects who will follow
59 // their parent's life cycle
60 // delete m_start;
61 // delete m_finish;
62 }
63
64 llvm::Expected<uint32_t> lldb_private::formatters::
CalculateNumChildren()65 LibcxxStdValarraySyntheticFrontEnd::CalculateNumChildren() {
66 if (!m_start || !m_finish)
67 return 0;
68 uint64_t start_val = m_start->GetValueAsUnsigned(0);
69 uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
70
71 if (start_val == 0 || finish_val == 0)
72 return 0;
73
74 if (start_val >= finish_val)
75 return 0;
76
77 size_t num_children = (finish_val - start_val);
78 if (num_children % m_element_size)
79 return 0;
80 return num_children / m_element_size;
81 }
82
83 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx)84 lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::GetChildAtIndex(
85 uint32_t idx) {
86 if (!m_start || !m_finish)
87 return lldb::ValueObjectSP();
88
89 uint64_t offset = idx * m_element_size;
90 offset = offset + m_start->GetValueAsUnsigned(0);
91 StreamString name;
92 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
93 return CreateValueObjectFromAddress(name.GetString(), offset,
94 m_backend.GetExecutionContextRef(),
95 m_element_type);
96 }
97
98 lldb::ChildCacheState
Update()99 lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::Update() {
100 m_start = m_finish = nullptr;
101
102 CompilerType type = m_backend.GetCompilerType();
103 if (type.GetNumTemplateArguments() == 0)
104 return ChildCacheState::eRefetch;
105
106 m_element_type = type.GetTypeTemplateArgument(0);
107 if (std::optional<uint64_t> size =
108 llvm::expectedToOptional(m_element_type.GetByteSize(nullptr)))
109 m_element_size = *size;
110
111 if (m_element_size == 0)
112 return ChildCacheState::eRefetch;
113
114 ValueObjectSP start = m_backend.GetChildMemberWithName("__begin_");
115 ValueObjectSP finish = m_backend.GetChildMemberWithName("__end_");
116
117 if (!start || !finish)
118 return ChildCacheState::eRefetch;
119
120 m_start = start.get();
121 m_finish = finish.get();
122
123 return ChildCacheState::eRefetch;
124 }
125
126 llvm::Expected<size_t>
127 lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)128 GetIndexOfChildWithName(ConstString name) {
129 if (!m_start || !m_finish)
130 return llvm::createStringError("Type has no child named '%s'",
131 name.AsCString());
132 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
133 if (!optional_idx) {
134 return llvm::createStringError("Type has no child named '%s'",
135 name.AsCString());
136 }
137 return *optional_idx;
138 }
139
140 lldb_private::SyntheticChildrenFrontEnd *
LibcxxStdValarraySyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)141 lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator(
142 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
143 if (!valobj_sp)
144 return nullptr;
145 return new LibcxxStdValarraySyntheticFrontEnd(valobj_sp);
146 }
147