blob: 3498c9dd23c63c75a592e6d7e90ed3e1831baccc [file] [log] [blame]
Enrico Granataf615b802013-02-15 23:38:37 +00001//===-- NSArray.cpp ---------------------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Enrico Granataf615b802013-02-15 23:38:37 +00006//
7//===----------------------------------------------------------------------===//
8
Eugene Zelenko8d15f332015-10-20 01:10:59 +00009#include "clang/AST/ASTContext.h"
10
Enrico Granata170c3952015-09-14 22:18:32 +000011#include "Cocoa.h"
Enrico Granataf615b802013-02-15 23:38:37 +000012
Kate Stoneb9c1b512016-09-06 20:57:50 +000013#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
Alex Langfordb57017102019-07-15 22:56:12 +000014
Enrico Granataf615b802013-02-15 23:38:37 +000015#include "lldb/Core/ValueObject.h"
16#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000017#include "lldb/DataFormatters/FormattersHelpers.h"
Jim Ingham151c0322015-09-15 21:13:50 +000018#include "lldb/Expression/FunctionCaller.h"
Enrico Granataf615b802013-02-15 23:38:37 +000019#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata675f49b2015-10-07 18:36:53 +000020#include "lldb/Target/Language.h"
Enrico Granataf615b802013-02-15 23:38:37 +000021#include "lldb/Target/Target.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000022#include "lldb/Utility/DataBufferHeap.h"
Zachary Turner01c32432017-02-14 19:06:07 +000023#include "lldb/Utility/Endian.h"
Zachary Turner97206d52017-05-12 04:51:55 +000024#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000025#include "lldb/Utility/Stream.h"
Enrico Granataf615b802013-02-15 23:38:37 +000026
27using namespace lldb;
28using namespace lldb_private;
29using namespace lldb_private::formatters;
30
Kate Stoneb9c1b512016-09-06 20:57:50 +000031namespace lldb_private {
32namespace formatters {
33std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
34NSArray_Additionals::GetAdditionalSummaries() {
35 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
36 return g_map;
37}
Eugene Zelenko8d15f332015-10-20 01:10:59 +000038
Kate Stoneb9c1b512016-09-06 20:57:50 +000039std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
40NSArray_Additionals::GetAdditionalSynthetics() {
41 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
42 g_map;
43 return g_map;
44}
Eugene Zelenko8d15f332015-10-20 01:10:59 +000045
Jason Molendabb934832017-08-15 21:23:14 +000046class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {
Kate Stoneb9c1b512016-09-06 20:57:50 +000047public:
Jason Molendabb934832017-08-15 21:23:14 +000048 NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);
Eugene Zelenko8d15f332015-10-20 01:10:59 +000049
Jason Molendabb934832017-08-15 21:23:14 +000050 ~NSArrayMSyntheticFrontEndBase() override = default;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000051
Kate Stoneb9c1b512016-09-06 20:57:50 +000052 size_t CalculateNumChildren() override;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000053
Kate Stoneb9c1b512016-09-06 20:57:50 +000054 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000055
Kate Stoneb9c1b512016-09-06 20:57:50 +000056 bool Update() override = 0;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000057
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 bool MightHaveChildren() override;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000059
Adrian Prantl0e4c4822019-03-06 21:22:25 +000060 size_t GetIndexOfChildWithName(ConstString name) override;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000061
Kate Stoneb9c1b512016-09-06 20:57:50 +000062protected:
63 virtual lldb::addr_t GetDataAddress() = 0;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000064
Kate Stoneb9c1b512016-09-06 20:57:50 +000065 virtual uint64_t GetUsedCount() = 0;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000066
Kate Stoneb9c1b512016-09-06 20:57:50 +000067 virtual uint64_t GetOffset() = 0;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000068
Kate Stoneb9c1b512016-09-06 20:57:50 +000069 virtual uint64_t GetSize() = 0;
Eugene Zelenko8d15f332015-10-20 01:10:59 +000070
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 ExecutionContextRef m_exe_ctx_ref;
72 uint8_t m_ptr_size;
73 CompilerType m_id_type;
74};
Eugene Zelenko8d15f332015-10-20 01:10:59 +000075
Jason Molendabb934832017-08-15 21:23:14 +000076template <typename D32, typename D64>
77class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {
Kate Stoneb9c1b512016-09-06 20:57:50 +000078public:
Jason Molendabb934832017-08-15 21:23:14 +000079 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
Eugene Zelenko8d15f332015-10-20 01:10:59 +000080
Jason Molendabb934832017-08-15 21:23:14 +000081 ~GenericNSArrayMSyntheticFrontEnd() override;
Enrico Granata936499a2016-02-29 21:06:50 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 bool Update() override;
84
85protected:
86 lldb::addr_t GetDataAddress() override;
87
88 uint64_t GetUsedCount() override;
89
90 uint64_t GetOffset() override;
91
92 uint64_t GetSize() override;
93
94private:
Jason Molendabb934832017-08-15 21:23:14 +000095 D32 *m_data_32;
96 D64 *m_data_64;
97};
98
99namespace Foundation109 {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000100 struct DataDescriptor_32 {
101 uint32_t _used;
102 uint32_t _priv1 : 2;
103 uint32_t _size : 30;
104 uint32_t _priv2 : 2;
105 uint32_t _offset : 30;
106 uint32_t _priv3;
107 uint32_t _data;
108 };
Jason Molendabb934832017-08-15 21:23:14 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 struct DataDescriptor_64 {
111 uint64_t _used;
112 uint64_t _priv1 : 2;
113 uint64_t _size : 62;
114 uint64_t _priv2 : 2;
115 uint64_t _offset : 62;
116 uint32_t _priv3;
117 uint64_t _data;
118 };
Jason Molendabb934832017-08-15 21:23:14 +0000119
120 using NSArrayMSyntheticFrontEnd =
121 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
Saleem Abdulrasoolfe3a5bf2017-08-23 17:00:14 +0000122}
Jason Molendabb934832017-08-15 21:23:14 +0000123
124namespace Foundation1010 {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 struct DataDescriptor_32 {
126 uint32_t _used;
127 uint32_t _offset;
128 uint32_t _size : 28;
129 uint64_t _priv1 : 4;
130 uint32_t _priv2;
131 uint32_t _data;
132 };
Jason Molendabb934832017-08-15 21:23:14 +0000133
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 struct DataDescriptor_64 {
135 uint64_t _used;
136 uint64_t _offset;
137 uint64_t _size : 60;
138 uint64_t _priv1 : 4;
139 uint32_t _priv2;
140 uint64_t _data;
141 };
Jason Molendabb934832017-08-15 21:23:14 +0000142
143 using NSArrayMSyntheticFrontEnd =
144 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
Saleem Abdulrasoolfe3a5bf2017-08-23 17:00:14 +0000145}
Jason Molendabb934832017-08-15 21:23:14 +0000146
147namespace Foundation1428 {
Sean Callananf40da172017-06-23 23:15:03 +0000148 struct DataDescriptor_32 {
Jason Molendabb934832017-08-15 21:23:14 +0000149 uint32_t _used;
150 uint32_t _offset;
151 uint32_t _size;
152 uint32_t _data;
Sean Callananf40da172017-06-23 23:15:03 +0000153 };
Jason Molendabb934832017-08-15 21:23:14 +0000154
Sean Callananf40da172017-06-23 23:15:03 +0000155 struct DataDescriptor_64 {
Jason Molendabb934832017-08-15 21:23:14 +0000156 uint64_t _used;
157 uint64_t _offset;
158 uint64_t _size;
159 uint64_t _data;
Sean Callananf40da172017-06-23 23:15:03 +0000160 };
Jason Molendabb934832017-08-15 21:23:14 +0000161
162 using NSArrayMSyntheticFrontEnd =
163 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
Saleem Abdulrasoolfe3a5bf2017-08-23 17:00:14 +0000164}
Jason Molendabb934832017-08-15 21:23:14 +0000165
166namespace Foundation1437 {
167 template <typename PtrType>
168 struct DataDescriptor {
169 PtrType _cow;
170 // __deque
171 PtrType _data;
172 uint32_t _offset;
173 uint32_t _size;
Zachary Turner52f8f342019-01-29 22:55:21 +0000174 uint32_t _muts;
175 uint32_t _used;
Jason Molendabb934832017-08-15 21:23:14 +0000176 };
177
178 using NSArrayMSyntheticFrontEnd =
179 GenericNSArrayMSyntheticFrontEnd<
180 DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;
181
182 template <typename DD>
183 uint64_t
184 __NSArrayMSize_Impl(lldb_private::Process &process,
185 lldb::addr_t valobj_addr, Status &error) {
186 const lldb::addr_t start_of_descriptor =
187 valobj_addr + process.GetAddressByteSize();
188 DD descriptor = DD();
189 process.ReadMemory(start_of_descriptor, &descriptor,
190 sizeof(descriptor), error);
191 if (error.Fail()) {
192 return 0;
193 }
194 return descriptor._used;
195 }
196
197 uint64_t
198 __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
199 Status &error) {
200 if (process.GetAddressByteSize() == 4) {
201 return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,
202 error);
203 } else {
204 return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,
205 error);
206 }
207 }
Sean Callananf40da172017-06-23 23:15:03 +0000208
Davide Italianoc8bee2c2017-08-19 16:30:47 +0000209}
Sean Callananf40da172017-06-23 23:15:03 +0000210
Kuba Mracek37791282018-11-12 21:26:03 +0000211namespace CallStackArray {
212struct DataDescriptor_32 {
213 uint32_t _data;
214 uint32_t _used;
215 uint32_t _offset;
216 const uint32_t _size = 0;
217};
218
219struct DataDescriptor_64 {
220 uint64_t _data;
221 uint64_t _used;
222 uint64_t _offset;
223 const uint64_t _size = 0;
224};
225
226using NSCallStackArraySyntheticFrontEnd =
227 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
228} // namespace CallStackArray
229
Jason Molendabb934832017-08-15 21:23:14 +0000230template <typename D32, typename D64, bool Inline>
231class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
Sean Callananf40da172017-06-23 23:15:03 +0000232public:
Jason Molendabb934832017-08-15 21:23:14 +0000233 GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
Sean Callananf40da172017-06-23 23:15:03 +0000234
Jason Molendabb934832017-08-15 21:23:14 +0000235 ~GenericNSArrayISyntheticFrontEnd() override;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000236
237 size_t CalculateNumChildren() override;
238
239 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
240
241 bool Update() override;
242
243 bool MightHaveChildren() override;
244
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000245 size_t GetIndexOfChildWithName(ConstString name) override;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246
247private:
248 ExecutionContextRef m_exe_ctx_ref;
249 uint8_t m_ptr_size;
Jason Molendabb934832017-08-15 21:23:14 +0000250
251 D32 *m_data_32;
252 D64 *m_data_64;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000253 CompilerType m_id_type;
254};
Jason Molendabb934832017-08-15 21:23:14 +0000255
256namespace Foundation1300 {
257 struct IDD32 {
258 uint32_t used;
259 uint32_t list;
260 };
261
262 struct IDD64 {
263 uint64_t used;
264 uint64_t list;
265 };
266
267 using NSArrayISyntheticFrontEnd =
268 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
Davide Italianoc8bee2c2017-08-19 16:30:47 +0000269}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000270
Jason Molendabb934832017-08-15 21:23:14 +0000271namespace Foundation1430 {
272 using NSArrayISyntheticFrontEnd =
273 Foundation1428::NSArrayMSyntheticFrontEnd;
Davide Italianoc8bee2c2017-08-19 16:30:47 +0000274}
Sean Callananf40da172017-06-23 23:15:03 +0000275
Jason Molendabb934832017-08-15 21:23:14 +0000276namespace Foundation1436 {
277 struct IDD32 {
278 uint32_t used;
279 uint32_t list; // in Inline cases, this is the first element
280 };
281
282 struct IDD64 {
283 uint64_t used;
284 uint64_t list; // in Inline cases, this is the first element
285 };
286
287 using NSArrayI_TransferSyntheticFrontEnd =
288 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;
Sean Callananf40da172017-06-23 23:15:03 +0000289
Jason Molendabb934832017-08-15 21:23:14 +0000290 using NSArrayISyntheticFrontEnd =
291 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
292
293 using NSFrozenArrayMSyntheticFrontEnd =
294 Foundation1437::NSArrayMSyntheticFrontEnd;
Sean Callananf40da172017-06-23 23:15:03 +0000295
Jason Molendabb934832017-08-15 21:23:14 +0000296 uint64_t
297 __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
298 Status &error) {
299 return Foundation1437::__NSArrayMSize(process, valobj_addr, error);
300 }
Davide Italianoc8bee2c2017-08-19 16:30:47 +0000301}
Sean Callananf40da172017-06-23 23:15:03 +0000302
Kate Stoneb9c1b512016-09-06 20:57:50 +0000303class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
304public:
305 NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
306
307 ~NSArray0SyntheticFrontEnd() override = default;
308
309 size_t CalculateNumChildren() override;
310
311 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
312
313 bool Update() override;
314
315 bool MightHaveChildren() override;
316
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000317 size_t GetIndexOfChildWithName(ConstString name) override;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000318};
319
320class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
321public:
322 NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
323
324 ~NSArray1SyntheticFrontEnd() override = default;
325
326 size_t CalculateNumChildren() override;
327
328 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
329
330 bool Update() override;
331
332 bool MightHaveChildren() override;
333
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000334 size_t GetIndexOfChildWithName(ConstString name) override;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335};
336} // namespace formatters
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000337} // namespace lldb_private
Jason Molenda705b1802014-06-13 02:37:02 +0000338
Kate Stoneb9c1b512016-09-06 20:57:50 +0000339bool lldb_private::formatters::NSArraySummaryProvider(
340 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
341 static ConstString g_TypeHint("NSArray");
342
343 ProcessSP process_sp = valobj.GetProcessSP();
344 if (!process_sp)
345 return false;
346
Alex Langforde823bbe2019-06-10 20:53:23 +0000347 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348
349 if (!runtime)
350 return false;
351
352 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
353 runtime->GetClassDescriptor(valobj));
354
355 if (!descriptor || !descriptor->IsValid())
356 return false;
357
358 uint32_t ptr_size = process_sp->GetAddressByteSize();
359
360 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
361
362 if (!valobj_addr)
363 return false;
364
365 uint64_t value = 0;
366
367 ConstString class_name(descriptor->GetClassName());
368
369 static const ConstString g_NSArrayI("__NSArrayI");
370 static const ConstString g_NSArrayM("__NSArrayM");
Jason Molendabb934832017-08-15 21:23:14 +0000371 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
372 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000373 static const ConstString g_NSArray0("__NSArray0");
374 static const ConstString g_NSArray1("__NSSingleObjectArrayI");
375 static const ConstString g_NSArrayCF("__NSCFArray");
Sean Callananf40da172017-06-23 23:15:03 +0000376 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
377 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
Kuba Mracek37791282018-11-12 21:26:03 +0000378 static const ConstString g_NSCallStackArray("_NSCallStackArray");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000379
380 if (class_name.IsEmpty())
381 return false;
382
383 if (class_name == g_NSArrayI) {
Zachary Turner97206d52017-05-12 04:51:55 +0000384 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000385 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
386 ptr_size, 0, error);
387 if (error.Fail())
388 return false;
389 } else if (class_name == g_NSArrayM) {
Jason Molendabb934832017-08-15 21:23:14 +0000390 AppleObjCRuntime *apple_runtime =
391 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
392 Status error;
393 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
394 value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);
395 } else {
396 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
397 ptr_size, 0, error);
398 }
399 if (error.Fail())
400 return false;
401 } else if (class_name == g_NSArrayI_Transfer) {
Zachary Turner97206d52017-05-12 04:51:55 +0000402 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000403 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
404 ptr_size, 0, error);
405 if (error.Fail())
406 return false;
Jason Molendabb934832017-08-15 21:23:14 +0000407 } else if (class_name == g_NSFrozenArrayM) {
408 Status error;
409 value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);
410 if (error.Fail())
411 return false;
Sean Callananf40da172017-06-23 23:15:03 +0000412 } else if (class_name == g_NSArrayMLegacy) {
413 Status error;
414 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
415 ptr_size, 0, error);
416 if (error.Fail())
417 return false;
418 } else if (class_name == g_NSArrayMImmutable) {
419 Status error;
420 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
421 ptr_size, 0, error);
422 if (error.Fail())
423 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000424 } else if (class_name == g_NSArray0) {
425 value = 0;
426 } else if (class_name == g_NSArray1) {
427 value = 1;
Kuba Mracek37791282018-11-12 21:26:03 +0000428 } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {
429 // __NSCFArray and _NSCallStackArray store the number of elements as a
430 // pointer-sized value at offset `2 * ptr_size`.
Zachary Turner97206d52017-05-12 04:51:55 +0000431 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000432 value = process_sp->ReadUnsignedIntegerFromMemory(
433 valobj_addr + 2 * ptr_size, ptr_size, 0, error);
434 if (error.Fail())
435 return false;
436 } else {
437 auto &map(NSArray_Additionals::GetAdditionalSummaries());
438 auto iter = map.find(class_name), end = map.end();
439 if (iter != end)
440 return iter->second(valobj, stream, options);
Enrico Granataf615b802013-02-15 23:38:37 +0000441 else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000442 return false;
443 }
444
445 std::string prefix, suffix;
446 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
447 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
448 suffix)) {
449 prefix.clear();
450 suffix.clear();
Enrico Granatac28b3e82016-04-11 18:46:37 +0000451 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000452 }
453
454 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
455 value == 1 ? "" : "s", suffix.c_str());
456 return true;
Enrico Granataf615b802013-02-15 23:38:37 +0000457}
458
Jason Molendabb934832017-08-15 21:23:14 +0000459lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontEndBase(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000460 lldb::ValueObjectSP valobj_sp)
461 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
462 m_id_type() {
463 if (valobj_sp) {
Alex Langford30318182019-11-14 13:41:52 -0800464 auto *clang_ast_context = ClangASTContext::GetScratch(
465 *valobj_sp->GetExecutionContextRef().GetTargetSP());
Alex Langfordbddab072019-08-13 19:40:36 +0000466 if (clang_ast_context)
467 m_id_type = CompilerType(
468 clang_ast_context,
469 clang_ast_context->getASTContext()->ObjCBuiltinIdTy.getAsOpaquePtr());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000470 if (valobj_sp->GetProcessSP())
471 m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
472 }
Enrico Granataf615b802013-02-15 23:38:37 +0000473}
474
Jason Molendabb934832017-08-15 21:23:14 +0000475template <typename D32, typename D64>
476lldb_private::formatters::
477 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
478 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
479 : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),
Sean Callananf40da172017-06-23 23:15:03 +0000480 m_data_64(nullptr) {}
481
Enrico Granataf615b802013-02-15 23:38:37 +0000482size_t
Jason Molendabb934832017-08-15 21:23:14 +0000483lldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000484 return GetUsedCount();
Enrico Granataf615b802013-02-15 23:38:37 +0000485}
486
487lldb::ValueObjectSP
Jason Molendabb934832017-08-15 21:23:14 +0000488lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000489 size_t idx) {
490 if (idx >= CalculateNumChildren())
491 return lldb::ValueObjectSP();
492 lldb::addr_t object_at_idx = GetDataAddress();
493 size_t pyhs_idx = idx;
494 pyhs_idx += GetOffset();
495 if (GetSize() <= pyhs_idx)
496 pyhs_idx -= GetSize();
497 object_at_idx += (pyhs_idx * m_ptr_size);
498 StreamString idx_name;
499 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
Zachary Turnerc1564272016-11-16 21:15:24 +0000500 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000501 m_exe_ctx_ref, m_id_type);
Enrico Granataf615b802013-02-15 23:38:37 +0000502}
503
Jason Molendabb934832017-08-15 21:23:14 +0000504template <typename D32, typename D64>
505bool
506lldb_private::formatters::
507 GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000508 ValueObjectSP valobj_sp = m_backend.GetSP();
509 m_ptr_size = 0;
510 delete m_data_32;
511 m_data_32 = nullptr;
512 delete m_data_64;
513 m_data_64 = nullptr;
514 if (!valobj_sp)
Jason Molenda705b1802014-06-13 02:37:02 +0000515 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000516 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
Zachary Turner97206d52017-05-12 04:51:55 +0000517 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000518 error.Clear();
519 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
520 if (!process_sp)
Enrico Granataf615b802013-02-15 23:38:37 +0000521 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000522 m_ptr_size = process_sp->GetAddressByteSize();
523 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
524 if (m_ptr_size == 4) {
Jason Molendabb934832017-08-15 21:23:14 +0000525 m_data_32 = new D32();
526 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000527 error);
528 } else {
Jason Molendabb934832017-08-15 21:23:14 +0000529 m_data_64 = new D64();
530 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000531 error);
532 }
533 if (error.Fail())
Enrico Granataf615b802013-02-15 23:38:37 +0000534 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000535 return false;
Enrico Granataf615b802013-02-15 23:38:37 +0000536}
537
Jason Molendabb934832017-08-15 21:23:14 +0000538bool
539lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000540 return true;
Enrico Granatabbf1da32015-10-14 22:45:04 +0000541}
542
Enrico Granatabbf1da32015-10-14 22:45:04 +0000543size_t
Jason Molendabb934832017-08-15 21:23:14 +0000544lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000545 ConstString name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000546 const char *item_name = name.GetCString();
547 uint32_t idx = ExtractIndexFromString(item_name);
548 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
Enrico Granatabbf1da32015-10-14 22:45:04 +0000549 return UINT32_MAX;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000550 return idx;
Enrico Granatabbf1da32015-10-14 22:45:04 +0000551}
552
Jason Molendabb934832017-08-15 21:23:14 +0000553template <typename D32, typename D64>
554lldb_private::formatters::
555 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
556 ~GenericNSArrayMSyntheticFrontEnd() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000557 delete m_data_32;
558 m_data_32 = nullptr;
559 delete m_data_64;
560 m_data_64 = nullptr;
561}
562
Jason Molendabb934832017-08-15 21:23:14 +0000563template <typename D32, typename D64>
Kate Stoneb9c1b512016-09-06 20:57:50 +0000564lldb::addr_t
Jason Molendabb934832017-08-15 21:23:14 +0000565lldb_private::formatters::
566 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
567 GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000568 if (!m_data_32 && !m_data_64)
569 return LLDB_INVALID_ADDRESS;
570 return m_data_32 ? m_data_32->_data : m_data_64->_data;
571}
572
Jason Molendabb934832017-08-15 21:23:14 +0000573template <typename D32, typename D64>
Kate Stoneb9c1b512016-09-06 20:57:50 +0000574uint64_t
Jason Molendabb934832017-08-15 21:23:14 +0000575lldb_private::formatters::
576 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
577 GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000578 if (!m_data_32 && !m_data_64)
Enrico Granatabbf1da32015-10-14 22:45:04 +0000579 return 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000580 return m_data_32 ? m_data_32->_used : m_data_64->_used;
Enrico Granatabbf1da32015-10-14 22:45:04 +0000581}
582
Jason Molendabb934832017-08-15 21:23:14 +0000583template <typename D32, typename D64>
584uint64_t
585lldb_private::formatters::
586 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
587 GenericNSArrayMSyntheticFrontEnd::GetOffset() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000588 if (!m_data_32 && !m_data_64)
589 return 0;
590 return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
Enrico Granatabbf1da32015-10-14 22:45:04 +0000591}
592
Jason Molendabb934832017-08-15 21:23:14 +0000593template <typename D32, typename D64>
594uint64_t
595lldb_private::formatters::
596 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
597 GenericNSArrayMSyntheticFrontEnd::GetSize() {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000598 if (!m_data_32 && !m_data_64)
599 return 0;
600 return m_data_32 ? m_data_32->_size : m_data_64->_size;
Enrico Granatabbf1da32015-10-14 22:45:04 +0000601}
602
Jason Molendabb934832017-08-15 21:23:14 +0000603template <typename D32, typename D64, bool Inline>
604lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
605 GenericNSArrayISyntheticFrontEnd(
Sean Callananf40da172017-06-23 23:15:03 +0000606 lldb::ValueObjectSP valobj_sp)
607 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
608 m_data_32(nullptr), m_data_64(nullptr) {
609 if (valobj_sp) {
610 CompilerType type = valobj_sp->GetCompilerType();
611 if (type) {
Alex Langford30318182019-11-14 13:41:52 -0800612 auto *clang_ast_context = ClangASTContext::GetScratch(
613 *valobj_sp->GetExecutionContextRef().GetTargetSP());
Alex Langfordbddab072019-08-13 19:40:36 +0000614 if (clang_ast_context)
615 m_id_type = CompilerType(clang_ast_context,
616 clang_ast_context->getASTContext()
617 ->ObjCBuiltinIdTy.getAsOpaquePtr());
Sean Callananf40da172017-06-23 23:15:03 +0000618 }
619 }
620}
621
Jason Molendabb934832017-08-15 21:23:14 +0000622template <typename D32, typename D64, bool Inline>
623lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
624 ~GenericNSArrayISyntheticFrontEnd() {
Sean Callananf40da172017-06-23 23:15:03 +0000625 delete m_data_32;
626 m_data_32 = nullptr;
627 delete m_data_64;
628 m_data_64 = nullptr;
629}
630
Jason Molendabb934832017-08-15 21:23:14 +0000631template <typename D32, typename D64, bool Inline>
Sean Callananf40da172017-06-23 23:15:03 +0000632size_t
Jason Molendabb934832017-08-15 21:23:14 +0000633lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000634 GetIndexOfChildWithName(ConstString name) {
Sean Callananf40da172017-06-23 23:15:03 +0000635 const char *item_name = name.GetCString();
636 uint32_t idx = ExtractIndexFromString(item_name);
637 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
638 return UINT32_MAX;
639 return idx;
640}
641
Jason Molendabb934832017-08-15 21:23:14 +0000642template <typename D32, typename D64, bool Inline>
Sean Callananf40da172017-06-23 23:15:03 +0000643size_t
Jason Molendabb934832017-08-15 21:23:14 +0000644lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
645 CalculateNumChildren() {
Sean Callananf40da172017-06-23 23:15:03 +0000646 return m_data_32 ? m_data_32->used : m_data_64->used;
647}
648
Jason Molendabb934832017-08-15 21:23:14 +0000649template <typename D32, typename D64, bool Inline>
650bool
651lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
652 Update() {
Sean Callananf40da172017-06-23 23:15:03 +0000653 ValueObjectSP valobj_sp = m_backend.GetSP();
654 m_ptr_size = 0;
655 delete m_data_32;
656 m_data_32 = nullptr;
657 delete m_data_64;
658 m_data_64 = nullptr;
659 if (!valobj_sp)
660 return false;
661 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
662 Status error;
663 error.Clear();
664 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
665 if (!process_sp)
666 return false;
667 m_ptr_size = process_sp->GetAddressByteSize();
668 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
669 if (m_ptr_size == 4) {
Jason Molendabb934832017-08-15 21:23:14 +0000670 m_data_32 = new D32();
671 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
Sean Callananf40da172017-06-23 23:15:03 +0000672 error);
673 } else {
Jason Molendabb934832017-08-15 21:23:14 +0000674 m_data_64 = new D64();
675 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
Sean Callananf40da172017-06-23 23:15:03 +0000676 error);
677 }
678 if (error.Fail())
679 return false;
680 return false;
681}
682
Jason Molendabb934832017-08-15 21:23:14 +0000683template <typename D32, typename D64, bool Inline>
684bool
685lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
686 MightHaveChildren() {
Sean Callananf40da172017-06-23 23:15:03 +0000687 return true;
688}
689
Jason Molendabb934832017-08-15 21:23:14 +0000690template <typename D32, typename D64, bool Inline>
Sean Callananf40da172017-06-23 23:15:03 +0000691lldb::ValueObjectSP
Jason Molendabb934832017-08-15 21:23:14 +0000692lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
693 GetChildAtIndex(size_t idx) {
Sean Callananf40da172017-06-23 23:15:03 +0000694 if (idx >= CalculateNumChildren())
695 return lldb::ValueObjectSP();
Jason Molendabb934832017-08-15 21:23:14 +0000696 lldb::addr_t object_at_idx;
697 if (Inline) {
698 object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;
699 object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header
700 object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer
701 } else {
702 object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
703 }
Sean Callananf40da172017-06-23 23:15:03 +0000704 object_at_idx += (idx * m_ptr_size);
Jason Molendabb934832017-08-15 21:23:14 +0000705
Sean Callananf40da172017-06-23 23:15:03 +0000706 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
707 if (!process_sp)
708 return lldb::ValueObjectSP();
709 Status error;
710 if (error.Fail())
711 return lldb::ValueObjectSP();
712 StreamString idx_name;
713 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
714 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
715 m_exe_ctx_ref, m_id_type);
716}
717
Kate Stoneb9c1b512016-09-06 20:57:50 +0000718lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
719 lldb::ValueObjectSP valobj_sp)
720 : SyntheticChildrenFrontEnd(*valobj_sp) {}
721
722size_t
723lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000724 ConstString name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000725 return UINT32_MAX;
726}
727
728size_t
729lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
730 return 0;
731}
732
733bool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
734 return false;
735}
736
737bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
738 return false;
739}
740
741lldb::ValueObjectSP
742lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
743 size_t idx) {
744 return lldb::ValueObjectSP();
745}
746
747lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
748 lldb::ValueObjectSP valobj_sp)
749 : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
750
751size_t
752lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
Adrian Prantl0e4c4822019-03-06 21:22:25 +0000753 ConstString name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000754 static const ConstString g_zero("[0]");
755
756 if (name == g_zero)
757 return 0;
758
759 return UINT32_MAX;
760}
761
762size_t
763lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
764 return 1;
765}
766
767bool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
768 return false;
769}
770
771bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
772 return true;
773}
774
775lldb::ValueObjectSP
776lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
777 size_t idx) {
778 static const ConstString g_zero("[0]");
779
780 if (idx == 0) {
Alex Langford30318182019-11-14 13:41:52 -0800781 auto *clang_ast_context =
782 ClangASTContext::GetScratch(*m_backend.GetTargetSP());
783 if (clang_ast_context) {
784 CompilerType id_type(
785 clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID));
786 return m_backend.GetSyntheticChildAtOffset(
787 m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true,
788 g_zero);
789 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000790 }
791 return lldb::ValueObjectSP();
792}
793
794SyntheticChildrenFrontEnd *
795lldb_private::formatters::NSArraySyntheticFrontEndCreator(
796 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
797 if (!valobj_sp)
Enrico Granata2543d292016-02-12 07:50:15 +0000798 return nullptr;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000799
800 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
801 if (!process_sp)
802 return nullptr;
803 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
Alex Langforde823bbe2019-06-10 20:53:23 +0000804 ObjCLanguageRuntime::Get(*process_sp));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000805 if (!runtime)
806 return nullptr;
807
808 CompilerType valobj_type(valobj_sp->GetCompilerType());
809 Flags flags(valobj_type.GetTypeInfo());
810
811 if (flags.IsClear(eTypeIsPointer)) {
Zachary Turner97206d52017-05-12 04:51:55 +0000812 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000813 valobj_sp = valobj_sp->AddressOf(error);
814 if (error.Fail() || !valobj_sp)
815 return nullptr;
816 }
817
818 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
819 runtime->GetClassDescriptor(*valobj_sp));
820
821 if (!descriptor || !descriptor->IsValid())
822 return nullptr;
823
824 ConstString class_name(descriptor->GetClassName());
825
826 static const ConstString g_NSArrayI("__NSArrayI");
Jason Molendabb934832017-08-15 21:23:14 +0000827 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
828 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000829 static const ConstString g_NSArrayM("__NSArrayM");
830 static const ConstString g_NSArray0("__NSArray0");
831 static const ConstString g_NSArray1("__NSSingleObjectArrayI");
Sean Callananf40da172017-06-23 23:15:03 +0000832 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
833 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
Kuba Mracek37791282018-11-12 21:26:03 +0000834 static const ConstString g_NSCallStackArray("_NSCallStackArray");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000835
836 if (class_name.IsEmpty())
837 return nullptr;
838
839 if (class_name == g_NSArrayI) {
Jason Molendabb934832017-08-15 21:23:14 +0000840 if (runtime->GetFoundationVersion() >= 1436)
841 return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));
842 if (runtime->GetFoundationVersion() >= 1430)
843 return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));
844 else
845 return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
846 } else if (class_name == g_NSArrayI_Transfer) {
847 return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
848 } else if (class_name == g_NSArray0) {
849 } else if (class_name == g_NSFrozenArrayM) {
850 return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000851 } else if (class_name == g_NSArray0) {
852 return (new NSArray0SyntheticFrontEnd(valobj_sp));
853 } else if (class_name == g_NSArray1) {
854 return (new NSArray1SyntheticFrontEnd(valobj_sp));
855 } else if (class_name == g_NSArrayM) {
Jason Molendabb934832017-08-15 21:23:14 +0000856 if (runtime->GetFoundationVersion() >= 1437)
857 return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));
858 if (runtime->GetFoundationVersion() >= 1428)
859 return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000860 if (runtime->GetFoundationVersion() >= 1100)
Jason Molendabb934832017-08-15 21:23:14 +0000861 return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000862 else
Jason Molendabb934832017-08-15 21:23:14 +0000863 return (new Foundation109::NSArrayMSyntheticFrontEnd(valobj_sp));
Kuba Mracek37791282018-11-12 21:26:03 +0000864 } else if (class_name == g_NSCallStackArray) {
865 return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000866 } else {
867 auto &map(NSArray_Additionals::GetAdditionalSynthetics());
868 auto iter = map.find(class_name), end = map.end();
869 if (iter != end)
870 return iter->second(synth, valobj_sp);
871 }
872
873 return nullptr;
Enrico Granataf615b802013-02-15 23:38:37 +0000874}