1 //===-- LibCxxSpan.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/Core/ValueObject.h"
12 #include "lldb/DataFormatters/FormattersHelpers.h"
13 #include "lldb/Utility/ConstString.h"
14 #include "llvm/ADT/APSInt.h"
15 #include <optional>
16
17 using namespace lldb;
18 using namespace lldb_private;
19 using namespace lldb_private::formatters;
20
21 namespace lldb_private {
22 namespace formatters {
23
24 class LibcxxStdSpanSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
25 public:
26 LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
27
28 ~LibcxxStdSpanSyntheticFrontEnd() override = default;
29
30 size_t CalculateNumChildren() override;
31
32 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
33
34 /// Determines properties of the std::span<> associated with this object
35 //
36 // std::span can either be instantiated with a compile-time known
37 // extent or a std::dynamic_extent (this is the default if only the
38 // type template argument is provided). The layout of std::span
39 // depends on whether the extent is dynamic or not. For static
40 // extents (e.g., std::span<int, 9>):
41 //
42 // (std::__1::span<const int, 9>) s = {
43 // __data = 0x000000016fdff494
44 // }
45 //
46 // For dynamic extents, e.g., std::span<int>, the layout is:
47 //
48 // (std::__1::span<const int, 18446744073709551615>) s = {
49 // __data = 0x000000016fdff494
50 // __size = 6
51 // }
52 //
53 // This function checks for a '__size' member to determine the number
54 // of elements in the span. If no such member exists, we get the size
55 // from the only other place it can be: the template argument.
56 bool Update() override;
57
58 bool MightHaveChildren() override;
59
60 size_t GetIndexOfChildWithName(ConstString name) override;
61
62 private:
63 ValueObject *m_start = nullptr; ///< First element of span. Held, not owned.
64 CompilerType m_element_type{}; ///< Type of span elements.
65 size_t m_num_elements = 0; ///< Number of elements in span.
66 uint32_t m_element_size = 0; ///< Size in bytes of each span element.
67 };
68
69 lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)70 LibcxxStdSpanSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
71 : SyntheticChildrenFrontEnd(*valobj_sp) {
72 if (valobj_sp)
73 Update();
74 }
75
76 size_t lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
CalculateNumChildren()77 CalculateNumChildren() {
78 return m_num_elements;
79 }
80
81 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)82 lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex(
83 size_t idx) {
84 if (!m_start)
85 return {};
86
87 uint64_t offset = idx * m_element_size;
88 offset = offset + m_start->GetValueAsUnsigned(0);
89 StreamString name;
90 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
91 return CreateValueObjectFromAddress(name.GetString(), offset,
92 m_backend.GetExecutionContextRef(),
93 m_element_type);
94 }
95
Update()96 bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() {
97 // Get element type.
98 ValueObjectSP data_type_finder_sp = GetChildMemberWithName(
99 m_backend, {ConstString("__data_"), ConstString("__data")});
100 if (!data_type_finder_sp)
101 return false;
102
103 m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
104
105 // Get element size.
106 if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
107 m_element_size = *size;
108
109 // Get data.
110 if (m_element_size > 0) {
111 m_start = data_type_finder_sp.get();
112 }
113
114 // Get number of elements.
115 if (auto size_sp = GetChildMemberWithName(
116 m_backend, {ConstString("__size_"), ConstString("__size")})) {
117 m_num_elements = size_sp->GetValueAsUnsigned(0);
118 } else if (auto arg =
119 m_backend.GetCompilerType().GetIntegralTemplateArgument(1)) {
120
121 m_num_elements = arg->value.getLimitedValue();
122 }
123 }
124
125 return true;
126 }
127
128 bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
MightHaveChildren()129 MightHaveChildren() {
130 return true;
131 }
132
133 size_t lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)134 GetIndexOfChildWithName(ConstString name) {
135 if (!m_start)
136 return UINT32_MAX;
137 return ExtractIndexFromString(name.GetCString());
138 }
139
140 lldb_private::SyntheticChildrenFrontEnd *
LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)141 LibcxxStdSpanSyntheticFrontEndCreator(CXXSyntheticChildren *,
142 lldb::ValueObjectSP valobj_sp) {
143 if (!valobj_sp)
144 return nullptr;
145 CompilerType type = valobj_sp->GetCompilerType();
146 if (!type.IsValid() || type.GetNumTemplateArguments() != 2)
147 return nullptr;
148 return new LibcxxStdSpanSyntheticFrontEnd(valobj_sp);
149 }
150
151 } // namespace formatters
152 } // namespace lldb_private
153