1 //===-- NSArray.cpp ---------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "clang/AST/ASTContext.h"
13 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
15 #include "lldb/Core/ValueObject.h"
16 #include "lldb/Core/ValueObjectConstResult.h"
17 #include "lldb/DataFormatters/FormattersHelpers.h"
18 #include "lldb/Expression/FunctionCaller.h"
19 #include "lldb/Symbol/ClangASTContext.h"
20 #include "lldb/Target/Language.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Utility/DataBufferHeap.h"
23 #include "lldb/Utility/Endian.h"
24 #include "lldb/Utility/Status.h"
25 #include "lldb/Utility/Stream.h"
28 using namespace lldb_private;
29 using namespace lldb_private::formatters;
31 namespace lldb_private {
32 namespace formatters {
33 std::map<ConstString, CXXFunctionSummaryFormat::Callback> &
34 NSArray_Additionals::GetAdditionalSummaries() {
35 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;
39 std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &
40 NSArray_Additionals::GetAdditionalSynthetics() {
41 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>
46 class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {
48 NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);
50 ~NSArrayMSyntheticFrontEndBase() override = default;
52 size_t CalculateNumChildren() override;
54 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
56 bool Update() override = 0;
58 bool MightHaveChildren() override;
60 size_t GetIndexOfChildWithName(ConstString name) override;
63 virtual lldb::addr_t GetDataAddress() = 0;
65 virtual uint64_t GetUsedCount() = 0;
67 virtual uint64_t GetOffset() = 0;
69 virtual uint64_t GetSize() = 0;
71 ExecutionContextRef m_exe_ctx_ref;
73 CompilerType m_id_type;
76 template <typename D32, typename D64>
77 class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {
79 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
81 ~GenericNSArrayMSyntheticFrontEnd() override;
83 bool Update() override;
86 lldb::addr_t GetDataAddress() override;
88 uint64_t GetUsedCount() override;
90 uint64_t GetOffset() override;
92 uint64_t GetSize() override;
99 namespace Foundation1010 {
100 struct DataDescriptor_32 {
109 struct DataDescriptor_64 {
118 using NSArrayMSyntheticFrontEnd =
119 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
122 namespace Foundation1428 {
123 struct DataDescriptor_32 {
130 struct DataDescriptor_64 {
137 using NSArrayMSyntheticFrontEnd =
138 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
141 namespace Foundation1437 {
142 template <typename PtrType>
143 struct DataDescriptor {
153 using NSArrayMSyntheticFrontEnd =
154 GenericNSArrayMSyntheticFrontEnd<
155 DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;
157 template <typename DD>
159 __NSArrayMSize_Impl(lldb_private::Process &process,
160 lldb::addr_t valobj_addr, Status &error) {
161 const lldb::addr_t start_of_descriptor =
162 valobj_addr + process.GetAddressByteSize();
163 DD descriptor = DD();
164 process.ReadMemory(start_of_descriptor, &descriptor,
165 sizeof(descriptor), error);
169 return descriptor._used;
173 __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
175 if (process.GetAddressByteSize() == 4) {
176 return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,
179 return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,
186 namespace CallStackArray {
187 struct DataDescriptor_32 {
191 const uint32_t _size = 0;
194 struct DataDescriptor_64 {
198 const uint64_t _size = 0;
201 using NSCallStackArraySyntheticFrontEnd =
202 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;
203 } // namespace CallStackArray
205 template <typename D32, typename D64, bool Inline>
206 class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
208 GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
210 ~GenericNSArrayISyntheticFrontEnd() override;
212 size_t CalculateNumChildren() override;
214 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
216 bool Update() override;
218 bool MightHaveChildren() override;
220 size_t GetIndexOfChildWithName(ConstString name) override;
223 ExecutionContextRef m_exe_ctx_ref;
228 CompilerType m_id_type;
231 namespace Foundation1300 {
242 using NSArrayISyntheticFrontEnd =
243 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
246 namespace Foundation1430 {
247 using NSArrayISyntheticFrontEnd =
248 Foundation1428::NSArrayMSyntheticFrontEnd;
251 namespace Foundation1436 {
254 uint32_t list; // in Inline cases, this is the first element
259 uint64_t list; // in Inline cases, this is the first element
262 using NSArrayI_TransferSyntheticFrontEnd =
263 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;
265 using NSArrayISyntheticFrontEnd =
266 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;
268 using NSFrozenArrayMSyntheticFrontEnd =
269 Foundation1437::NSArrayMSyntheticFrontEnd;
272 __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,
274 return Foundation1437::__NSArrayMSize(process, valobj_addr, error);
278 class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
280 NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
282 ~NSArray0SyntheticFrontEnd() override = default;
284 size_t CalculateNumChildren() override;
286 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
288 bool Update() override;
290 bool MightHaveChildren() override;
292 size_t GetIndexOfChildWithName(ConstString name) override;
295 class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
297 NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
299 ~NSArray1SyntheticFrontEnd() override = default;
301 size_t CalculateNumChildren() override;
303 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
305 bool Update() override;
307 bool MightHaveChildren() override;
309 size_t GetIndexOfChildWithName(ConstString name) override;
311 } // namespace formatters
312 } // namespace lldb_private
314 bool lldb_private::formatters::NSArraySummaryProvider(
315 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
316 static ConstString g_TypeHint("NSArray");
318 ProcessSP process_sp = valobj.GetProcessSP();
322 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
327 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
328 runtime->GetClassDescriptor(valobj));
330 if (!descriptor || !descriptor->IsValid())
333 uint32_t ptr_size = process_sp->GetAddressByteSize();
335 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
342 ConstString class_name(descriptor->GetClassName());
344 static const ConstString g_NSArrayI("__NSArrayI");
345 static const ConstString g_NSArrayM("__NSArrayM");
346 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
347 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
348 static const ConstString g_NSArray0("__NSArray0");
349 static const ConstString g_NSArray1("__NSSingleObjectArrayI");
350 static const ConstString g_NSArrayCF("__NSCFArray");
351 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
352 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
353 static const ConstString g_NSCallStackArray("_NSCallStackArray");
355 if (class_name.IsEmpty())
358 if (class_name == g_NSArrayI) {
360 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
364 } else if (class_name == g_NSArrayM) {
365 AppleObjCRuntime *apple_runtime =
366 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
368 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
369 value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);
371 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
376 } else if (class_name == g_NSArrayI_Transfer) {
378 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
382 } else if (class_name == g_NSFrozenArrayM) {
384 value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);
387 } else if (class_name == g_NSArrayMLegacy) {
389 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
393 } else if (class_name == g_NSArrayMImmutable) {
395 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
399 } else if (class_name == g_NSArray0) {
401 } else if (class_name == g_NSArray1) {
403 } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {
404 // __NSCFArray and _NSCallStackArray store the number of elements as a
405 // pointer-sized value at offset `2 * ptr_size`.
407 value = process_sp->ReadUnsignedIntegerFromMemory(
408 valobj_addr + 2 * ptr_size, ptr_size, 0, error);
412 auto &map(NSArray_Additionals::GetAdditionalSummaries());
413 auto iter = map.find(class_name), end = map.end();
415 return iter->second(valobj, stream, options);
420 std::string prefix, suffix;
421 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
422 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
429 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "element",
430 value == 1 ? "" : "s", suffix.c_str());
434 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontEndBase(
435 lldb::ValueObjectSP valobj_sp)
436 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
439 auto *clang_ast_context = ClangASTContext::GetScratch(
440 *valobj_sp->GetExecutionContextRef().GetTargetSP());
441 if (clang_ast_context)
442 m_id_type = CompilerType(
444 clang_ast_context->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr());
445 if (valobj_sp->GetProcessSP())
446 m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();
450 template <typename D32, typename D64>
451 lldb_private::formatters::
452 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
453 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
454 : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),
455 m_data_64(nullptr) {}
458 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {
459 return GetUsedCount();
463 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(
465 if (idx >= CalculateNumChildren())
466 return lldb::ValueObjectSP();
467 lldb::addr_t object_at_idx = GetDataAddress();
468 size_t pyhs_idx = idx;
469 pyhs_idx += GetOffset();
470 if (GetSize() <= pyhs_idx)
471 pyhs_idx -= GetSize();
472 object_at_idx += (pyhs_idx * m_ptr_size);
473 StreamString idx_name;
474 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
475 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
476 m_exe_ctx_ref, m_id_type);
479 template <typename D32, typename D64>
481 lldb_private::formatters::
482 GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {
483 ValueObjectSP valobj_sp = m_backend.GetSP();
491 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
494 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
497 m_ptr_size = process_sp->GetAddressByteSize();
498 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
499 if (m_ptr_size == 4) {
500 m_data_32 = new D32();
501 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
504 m_data_64 = new D64();
505 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
514 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::MightHaveChildren() {
519 lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName(
521 const char *item_name = name.GetCString();
522 uint32_t idx = ExtractIndexFromString(item_name);
523 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
528 template <typename D32, typename D64>
529 lldb_private::formatters::
530 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
531 ~GenericNSArrayMSyntheticFrontEnd() {
538 template <typename D32, typename D64>
540 lldb_private::formatters::
541 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
542 GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {
543 if (!m_data_32 && !m_data_64)
544 return LLDB_INVALID_ADDRESS;
545 return m_data_32 ? m_data_32->_data : m_data_64->_data;
548 template <typename D32, typename D64>
550 lldb_private::formatters::
551 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
552 GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {
553 if (!m_data_32 && !m_data_64)
555 return m_data_32 ? m_data_32->_used : m_data_64->_used;
558 template <typename D32, typename D64>
560 lldb_private::formatters::
561 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
562 GenericNSArrayMSyntheticFrontEnd::GetOffset() {
563 if (!m_data_32 && !m_data_64)
565 return m_data_32 ? m_data_32->_offset : m_data_64->_offset;
568 template <typename D32, typename D64>
570 lldb_private::formatters::
571 GenericNSArrayMSyntheticFrontEnd<D32, D64>::
572 GenericNSArrayMSyntheticFrontEnd::GetSize() {
573 if (!m_data_32 && !m_data_64)
575 return m_data_32 ? m_data_32->_size : m_data_64->_size;
578 template <typename D32, typename D64, bool Inline>
579 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
580 GenericNSArrayISyntheticFrontEnd(
581 lldb::ValueObjectSP valobj_sp)
582 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
583 m_data_32(nullptr), m_data_64(nullptr) {
585 CompilerType type = valobj_sp->GetCompilerType();
587 auto *clang_ast_context = ClangASTContext::GetScratch(
588 *valobj_sp->GetExecutionContextRef().GetTargetSP());
589 if (clang_ast_context)
590 m_id_type = clang_ast_context->GetType(
591 clang_ast_context->getASTContext().ObjCBuiltinIdTy);
596 template <typename D32, typename D64, bool Inline>
597 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
598 ~GenericNSArrayISyntheticFrontEnd() {
605 template <typename D32, typename D64, bool Inline>
607 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
608 GetIndexOfChildWithName(ConstString name) {
609 const char *item_name = name.GetCString();
610 uint32_t idx = ExtractIndexFromString(item_name);
611 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
616 template <typename D32, typename D64, bool Inline>
618 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
619 CalculateNumChildren() {
620 return m_data_32 ? m_data_32->used : m_data_64->used;
623 template <typename D32, typename D64, bool Inline>
625 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
627 ValueObjectSP valobj_sp = m_backend.GetSP();
635 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
638 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
641 m_ptr_size = process_sp->GetAddressByteSize();
642 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
643 if (m_ptr_size == 4) {
644 m_data_32 = new D32();
645 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
648 m_data_64 = new D64();
649 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
657 template <typename D32, typename D64, bool Inline>
659 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
660 MightHaveChildren() {
664 template <typename D32, typename D64, bool Inline>
666 lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::
667 GetChildAtIndex(size_t idx) {
668 if (idx >= CalculateNumChildren())
669 return lldb::ValueObjectSP();
670 lldb::addr_t object_at_idx;
672 object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;
673 object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header
674 object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer
676 object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
678 object_at_idx += (idx * m_ptr_size);
680 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
682 return lldb::ValueObjectSP();
685 return lldb::ValueObjectSP();
686 StreamString idx_name;
687 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
688 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
689 m_exe_ctx_ref, m_id_type);
692 lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
693 lldb::ValueObjectSP valobj_sp)
694 : SyntheticChildrenFrontEnd(*valobj_sp) {}
697 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(
703 lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {
707 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {
711 bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {
716 lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(
718 return lldb::ValueObjectSP();
721 lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(
722 lldb::ValueObjectSP valobj_sp)
723 : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}
726 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(
728 static const ConstString g_zero("[0]");
737 lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {
741 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {
745 bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() {
750 lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(
752 static const ConstString g_zero("[0]");
755 auto *clang_ast_context =
756 ClangASTContext::GetScratch(*m_backend.GetTargetSP());
757 if (clang_ast_context) {
758 CompilerType id_type(
759 clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID));
760 return m_backend.GetSyntheticChildAtOffset(
761 m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true,
765 return lldb::ValueObjectSP();
768 SyntheticChildrenFrontEnd *
769 lldb_private::formatters::NSArraySyntheticFrontEndCreator(
770 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
774 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
777 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
778 ObjCLanguageRuntime::Get(*process_sp));
782 CompilerType valobj_type(valobj_sp->GetCompilerType());
783 Flags flags(valobj_type.GetTypeInfo());
785 if (flags.IsClear(eTypeIsPointer)) {
787 valobj_sp = valobj_sp->AddressOf(error);
788 if (error.Fail() || !valobj_sp)
792 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
793 runtime->GetClassDescriptor(*valobj_sp));
795 if (!descriptor || !descriptor->IsValid())
798 ConstString class_name(descriptor->GetClassName());
800 static const ConstString g_NSArrayI("__NSArrayI");
801 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");
802 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");
803 static const ConstString g_NSArrayM("__NSArrayM");
804 static const ConstString g_NSArray0("__NSArray0");
805 static const ConstString g_NSArray1("__NSSingleObjectArrayI");
806 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
807 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
808 static const ConstString g_NSCallStackArray("_NSCallStackArray");
810 if (class_name.IsEmpty())
813 if (class_name == g_NSArrayI) {
814 if (runtime->GetFoundationVersion() >= 1436)
815 return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));
816 if (runtime->GetFoundationVersion() >= 1430)
817 return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));
819 return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));
820 } else if (class_name == g_NSArrayI_Transfer) {
821 return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));
822 } else if (class_name == g_NSArray0) {
823 } else if (class_name == g_NSFrozenArrayM) {
824 return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));
825 } else if (class_name == g_NSArray0) {
826 return (new NSArray0SyntheticFrontEnd(valobj_sp));
827 } else if (class_name == g_NSArray1) {
828 return (new NSArray1SyntheticFrontEnd(valobj_sp));
829 } else if (class_name == g_NSArrayM) {
830 if (runtime->GetFoundationVersion() >= 1437)
831 return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));
832 if (runtime->GetFoundationVersion() >= 1428)
833 return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));
834 if (runtime->GetFoundationVersion() >= 1100)
835 return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));
836 } else if (class_name == g_NSCallStackArray) {
837 return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));
839 auto &map(NSArray_Additionals::GetAdditionalSynthetics());
840 auto iter = map.find(class_name), end = map.end();
842 return iter->second(synth, valobj_sp);