1 //===-- VectorType.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 "lldb/DataFormatters/VectorType.h"
10 
11 #include "lldb/Core/ValueObject.h"
12 #include "lldb/DataFormatters/FormattersHelpers.h"
13 #include "lldb/Symbol/CompilerType.h"
14 #include "lldb/Symbol/TypeSystem.h"
15 #include "lldb/Target/Target.h"
16 
17 #include "lldb/Utility/LLDBAssert.h"
18 #include "lldb/Utility/Log.h"
19 #include <optional>
20 
21 using namespace lldb;
22 using namespace lldb_private;
23 using namespace lldb_private::formatters;
24 
GetCompilerTypeForFormat(lldb::Format format,CompilerType element_type,TypeSystemSP type_system)25 static CompilerType GetCompilerTypeForFormat(lldb::Format format,
26                                              CompilerType element_type,
27                                              TypeSystemSP type_system) {
28   lldbassert(type_system && "type_system needs to be not NULL");
29   if (!type_system)
30     return {};
31 
32   switch (format) {
33   case lldb::eFormatAddressInfo:
34   case lldb::eFormatPointer:
35     return type_system->GetBuiltinTypeForEncodingAndBitSize(
36         eEncodingUint, 8 * type_system->GetPointerByteSize());
37 
38   case lldb::eFormatBoolean:
39     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeBool);
40 
41   case lldb::eFormatBytes:
42   case lldb::eFormatBytesWithASCII:
43   case lldb::eFormatChar:
44   case lldb::eFormatCharArray:
45   case lldb::eFormatCharPrintable:
46     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar);
47 
48   case lldb::eFormatComplex /* lldb::eFormatComplexFloat */:
49     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloatComplex);
50 
51   case lldb::eFormatCString:
52     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar)
53         .GetPointerType();
54 
55   case lldb::eFormatFloat:
56     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat);
57 
58   case lldb::eFormatHex:
59   case lldb::eFormatHexUppercase:
60   case lldb::eFormatOctal:
61     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeInt);
62 
63   case lldb::eFormatHexFloat:
64     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeFloat);
65 
66   case lldb::eFormatUnicode16:
67   case lldb::eFormatUnicode32:
68 
69   case lldb::eFormatUnsigned:
70     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt);
71 
72   case lldb::eFormatVectorOfChar:
73     return type_system->GetBasicTypeFromAST(lldb::eBasicTypeChar);
74 
75   case lldb::eFormatVectorOfFloat32:
76     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754,
77                                                             32);
78 
79   case lldb::eFormatVectorOfFloat64:
80     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingIEEE754,
81                                                             64);
82 
83   case lldb::eFormatVectorOfSInt16:
84     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 16);
85 
86   case lldb::eFormatVectorOfSInt32:
87     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32);
88 
89   case lldb::eFormatVectorOfSInt64:
90     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64);
91 
92   case lldb::eFormatVectorOfSInt8:
93     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 8);
94 
95   case lldb::eFormatVectorOfUInt128:
96     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 128);
97 
98   case lldb::eFormatVectorOfUInt16:
99     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16);
100 
101   case lldb::eFormatVectorOfUInt32:
102     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
103 
104   case lldb::eFormatVectorOfUInt64:
105     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64);
106 
107   case lldb::eFormatVectorOfUInt8:
108     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8);
109 
110   case lldb::eFormatDefault:
111     return element_type;
112 
113   case lldb::eFormatBinary:
114   case lldb::eFormatComplexInteger:
115   case lldb::eFormatDecimal:
116   case lldb::eFormatEnum:
117   case lldb::eFormatInstruction:
118   case lldb::eFormatOSType:
119   case lldb::eFormatVoid:
120   default:
121     return type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8);
122   }
123 }
124 
GetItemFormatForFormat(lldb::Format format,CompilerType element_type)125 static lldb::Format GetItemFormatForFormat(lldb::Format format,
126                                            CompilerType element_type) {
127   switch (format) {
128   case lldb::eFormatVectorOfChar:
129     return lldb::eFormatChar;
130 
131   case lldb::eFormatVectorOfFloat32:
132   case lldb::eFormatVectorOfFloat64:
133     return lldb::eFormatFloat;
134 
135   case lldb::eFormatVectorOfSInt16:
136   case lldb::eFormatVectorOfSInt32:
137   case lldb::eFormatVectorOfSInt64:
138   case lldb::eFormatVectorOfSInt8:
139     return lldb::eFormatDecimal;
140 
141   case lldb::eFormatVectorOfUInt128:
142   case lldb::eFormatVectorOfUInt16:
143   case lldb::eFormatVectorOfUInt32:
144   case lldb::eFormatVectorOfUInt64:
145   case lldb::eFormatVectorOfUInt8:
146     return lldb::eFormatUnsigned;
147 
148   case lldb::eFormatBinary:
149   case lldb::eFormatComplexInteger:
150   case lldb::eFormatDecimal:
151   case lldb::eFormatEnum:
152   case lldb::eFormatInstruction:
153   case lldb::eFormatOSType:
154   case lldb::eFormatVoid:
155     return eFormatHex;
156 
157   case lldb::eFormatDefault: {
158     // special case the (default, char) combination to actually display as an
159     // integer value most often, you won't want to see the ASCII characters...
160     // (and if you do, eFormatChar is a keystroke away)
161     bool is_char = element_type.IsCharType();
162     bool is_signed = false;
163     element_type.IsIntegerType(is_signed);
164     return is_char ? (is_signed ? lldb::eFormatDecimal : eFormatHex) : format;
165   } break;
166 
167   default:
168     return format;
169   }
170 }
171 
172 /// Calculates the number of elements stored in a container (with
173 /// element type 'container_elem_type') as if it had elements of type
174 /// 'element_type'.
175 ///
176 /// For example, a container of type
177 /// `uint8_t __attribute__((vector_size(16)))` has 16 elements.
178 /// But calling `CalculateNumChildren` with an 'element_type'
179 /// of `float` (4-bytes) will return `4` because we are interpreting
180 /// the byte-array as a `float32[]`.
181 ///
182 /// \param[in] container_elem_type The type of the elements stored
183 /// in the container we are calculating the children of.
184 ///
185 /// \param[in] num_elements Number of 'container_elem_type's our
186 /// container stores.
187 ///
188 /// \param[in] element_type The type of elements we interpret
189 /// container_type to contain for the purposes of calculating
190 /// the number of children.
191 ///
192 /// \returns The number of elements stored in a container of
193 /// type 'element_type'. Returns a std::nullopt if the
194 /// size of the container is not a multiple of 'element_type'
195 /// or if an error occurs.
196 static std::optional<size_t>
CalculateNumChildren(CompilerType container_elem_type,uint64_t num_elements,CompilerType element_type)197 CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements,
198                      CompilerType element_type) {
199   std::optional<uint64_t> container_elem_size =
200       container_elem_type.GetByteSize(/* exe_scope */ nullptr);
201   if (!container_elem_size)
202     return {};
203 
204   auto container_size = *container_elem_size * num_elements;
205 
206   std::optional<uint64_t> element_size =
207       element_type.GetByteSize(/* exe_scope */ nullptr);
208   if (!element_size || !*element_size)
209     return {};
210 
211   if (container_size % *element_size)
212     return {};
213 
214   return container_size / *element_size;
215 }
216 
217 namespace lldb_private {
218 namespace formatters {
219 
220 class VectorTypeSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
221 public:
VectorTypeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)222   VectorTypeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
223       : SyntheticChildrenFrontEnd(*valobj_sp), m_child_type() {}
224 
225   ~VectorTypeSyntheticFrontEnd() override = default;
226 
CalculateNumChildren()227   size_t CalculateNumChildren() override { return m_num_children; }
228 
GetChildAtIndex(size_t idx)229   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
230     if (idx >= CalculateNumChildren())
231       return {};
232     std::optional<uint64_t> size = m_child_type.GetByteSize(nullptr);
233     if (!size)
234       return {};
235     auto offset = idx * *size;
236     StreamString idx_name;
237     idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
238     ValueObjectSP child_sp(m_backend.GetSyntheticChildAtOffset(
239         offset, m_child_type, true, ConstString(idx_name.GetString())));
240     if (!child_sp)
241       return child_sp;
242 
243     child_sp->SetFormat(m_item_format);
244 
245     return child_sp;
246   }
247 
Update()248   bool Update() override {
249     m_parent_format = m_backend.GetFormat();
250     CompilerType parent_type(m_backend.GetCompilerType());
251     CompilerType element_type;
252     uint64_t num_elements;
253     parent_type.IsVectorType(&element_type, &num_elements);
254     m_child_type = ::GetCompilerTypeForFormat(
255         m_parent_format, element_type,
256         parent_type.GetTypeSystem().GetSharedPointer());
257     m_num_children =
258         ::CalculateNumChildren(element_type, num_elements, m_child_type)
259             .value_or(0);
260     m_item_format = GetItemFormatForFormat(m_parent_format, m_child_type);
261     return false;
262   }
263 
MightHaveChildren()264   bool MightHaveChildren() override { return true; }
265 
GetIndexOfChildWithName(ConstString name)266   size_t GetIndexOfChildWithName(ConstString name) override {
267     const char *item_name = name.GetCString();
268     uint32_t idx = ExtractIndexFromString(item_name);
269     if (idx < UINT32_MAX && idx >= CalculateNumChildren())
270       return UINT32_MAX;
271     return idx;
272   }
273 
274 private:
275   lldb::Format m_parent_format = eFormatInvalid;
276   lldb::Format m_item_format = eFormatInvalid;
277   CompilerType m_child_type;
278   size_t m_num_children = 0;
279 };
280 
281 } // namespace formatters
282 } // namespace lldb_private
283 
VectorTypeSummaryProvider(ValueObject & valobj,Stream & s,const TypeSummaryOptions &)284 bool lldb_private::formatters::VectorTypeSummaryProvider(
285     ValueObject &valobj, Stream &s, const TypeSummaryOptions &) {
286   auto synthetic_children =
287       VectorTypeSyntheticFrontEndCreator(nullptr, valobj.GetSP());
288   if (!synthetic_children)
289     return false;
290 
291   synthetic_children->Update();
292 
293   s.PutChar('(');
294   bool first = true;
295 
296   size_t idx = 0, len = synthetic_children->CalculateNumChildren();
297 
298   for (; idx < len; idx++) {
299     auto child_sp = synthetic_children->GetChildAtIndex(idx);
300     if (!child_sp)
301       continue;
302     child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
303         lldb::eDynamicDontRunTarget, true);
304 
305     const char *child_value = child_sp->GetValueAsCString();
306     if (child_value && *child_value) {
307       if (first) {
308         s.Printf("%s", child_value);
309         first = false;
310       } else {
311         s.Printf(", %s", child_value);
312       }
313     }
314   }
315 
316   s.PutChar(')');
317 
318   return true;
319 }
320 
321 lldb_private::SyntheticChildrenFrontEnd *
VectorTypeSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)322 lldb_private::formatters::VectorTypeSyntheticFrontEndCreator(
323     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
324   if (!valobj_sp)
325     return nullptr;
326   return new VectorTypeSyntheticFrontEnd(valobj_sp);
327 }
328