1//===-- LibCxxSliceArray.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
15using namespace lldb;
16using namespace lldb_private;
17using namespace lldb_private::formatters;
18
19namespace lldb_private {
20namespace formatters {
21
22bool LibcxxStdSliceArraySummaryProvider(ValueObject &valobj, Stream &stream,
23 const TypeSummaryOptions &options) {
24 ValueObjectSP obj = valobj.GetNonSyntheticValue();
25 if (!obj)
26 return false;
27
28 ValueObjectSP ptr_sp = obj->GetChildMemberWithName(name: "__size_");
29 if (!ptr_sp)
30 return false;
31 const size_t size = ptr_sp->GetValueAsUnsigned(fail_value: 0);
32
33 ptr_sp = obj->GetChildMemberWithName(name: "__stride_");
34 if (!ptr_sp)
35 return false;
36 const size_t stride = ptr_sp->GetValueAsUnsigned(fail_value: 0);
37
38 stream.Printf(format: "stride=%zu size=%zu", stride, size);
39
40 return true;
41}
42
43/// Data formatter for libc++'s std::slice_array.
44///
45/// A slice_array is created by using:
46/// operator[](std::slice slicearr);
47/// and std::slice is created by:
48/// slice(std::size_t start, std::size_t size, std::size_t stride);
49/// The std::slice_array has the following members:
50/// - __vp_ points to std::valarray::__begin_ + @a start
51/// - __size_ is @a size
52/// - __stride_is @a stride
53class LibcxxStdSliceArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
54public:
55 LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
56
57 ~LibcxxStdSliceArraySyntheticFrontEnd() override;
58
59 llvm::Expected<uint32_t> CalculateNumChildren() override;
60
61 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
62
63 lldb::ChildCacheState Update() override;
64
65 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
66
67private:
68 /// A non-owning pointer to slice_array.__vp_.
69 ValueObject *m_start = nullptr;
70 /// slice_array.__size_.
71 size_t m_size = 0;
72 /// slice_array.__stride_.
73 size_t m_stride = 0;
74 /// The type of slice_array's template argument T.
75 CompilerType m_element_type;
76 /// The sizeof slice_array's template argument T.
77 uint32_t m_element_size = 0;
78};
79
80} // namespace formatters
81} // namespace lldb_private
82
83lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
84 LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
85 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
86 if (valobj_sp)
87 Update();
88}
89
90lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
91 ~LibcxxStdSliceArraySyntheticFrontEnd() {
92 // these need to stay around because they are child objects who will follow
93 // their parent's life cycle
94 // delete m_start;
95}
96
97llvm::Expected<uint32_t> lldb_private::formatters::
98 LibcxxStdSliceArraySyntheticFrontEnd::CalculateNumChildren() {
99 return m_size;
100}
101
102lldb::ValueObjectSP
103lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::GetChildAtIndex(
104 uint32_t idx) {
105 if (!m_start)
106 return lldb::ValueObjectSP();
107
108 uint64_t offset = idx * m_stride * m_element_size;
109 offset = offset + m_start->GetValueAsUnsigned(fail_value: 0);
110 StreamString name;
111 name.Printf(format: "[%" PRIu64 "]", (uint64_t)idx);
112 return CreateValueObjectFromAddress(name: name.GetString(), address: offset,
113 exe_ctx: m_backend.GetExecutionContextRef(),
114 type: m_element_type);
115}
116
117lldb::ChildCacheState
118lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::Update() {
119 m_start = nullptr;
120
121 CompilerType type = m_backend.GetCompilerType();
122 if (type.GetNumTemplateArguments() == 0)
123 return ChildCacheState::eRefetch;
124
125 m_element_type = type.GetTypeTemplateArgument(idx: 0);
126 if (std::optional<uint64_t> size =
127 llvm::expectedToOptional(E: m_element_type.GetByteSize(exe_scope: nullptr)))
128 m_element_size = *size;
129
130 if (m_element_size == 0)
131 return ChildCacheState::eRefetch;
132
133 ValueObjectSP start = m_backend.GetChildMemberWithName(name: "__vp_");
134 ValueObjectSP size = m_backend.GetChildMemberWithName(name: "__size_");
135 ValueObjectSP stride = m_backend.GetChildMemberWithName(name: "__stride_");
136
137 if (!start || !size || !stride)
138 return ChildCacheState::eRefetch;
139
140 m_start = start.get();
141 m_size = size->GetValueAsUnsigned(fail_value: 0);
142 m_stride = stride->GetValueAsUnsigned(fail_value: 0);
143
144 return ChildCacheState::eRefetch;
145}
146
147llvm::Expected<size_t>
148lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::
149 GetIndexOfChildWithName(ConstString name) {
150 if (!m_start)
151 return llvm::createStringError(Fmt: "Type has no child named '%s'",
152 Vals: name.AsCString());
153 auto optional_idx = formatters::ExtractIndexFromString(item_name: name.GetCString());
154 if (!optional_idx) {
155 return llvm::createStringError(Fmt: "Type has no child named '%s'",
156 Vals: name.AsCString());
157 }
158 return *optional_idx;
159}
160
161lldb_private::SyntheticChildrenFrontEnd *
162lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator(
163 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
164 if (!valobj_sp)
165 return nullptr;
166 return new LibcxxStdSliceArraySyntheticFrontEnd(valobj_sp);
167}
168

source code of lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp