856 lines · cpp
1//===-- NSArray.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/AST/ASTContext.h"10#include "clang/Basic/TargetInfo.h"11 12#include "Cocoa.h"13 14#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"15#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"16 17#include "lldb/DataFormatters/FormattersHelpers.h"18#include "lldb/Expression/FunctionCaller.h"19#include "lldb/Target/Language.h"20#include "lldb/Target/Target.h"21#include "lldb/Utility/DataBufferHeap.h"22#include "lldb/Utility/Endian.h"23#include "lldb/Utility/Status.h"24#include "lldb/Utility/Stream.h"25#include "lldb/ValueObject/ValueObject.h"26#include "lldb/ValueObject/ValueObjectConstResult.h"27 28using namespace lldb;29using namespace lldb_private;30using namespace lldb_private::formatters;31 32namespace lldb_private {33namespace formatters {34std::map<ConstString, CXXFunctionSummaryFormat::Callback> &35NSArray_Additionals::GetAdditionalSummaries() {36 static std::map<ConstString, CXXFunctionSummaryFormat::Callback> g_map;37 return g_map;38}39 40std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback> &41NSArray_Additionals::GetAdditionalSynthetics() {42 static std::map<ConstString, CXXSyntheticChildren::CreateFrontEndCallback>43 g_map;44 return g_map;45}46 47class NSArrayMSyntheticFrontEndBase : public SyntheticChildrenFrontEnd {48public:49 NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp);50 51 ~NSArrayMSyntheticFrontEndBase() override = default;52 53 llvm::Expected<uint32_t> CalculateNumChildren() override;54 55 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;56 57 lldb::ChildCacheState Update() override = 0;58 59 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;60 61protected:62 virtual lldb::addr_t GetDataAddress() = 0;63 64 virtual uint64_t GetUsedCount() = 0;65 66 virtual uint64_t GetOffset() = 0;67 68 virtual uint64_t GetSize() = 0;69 70 ExecutionContextRef m_exe_ctx_ref;71 uint8_t m_ptr_size = 8;72 CompilerType m_id_type;73};74 75template <typename D32, typename D64>76class GenericNSArrayMSyntheticFrontEnd : public NSArrayMSyntheticFrontEndBase {77public:78 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);79 80 ~GenericNSArrayMSyntheticFrontEnd() override;81 82 lldb::ChildCacheState Update() override;83 84protected:85 lldb::addr_t GetDataAddress() override;86 87 uint64_t GetUsedCount() override;88 89 uint64_t GetOffset() override;90 91 uint64_t GetSize() override;92 93private:94 D32 *m_data_32;95 D64 *m_data_64;96};97 98namespace Foundation1010 {99 namespace {100 struct DataDescriptor_32 {101 uint32_t _used;102 uint32_t _offset;103 uint32_t _size : 28;104 uint64_t _priv1 : 4;105 uint32_t _priv2;106 uint32_t _data;107 };108 109 struct DataDescriptor_64 {110 uint64_t _used;111 uint64_t _offset;112 uint64_t _size : 60;113 uint64_t _priv1 : 4;114 uint32_t _priv2;115 uint64_t _data;116 };117 }118 119 using NSArrayMSyntheticFrontEnd =120 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;121}122 123namespace Foundation1428 {124 namespace {125 struct DataDescriptor_32 {126 uint32_t _used;127 uint32_t _offset;128 uint32_t _size;129 uint32_t _data;130 };131 132 struct DataDescriptor_64 {133 uint64_t _used;134 uint64_t _offset;135 uint64_t _size;136 uint64_t _data;137 };138 }139 140 using NSArrayMSyntheticFrontEnd =141 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;142}143 144namespace Foundation1437 {145 template <typename PtrType>146 struct DataDescriptor {147 PtrType _cow;148 // __deque149 PtrType _data;150 uint32_t _offset;151 uint32_t _size;152 uint32_t _muts;153 uint32_t _used;154 };155 156 using NSArrayMSyntheticFrontEnd =157 GenericNSArrayMSyntheticFrontEnd<158 DataDescriptor<uint32_t>, DataDescriptor<uint64_t>>;159 160 template <typename DD>161 uint64_t162 __NSArrayMSize_Impl(lldb_private::Process &process,163 lldb::addr_t valobj_addr, Status &error) {164 const lldb::addr_t start_of_descriptor =165 valobj_addr + process.GetAddressByteSize();166 DD descriptor = DD();167 process.ReadMemory(start_of_descriptor, &descriptor,168 sizeof(descriptor), error);169 if (error.Fail()) {170 return 0;171 }172 return descriptor._used;173 }174 175 uint64_t176 __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,177 Status &error) {178 if (process.GetAddressByteSize() == 4) {179 return __NSArrayMSize_Impl<DataDescriptor<uint32_t>>(process, valobj_addr,180 error);181 } else {182 return __NSArrayMSize_Impl<DataDescriptor<uint64_t>>(process, valobj_addr,183 error);184 }185 }186 187}188 189namespace CallStackArray {190struct DataDescriptor_32 {191 uint32_t _data;192 uint32_t _used;193 uint32_t _offset;194 const uint32_t _size = 0;195};196 197struct DataDescriptor_64 {198 uint64_t _data;199 uint64_t _used;200 uint64_t _offset;201 const uint64_t _size = 0;202};203 204using NSCallStackArraySyntheticFrontEnd =205 GenericNSArrayMSyntheticFrontEnd<DataDescriptor_32, DataDescriptor_64>;206} // namespace CallStackArray207 208template <typename D32, typename D64, bool Inline>209class GenericNSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {210public:211 GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);212 213 ~GenericNSArrayISyntheticFrontEnd() override;214 215 llvm::Expected<uint32_t> CalculateNumChildren() override;216 217 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;218 219 lldb::ChildCacheState Update() override;220 221 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;222 223private:224 ExecutionContextRef m_exe_ctx_ref;225 uint8_t m_ptr_size = 8;226 227 D32 *m_data_32;228 D64 *m_data_64;229 CompilerType m_id_type;230};231 232namespace Foundation1300 {233 struct IDD32 {234 uint32_t used;235 uint32_t list;236 };237 238 struct IDD64 {239 uint64_t used;240 uint64_t list;241 };242 243 using NSArrayISyntheticFrontEnd =244 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;245}246 247namespace Foundation1430 {248 using NSArrayISyntheticFrontEnd =249 Foundation1428::NSArrayMSyntheticFrontEnd;250}251 252namespace Foundation1436 {253 struct IDD32 {254 uint32_t used;255 uint32_t list; // in Inline cases, this is the first element256 };257 258 struct IDD64 {259 uint64_t used;260 uint64_t list; // in Inline cases, this is the first element261 };262 263 using NSArrayI_TransferSyntheticFrontEnd =264 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, false>;265 266 using NSArrayISyntheticFrontEnd =267 GenericNSArrayISyntheticFrontEnd<IDD32, IDD64, true>;268 269 using NSFrozenArrayMSyntheticFrontEnd =270 Foundation1437::NSArrayMSyntheticFrontEnd;271 272 uint64_t273 __NSFrozenArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr,274 Status &error) {275 return Foundation1437::__NSArrayMSize(process, valobj_addr, error);276 }277}278 279namespace ConstantArray {280 281struct ConstantArray32 {282 uint64_t used;283 uint32_t list;284};285 286struct ConstantArray64 {287 uint64_t used;288 uint64_t list;289};290 291using NSConstantArraySyntheticFrontEnd =292 GenericNSArrayISyntheticFrontEnd<ConstantArray32, ConstantArray64, false>;293} // namespace ConstantArray294 295class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {296public:297 NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);298 299 ~NSArray0SyntheticFrontEnd() override = default;300 301 llvm::Expected<uint32_t> CalculateNumChildren() override;302 303 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;304 305 lldb::ChildCacheState Update() override;306 307 bool MightHaveChildren() override;308 309 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;310};311 312class NSArray1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {313public:314 NSArray1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);315 316 ~NSArray1SyntheticFrontEnd() override = default;317 318 llvm::Expected<uint32_t> CalculateNumChildren() override;319 320 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;321 322 lldb::ChildCacheState Update() override;323 324 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;325};326} // namespace formatters327} // namespace lldb_private328 329bool lldb_private::formatters::NSArraySummaryProvider(330 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {331 static constexpr llvm::StringLiteral g_TypeHint("NSArray");332 333 ProcessSP process_sp = valobj.GetProcessSP();334 if (!process_sp)335 return false;336 337 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);338 339 if (!runtime)340 return false;341 342 ObjCLanguageRuntime::ClassDescriptorSP descriptor(343 runtime->GetClassDescriptor(valobj));344 345 if (!descriptor || !descriptor->IsValid())346 return false;347 348 uint32_t ptr_size = process_sp->GetAddressByteSize();349 350 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);351 352 if (!valobj_addr)353 return false;354 355 uint64_t value = 0;356 357 ConstString class_name(descriptor->GetClassName());358 359 static const ConstString g_NSArrayI("__NSArrayI");360 static const ConstString g_NSArrayM("__NSArrayM");361 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");362 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");363 static const ConstString g_NSArray0("__NSArray0");364 static const ConstString g_NSArray1("__NSSingleObjectArrayI");365 static const ConstString g_NSArrayCF("__NSCFArray");366 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");367 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");368 static const ConstString g_NSCallStackArray("_NSCallStackArray");369 static const ConstString g_NSConstantArray("NSConstantArray");370 371 if (class_name.IsEmpty())372 return false;373 374 if (class_name == g_NSArrayI) {375 Status error;376 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,377 ptr_size, 0, error);378 if (error.Fail())379 return false;380 } else if (class_name == g_NSConstantArray) {381 Status error;382 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 8,383 0, error);384 if (error.Fail())385 return false;386 } else if (class_name == g_NSArrayM) {387 AppleObjCRuntime *apple_runtime =388 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);389 Status error;390 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {391 value = Foundation1437::__NSArrayMSize(*process_sp, valobj_addr, error);392 } else {393 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,394 ptr_size, 0, error);395 }396 if (error.Fail())397 return false;398 } else if (class_name == g_NSArrayI_Transfer) {399 Status error;400 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,401 ptr_size, 0, error);402 if (error.Fail())403 return false;404 } else if (class_name == g_NSFrozenArrayM) {405 Status error;406 value = Foundation1436::__NSFrozenArrayMSize(*process_sp, valobj_addr, error);407 if (error.Fail())408 return false;409 } else if (class_name == g_NSArrayMLegacy) {410 Status error;411 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,412 ptr_size, 0, error);413 if (error.Fail())414 return false;415 } else if (class_name == g_NSArrayMImmutable) {416 Status error;417 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,418 ptr_size, 0, error);419 if (error.Fail())420 return false;421 } else if (class_name == g_NSArray0) {422 value = 0;423 } else if (class_name == g_NSArray1) {424 value = 1;425 } else if (class_name == g_NSArrayCF || class_name == g_NSCallStackArray) {426 // __NSCFArray and _NSCallStackArray store the number of elements as a427 // pointer-sized value at offset `2 * ptr_size`.428 Status error;429 value = process_sp->ReadUnsignedIntegerFromMemory(430 valobj_addr + 2 * ptr_size, ptr_size, 0, error);431 if (error.Fail())432 return false;433 } else {434 auto &map(NSArray_Additionals::GetAdditionalSummaries());435 auto iter = map.find(class_name), end = map.end();436 if (iter != end)437 return iter->second(valobj, stream, options);438 else439 return false;440 }441 442 llvm::StringRef prefix, suffix;443 if (Language *language = Language::FindPlugin(options.GetLanguage()))444 std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);445 446 stream << prefix;447 stream.Printf("%" PRIu64 " %s%s", value, "element", value == 1 ? "" : "s");448 stream << suffix;449 return true;450}451 452lldb_private::formatters::NSArrayMSyntheticFrontEndBase::453 NSArrayMSyntheticFrontEndBase(lldb::ValueObjectSP valobj_sp)454 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_id_type() {455 if (valobj_sp) {456 TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(457 *valobj_sp->GetExecutionContextRef().GetTargetSP());458 if (scratch_ts_sp)459 m_id_type = CompilerType(460 scratch_ts_sp->weak_from_this(),461 scratch_ts_sp->getASTContext().ObjCBuiltinIdTy.getAsOpaquePtr());462 if (valobj_sp->GetProcessSP())463 m_ptr_size = valobj_sp->GetProcessSP()->GetAddressByteSize();464 }465}466 467template <typename D32, typename D64>468lldb_private::formatters::469 GenericNSArrayMSyntheticFrontEnd<D32, D64>::470 GenericNSArrayMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)471 : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr),472 m_data_64(nullptr) {}473 474llvm::Expected<uint32_t> lldb_private::formatters::475 NSArrayMSyntheticFrontEndBase::CalculateNumChildren() {476 return GetUsedCount();477}478 479lldb::ValueObjectSP480lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex(481 uint32_t idx) {482 if (idx >= CalculateNumChildrenIgnoringErrors())483 return lldb::ValueObjectSP();484 lldb::addr_t object_at_idx = GetDataAddress();485 size_t pyhs_idx = idx;486 pyhs_idx += GetOffset();487 if (GetSize() <= pyhs_idx)488 pyhs_idx -= GetSize();489 object_at_idx += (pyhs_idx * m_ptr_size);490 StreamString idx_name;491 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);492 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,493 m_exe_ctx_ref, m_id_type);494}495 496template <typename D32, typename D64>497lldb::ChildCacheState498lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() {499 ValueObjectSP valobj_sp = m_backend.GetSP();500 m_ptr_size = 0;501 delete m_data_32;502 m_data_32 = nullptr;503 delete m_data_64;504 m_data_64 = nullptr;505 if (!valobj_sp)506 return lldb::ChildCacheState::eRefetch;507 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();508 Status error;509 error.Clear();510 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());511 if (!process_sp)512 return lldb::ChildCacheState::eRefetch;513 m_ptr_size = process_sp->GetAddressByteSize();514 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;515 if (m_ptr_size == 4) {516 m_data_32 = new D32();517 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),518 error);519 } else {520 m_data_64 = new D64();521 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),522 error);523 }524 525 return error.Success() ? lldb::ChildCacheState::eReuse526 : lldb::ChildCacheState::eRefetch;527}528 529llvm::Expected<size_t> lldb_private::formatters::NSArrayMSyntheticFrontEndBase::530 GetIndexOfChildWithName(ConstString name) {531 auto optional_idx = ExtractIndexFromString(name.AsCString());532 if (!optional_idx) {533 return llvm::createStringError("Type has no child named '%s'",534 name.AsCString());535 }536 uint32_t idx = *optional_idx;537 if (idx >= CalculateNumChildrenIgnoringErrors())538 return llvm::createStringError("Type has no child named '%s'",539 name.AsCString());540 return idx;541}542 543template <typename D32, typename D64>544lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::545 GenericNSArrayMSyntheticFrontEnd::~GenericNSArrayMSyntheticFrontEnd() {546 delete m_data_32;547 m_data_32 = nullptr;548 delete m_data_64;549 m_data_64 = nullptr;550}551 552template <typename D32, typename D64>553lldb::addr_t554lldb_private::formatters::555 GenericNSArrayMSyntheticFrontEnd<D32, D64>::556 GenericNSArrayMSyntheticFrontEnd::GetDataAddress() {557 if (!m_data_32 && !m_data_64)558 return LLDB_INVALID_ADDRESS;559 return m_data_32 ? m_data_32->_data : m_data_64->_data;560}561 562template <typename D32, typename D64>563uint64_t564lldb_private::formatters::565 GenericNSArrayMSyntheticFrontEnd<D32, D64>::566 GenericNSArrayMSyntheticFrontEnd::GetUsedCount() {567 if (!m_data_32 && !m_data_64)568 return 0;569 return m_data_32 ? m_data_32->_used : m_data_64->_used;570}571 572template <typename D32, typename D64>573uint64_t574lldb_private::formatters::575 GenericNSArrayMSyntheticFrontEnd<D32, D64>::576 GenericNSArrayMSyntheticFrontEnd::GetOffset() {577 if (!m_data_32 && !m_data_64)578 return 0;579 return m_data_32 ? m_data_32->_offset : m_data_64->_offset;580}581 582template <typename D32, typename D64>583uint64_t584lldb_private::formatters::585 GenericNSArrayMSyntheticFrontEnd<D32, D64>::586 GenericNSArrayMSyntheticFrontEnd::GetSize() {587 if (!m_data_32 && !m_data_64)588 return 0;589 return m_data_32 ? m_data_32->_size : m_data_64->_size;590}591 592template <typename D32, typename D64, bool Inline>593lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::594 GenericNSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)595 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),596 m_data_32(nullptr), m_data_64(nullptr) {597 if (valobj_sp) {598 CompilerType type = valobj_sp->GetCompilerType();599 if (type) {600 TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(601 *valobj_sp->GetExecutionContextRef().GetTargetSP());602 if (scratch_ts_sp)603 m_id_type = scratch_ts_sp->GetType(604 scratch_ts_sp->getASTContext().ObjCBuiltinIdTy);605 }606 }607}608 609template <typename D32, typename D64, bool Inline>610lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::611 GenericNSArrayISyntheticFrontEnd::~GenericNSArrayISyntheticFrontEnd() {612 delete m_data_32;613 m_data_32 = nullptr;614 delete m_data_64;615 m_data_64 = nullptr;616}617 618template <typename D32, typename D64, bool Inline>619llvm::Expected<size_t>620lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<621 D32, D64, Inline>::GetIndexOfChildWithName(ConstString name) {622 auto optional_idx = ExtractIndexFromString(name.AsCString());623 if (!optional_idx) {624 return llvm::createStringError("Type has no child named '%s'",625 name.AsCString());626 }627 uint32_t idx = *optional_idx;628 if (idx >= CalculateNumChildrenIgnoringErrors())629 return llvm::createStringError("Type has no child named '%s'",630 name.AsCString());631 return idx;632}633 634template <typename D32, typename D64, bool Inline>635llvm::Expected<uint32_t>636lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<637 D32, D64, Inline>::CalculateNumChildren() {638 return m_data_32 ? m_data_32->used : m_data_64->used;639}640 641template <typename D32, typename D64, bool Inline>642lldb::ChildCacheState643lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64,644 Inline>::Update() {645 ValueObjectSP valobj_sp = m_backend.GetSP();646 m_ptr_size = 0;647 delete m_data_32;648 m_data_32 = nullptr;649 delete m_data_64;650 m_data_64 = nullptr;651 if (!valobj_sp)652 return lldb::ChildCacheState::eRefetch;653 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();654 Status error;655 error.Clear();656 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());657 if (!process_sp)658 return lldb::ChildCacheState::eRefetch;659 m_ptr_size = process_sp->GetAddressByteSize();660 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;661 if (m_ptr_size == 4) {662 m_data_32 = new D32();663 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),664 error);665 } else {666 m_data_64 = new D64();667 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),668 error);669 }670 671 return error.Success() ? lldb::ChildCacheState::eReuse672 : lldb::ChildCacheState::eRefetch;673}674 675template <typename D32, typename D64, bool Inline>676lldb::ValueObjectSP677lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>::678 GetChildAtIndex(uint32_t idx) {679 if (idx >= CalculateNumChildrenIgnoringErrors())680 return lldb::ValueObjectSP();681 lldb::addr_t object_at_idx;682 if (Inline) {683 object_at_idx = m_backend.GetSP()->GetValueAsUnsigned(0) + m_ptr_size;684 object_at_idx += m_ptr_size == 4 ? sizeof(D32) : sizeof(D64); // skip the data header685 object_at_idx -= m_ptr_size; // we treat the last entry in the data header as the first pointer686 } else {687 object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;688 }689 object_at_idx += (idx * m_ptr_size);690 691 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();692 if (!process_sp)693 return lldb::ValueObjectSP();694 Status error;695 if (error.Fail())696 return lldb::ValueObjectSP();697 StreamString idx_name;698 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);699 return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,700 m_exe_ctx_ref, m_id_type);701}702 703lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(704 lldb::ValueObjectSP valobj_sp)705 : SyntheticChildrenFrontEnd(*valobj_sp) {}706 707llvm::Expected<size_t>708lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName(709 ConstString name) {710 return UINT32_MAX;711}712 713llvm::Expected<uint32_t>714lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() {715 return 0;716}717 718lldb::ChildCacheState719lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() {720 return lldb::ChildCacheState::eRefetch;721}722 723bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() {724 return false;725}726 727lldb::ValueObjectSP728lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex(729 uint32_t idx) {730 return lldb::ValueObjectSP();731}732 733lldb_private::formatters::NSArray1SyntheticFrontEnd::NSArray1SyntheticFrontEnd(734 lldb::ValueObjectSP valobj_sp)735 : SyntheticChildrenFrontEnd(*valobj_sp.get()) {}736 737llvm::Expected<size_t>738lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName(739 ConstString name) {740 static const ConstString g_zero("[0]");741 742 if (name == g_zero)743 return 0;744 745 return UINT32_MAX;746}747 748llvm::Expected<uint32_t>749lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() {750 return 1;751}752 753lldb::ChildCacheState754lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() {755 return lldb::ChildCacheState::eRefetch;756}757 758lldb::ValueObjectSP759lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex(760 uint32_t idx) {761 static const ConstString g_zero("[0]");762 763 if (idx == 0) {764 TypeSystemClangSP scratch_ts_sp =765 ScratchTypeSystemClang::GetForTarget(*m_backend.GetTargetSP());766 if (scratch_ts_sp) {767 CompilerType id_type(scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID));768 return m_backend.GetSyntheticChildAtOffset(769 m_backend.GetProcessSP()->GetAddressByteSize(), id_type, true,770 g_zero);771 }772 }773 return lldb::ValueObjectSP();774}775 776SyntheticChildrenFrontEnd *777lldb_private::formatters::NSArraySyntheticFrontEndCreator(778 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {779 if (!valobj_sp)780 return nullptr;781 782 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());783 if (!process_sp)784 return nullptr;785 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(786 ObjCLanguageRuntime::Get(*process_sp));787 if (!runtime)788 return nullptr;789 790 CompilerType valobj_type(valobj_sp->GetCompilerType());791 Flags flags(valobj_type.GetTypeInfo());792 793 if (flags.IsClear(eTypeIsPointer)) {794 Status error;795 valobj_sp = valobj_sp->AddressOf(error);796 if (error.Fail() || !valobj_sp)797 return nullptr;798 }799 800 ObjCLanguageRuntime::ClassDescriptorSP descriptor(801 runtime->GetClassDescriptor(*valobj_sp));802 803 if (!descriptor || !descriptor->IsValid())804 return nullptr;805 806 ConstString class_name(descriptor->GetClassName());807 808 static const ConstString g_NSArrayI("__NSArrayI");809 static const ConstString g_NSConstantArray("NSConstantArray");810 static const ConstString g_NSArrayI_Transfer("__NSArrayI_Transfer");811 static const ConstString g_NSFrozenArrayM("__NSFrozenArrayM");812 static const ConstString g_NSArrayM("__NSArrayM");813 static const ConstString g_NSArray0("__NSArray0");814 static const ConstString g_NSArray1("__NSSingleObjectArrayI");815 static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");816 static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");817 static const ConstString g_NSCallStackArray("_NSCallStackArray");818 819 if (class_name.IsEmpty())820 return nullptr;821 822 if (class_name == g_NSArrayI) {823 if (runtime->GetFoundationVersion() >= 1436)824 return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp));825 if (runtime->GetFoundationVersion() >= 1430)826 return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp));827 return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp));828 } else if (class_name == g_NSArrayI_Transfer) {829 return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp));830 } else if (class_name == g_NSConstantArray) {831 return new ConstantArray::NSConstantArraySyntheticFrontEnd(valobj_sp);832 } else if (class_name == g_NSFrozenArrayM) {833 return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp));834 } else if (class_name == g_NSArray0) {835 return (new NSArray0SyntheticFrontEnd(valobj_sp));836 } else if (class_name == g_NSArray1) {837 return (new NSArray1SyntheticFrontEnd(valobj_sp));838 } else if (class_name == g_NSArrayM) {839 if (runtime->GetFoundationVersion() >= 1437)840 return (new Foundation1437::NSArrayMSyntheticFrontEnd(valobj_sp));841 if (runtime->GetFoundationVersion() >= 1428)842 return (new Foundation1428::NSArrayMSyntheticFrontEnd(valobj_sp));843 if (runtime->GetFoundationVersion() >= 1100)844 return (new Foundation1010::NSArrayMSyntheticFrontEnd(valobj_sp));845 } else if (class_name == g_NSCallStackArray) {846 return (new CallStackArray::NSCallStackArraySyntheticFrontEnd(valobj_sp));847 } else {848 auto &map(NSArray_Additionals::GetAdditionalSynthetics());849 auto iter = map.find(class_name), end = map.end();850 if (iter != end)851 return iter->second(synth, valobj_sp);852 }853 854 return nullptr;855}856