11#include "clang/AST/DeclCXX.h"
40 return class_name.
GetStringRef().starts_with(m_prefix.GetStringRef());
48 return (class_name == m_name);
74 static constexpr llvm::StringLiteral g_lldb_autogen_nspair(
"__lldb_autogen_nspair");
76 compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(g_lldb_autogen_nspair);
79 compiler_type = scratch_ts_sp->CreateRecordType(
81 g_lldb_autogen_nspair, llvm::to_underlying(clang::TagTypeKind::Struct),
112 bool MightHaveChildren()
override;
114 size_t GetIndexOfChildWithName(
ConstString name)
override;
134 uint8_t m_ptr_size = 8;
153 bool MightHaveChildren()
override;
155 size_t GetIndexOfChildWithName(
ConstString name)
override;
160 uint8_t m_ptr_size = 8;
162 unsigned int m_size = 0;
185 bool MightHaveChildren()
override;
187 size_t GetIndexOfChildWithName(
ConstString name)
override;
197 uint8_t m_ptr_size = 8;
218 bool MightHaveChildren()
override;
220 size_t GetIndexOfChildWithName(
ConstString name)
override;
226template <
typename D32,
typename D64>
239 bool MightHaveChildren()
override;
241 size_t GetIndexOfChildWithName(
ConstString name)
override;
251 uint8_t m_ptr_size = 8;
259namespace Foundation1100 {
272 bool MightHaveChildren()
override;
274 size_t GetIndexOfChildWithName(
ConstString name)
override;
302 uint8_t m_ptr_size = 8;
311namespace Foundation1428 {
313 struct DataDescriptor_32 {
318 uint64_t GetSize() {
return _size; }
321 struct DataDescriptor_64 {
326 uint64_t GetSize() {
return _size; }
334namespace Foundation1437 {
336 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
337 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
338 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
339 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
340 111638519, 180634607, 292272623, 472907251
347 struct DataDescriptor_32 {
355 return (
_szidx) >= NSDictionaryNumSizeBuckets ?
356 0 : NSDictionaryCapacities[
_szidx];
360 struct DataDescriptor_64 {
377 template <
typename DD>
383 DD descriptor = DD();
384 process.
ReadMemory(start_of_descriptor, &descriptor,
sizeof(descriptor),
389 return descriptor._used;
396 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
399 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
408template <
bool name_entries>
411 static constexpr llvm::StringLiteral g_TypeHint(
"NSDictionary");
424 if (!descriptor || !descriptor->IsValid())
427 uint32_t ptr_size = process_sp->GetAddressByteSize();
428 bool is_64bit = (ptr_size == 8);
437 ConstString class_name(descriptor->GetClassName());
439 static const ConstString g_DictionaryI(
"__NSDictionaryI");
440 static const ConstString g_DictionaryM(
"__NSDictionaryM");
441 static const ConstString g_DictionaryMLegacy(
"__NSDictionaryM_Legacy");
442 static const ConstString g_DictionaryMImmutable(
"__NSDictionaryM_Immutable");
443 static const ConstString g_DictionaryMFrozen(
"__NSFrozenDictionaryM");
444 static const ConstString g_Dictionary1(
"__NSSingleEntryDictionaryI");
445 static const ConstString g_Dictionary0(
"__NSDictionary0");
446 static const ConstString g_DictionaryCF(
"__CFDictionary");
447 static const ConstString g_DictionaryNSCF(
"__NSCFDictionary");
448 static const ConstString g_DictionaryCFRef(
"CFDictionaryRef");
449 static const ConstString g_ConstantDictionary(
"NSConstantDictionary");
454 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
456 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
461 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
462 }
else if (class_name == g_ConstantDictionary) {
464 value = process_sp->ReadUnsignedIntegerFromMemory(
465 valobj_addr + 2 * ptr_size, ptr_size, 0,
error);
468 }
else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
469 class_name == g_DictionaryMFrozen) {
471 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
477 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
479 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
483 }
else if (class_name == g_Dictionary1) {
485 }
else if (class_name == g_Dictionary0) {
487 }
else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
488 class_name == g_DictionaryCFRef) {
491 if (!cfbh.
Update(valobj_addr, exe_ctx))
496 for (
auto &candidate : map) {
497 if (candidate.first && candidate.first->Match(class_name))
498 return candidate.second(valobj, stream, options);
503 llvm::StringRef prefix, suffix;
505 std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
508 stream.
Printf(
"%" PRIu64
" %s%s", value,
"key/value pair",
509 value == 1 ?
"" :
"s");
528 if (flags.
IsClear(eTypeIsPointer)) {
530 valobj_sp = valobj_sp->AddressOf(
error);
531 if (
error.Fail() || !valobj_sp)
538 if (!descriptor || !descriptor->IsValid())
541 ConstString class_name(descriptor->GetClassName());
543 static const ConstString g_DictionaryI(
"__NSDictionaryI");
544 static const ConstString g_DictionaryM(
"__NSDictionaryM");
545 static const ConstString g_Dictionary1(
"__NSSingleEntryDictionaryI");
546 static const ConstString g_DictionaryImmutable(
"__NSDictionaryM_Immutable");
547 static const ConstString g_DictionaryMFrozen(
"__NSFrozenDictionaryM");
548 static const ConstString g_DictionaryMLegacy(
"__NSDictionaryM_Legacy");
549 static const ConstString g_Dictionary0(
"__NSDictionary0");
550 static const ConstString g_DictionaryCF(
"__CFDictionary");
551 static const ConstString g_DictionaryNSCF(
"__NSCFDictionary");
552 static const ConstString g_DictionaryCFRef(
"CFDictionaryRef");
553 static const ConstString g_ConstantDictionary(
"NSConstantDictionary");
558 if (class_name == g_DictionaryI) {
560 }
else if (class_name == g_ConstantDictionary) {
562 }
else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {
570 }
else if (class_name == g_DictionaryMLegacy) {
572 }
else if (class_name == g_Dictionary1) {
574 }
else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
575 class_name == g_DictionaryCFRef) {
579 for (
auto &candidate : map) {
580 if (candidate.first && candidate.first->Match((class_name)))
581 return candidate.second(synth, valobj_sp);
604 if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
611 if (!m_data_32 && !m_data_64)
613 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
627 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
633 m_ptr_size = process_sp->GetAddressByteSize();
634 m_order = process_sp->GetByteOrder();
635 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
636 if (m_ptr_size == 4) {
647 m_data_ptr = data_location + m_ptr_size;
659 uint32_t num_children = CalculateNumChildrenIgnoringErrors();
661 if (idx >= num_children)
664 if (m_children.empty()) {
669 uint32_t test_idx = 0;
671 while (tries < num_children) {
672 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
673 val_at_idx = key_at_idx + m_ptr_size;
674 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
678 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx,
error);
681 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx,
error);
687 if (!key_at_idx || !val_at_idx)
694 m_children.push_back(descriptor);
698 if (idx >= m_children.size())
703 if (!m_pair_type.IsValid()) {
704 TargetSP target_sp(m_backend.GetTargetSP());
709 if (!m_pair_type.IsValid())
714 if (m_ptr_size == 8) {
715 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
717 *(data_ptr + 1) = dict_item.
val_ptr;
719 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
721 *(data_ptr + 1) = dict_item.
val_ptr;
725 idx_name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
728 m_exe_ctx_ref, m_pair_type);
742 if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
749 if (!m_hashtable.IsValid())
751 return m_hashtable.GetCount();
761 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
766 m_ptr_size = process_sp->GetAddressByteSize();
767 m_order = process_sp->GetByteOrder();
768 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref)
782 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
784 const uint32_t num_children = CalculateNumChildrenIgnoringErrors();
786 if (idx >= num_children)
789 if (m_children.empty()) {
790 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
798 uint32_t test_idx = 0;
804 while (tries < num_children) {
805 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
806 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
808 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx,
error);
811 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx,
error);
817 if (!key_at_idx || !val_at_idx)
824 m_children.push_back(descriptor);
828 if (idx >= m_children.size())
833 if (!m_pair_type.IsValid()) {
834 TargetSP target_sp(m_backend.GetTargetSP());
839 if (!m_pair_type.IsValid())
844 switch (m_ptr_size) {
848 uint32_t *data_ptr =
reinterpret_cast<uint32_t *
>(buffer_sp->GetBytes());
850 *(data_ptr + 1) = dict_item.
val_ptr;
853 uint64_t *data_ptr =
reinterpret_cast<uint64_t *
>(buffer_sp->GetBytes());
855 *(data_ptr + 1) = dict_item.
val_ptr;
858 lldbassert(
false &&
"pointer size is not 4 nor 8");
862 idx_name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
865 m_exe_ctx_ref, m_pair_type);
878 if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
893 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
899 m_ptr_size = process_sp->GetAddressByteSize();
900 m_order = process_sp->GetByteOrder();
901 uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);
902 m_size = process_sp->ReadUnsignedIntegerFromMemory(
903 valobj_addr + 2 * m_ptr_size, m_ptr_size, 0,
error);
907 process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size,
error);
911 process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size,
error);
924 uint32_t num_children = CalculateNumChildrenIgnoringErrors();
926 if (idx >= num_children)
929 if (m_children.empty()) {
932 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
936 for (
unsigned int child = 0; child < num_children; ++child) {
938 key_at_idx = process_sp->ReadPointerFromMemory(
939 m_keys_ptr + child * m_ptr_size,
error);
942 val_at_idx = process_sp->ReadPointerFromMemory(
943 m_objects_ptr + child * m_ptr_size,
error);
948 m_children.push_back(descriptor);
952 if (idx >= m_children.size())
957 if (!m_pair_type.IsValid()) {
958 TargetSP target_sp(m_backend.GetTargetSP());
963 if (!m_pair_type.IsValid())
968 if (m_ptr_size == 8) {
969 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
971 *(data_ptr + 1) = dict_item.
val_ptr;
973 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
975 *(data_ptr + 1) = dict_item.
val_ptr;
979 idx_name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
982 m_exe_ctx_ref, m_pair_type);
1022 auto process_sp(m_backend.GetProcessSP());
1026 auto ptr_size = process_sp->GetAddressByteSize();
1046 if (ptr_size == 8) {
1047 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1048 *data_ptr = key_at_idx;
1049 *(data_ptr + 1) = value_at_idx;
1051 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1052 *data_ptr = key_at_idx;
1053 *(data_ptr + 1) = value_at_idx;
1056 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
1057 m_pair = CreateValueObjectFromData(
1058 "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
1063template <
typename D32,
typename D64>
1067 m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {}
1069template <
typename D32,
typename D64>
1074 m_data_32 =
nullptr;
1076 m_data_64 =
nullptr;
1079template <
typename D32,
typename D64>
1084 if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
1089template <
typename D32,
typename D64>
1090llvm::Expected<uint32_t>
1093 if (!m_data_32 && !m_data_64)
1095 return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used);
1098template <
typename D32,
typename D64>
1106 m_data_32 =
nullptr;
1108 m_data_64 =
nullptr;
1111 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1117 m_ptr_size = process_sp->GetAddressByteSize();
1118 m_order = process_sp->GetByteOrder();
1119 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1120 if (m_ptr_size == 4) {
1121 m_data_32 =
new D32();
1122 process_sp->ReadMemory(data_location, m_data_32,
sizeof(D32),
1125 m_data_64 =
new D64();
1126 process_sp->ReadMemory(data_location, m_data_64,
sizeof(D64),
1134template <
typename D32,
typename D64>
1141template <
typename D32,
typename D64>
1144 D32, D64>::GetChildAtIndex(uint32_t idx) {
1148 uint32_t size = m_data_32->GetSize();
1149 m_keys_ptr = m_data_32->_buffer;
1150 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
1152 uint32_t size = m_data_64->GetSize();
1153 m_keys_ptr = m_data_64->_buffer;
1154 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
1157 uint32_t num_children = CalculateNumChildrenIgnoringErrors();
1159 if (idx >= num_children)
1162 if (m_children.empty()) {
1167 uint32_t test_idx = 0;
1169 while (tries < num_children) {
1170 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1171 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1173 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1177 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx,
error);
1180 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx,
error);
1186 if (!key_at_idx || !val_at_idx)
1193 m_children.push_back(descriptor);
1197 if (idx >= m_children.size())
1202 if (!m_pair_type.IsValid()) {
1203 TargetSP target_sp(m_backend.GetTargetSP());
1208 if (!m_pair_type.IsValid())
1213 if (m_ptr_size == 8) {
1214 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1215 *data_ptr = dict_item.
key_ptr;
1216 *(data_ptr + 1) = dict_item.
val_ptr;
1218 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1219 *data_ptr = dict_item.
key_ptr;
1220 *(data_ptr + 1) = dict_item.
val_ptr;
1224 idx_name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
1227 m_exe_ctx_ref, m_pair_type);
1239 m_data_32 =
nullptr;
1241 m_data_64 =
nullptr;
1249 if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors())
1256 if (!m_data_32 && !m_data_64)
1258 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1267 m_data_32 =
nullptr;
1269 m_data_64 =
nullptr;
1272 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1278 m_ptr_size = process_sp->GetAddressByteSize();
1279 m_order = process_sp->GetByteOrder();
1280 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1281 if (m_ptr_size == 4) {
1305 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1307 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1309 uint32_t num_children = CalculateNumChildrenIgnoringErrors();
1311 if (idx >= num_children)
1314 if (m_children.empty()) {
1319 uint32_t test_idx = 0;
1321 while (tries < num_children) {
1322 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1323 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1325 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1329 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx,
error);
1332 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx,
error);
1338 if (!key_at_idx || !val_at_idx)
1345 m_children.push_back(descriptor);
1349 if (idx >= m_children.size())
1354 if (!m_pair_type.IsValid()) {
1355 TargetSP target_sp(m_backend.GetTargetSP());
1360 if (!m_pair_type.IsValid())
1365 if (m_ptr_size == 8) {
1366 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1367 *data_ptr = dict_item.
key_ptr;
1368 *(data_ptr + 1) = dict_item.
val_ptr;
1370 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1371 *data_ptr = dict_item.
key_ptr;
1372 *(data_ptr + 1) = dict_item.
val_ptr;
1376 idx_name.
Printf(
"[%" PRIu64
"]", (uint64_t)idx);
1379 m_exe_ctx_ref, m_pair_type);
static llvm::raw_ostream & error(Stream &strm)
static CompilerType GetLLDBNSPairType(TargetSP target_sp)
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
uint32_t GetFoundationVersion()
bool Update(lldb::addr_t addr, ExecutionContextRef exe_ctx_rf)
std::function< SyntheticChildrenFrontEnd *(CXXSyntheticChildren *, lldb::ValueObjectSP)> CreateFrontEndCallback
Generic representation of a type in a programming language.
uint32_t GetTypeInfo(CompilerType *pointee_or_element_compiler_type=nullptr) const
A uniqued constant string class.
bool IsEmpty() const
Test for empty string.
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
const char * GetCString() const
Get the string value as a C string.
A subclass of DataBuffer that stores a data buffer on the heap.
Execution context objects refer to objects in the execution of the program that is being debugged.
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool IsClear(ValueType bit) const
Test a single flag bit to see if it is clear (zero).
static Language * FindPlugin(lldb::LanguageType language)
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value)
static ObjCLanguageRuntime * Get(Process &process)
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
A plug-in interface definition class for debugging a process.
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
uint32_t GetAddressByteSize() const
static lldb::TypeSystemClangSP GetForTarget(Target &target, std::optional< IsolatedASTKind > ast_kind=DefaultAST, bool create_on_demand=true)
Returns the scratch TypeSystemClang for the given target.
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
lldb::LanguageType GetLanguage() const
static clang::FieldDecl * AddFieldToRecordType(const CompilerType &type, llvm::StringRef name, const CompilerType &field_type, lldb::AccessType access, uint32_t bitfield_bit_size)
static bool CompleteTagDeclarationDefinition(const CompilerType &type)
static bool StartTagDeclarationDefinition(const CompilerType &type)
lldb::ProcessSP GetProcessSP() const
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
@ eReuse
Children did not change and don't need to be recomputed; re-use what we computed the last time we cal...
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
@ eLanguageTypeC
Non-standardized C, such as K&R.
std::shared_ptr< lldb_private::Process > ProcessSP
ByteOrder
Byte ordering definitions.
std::shared_ptr< lldb_private::TypeSystemClang > TypeSystemClangSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
std::shared_ptr< lldb_private::Target > TargetSP