LLDB mainline
NSDictionary.cpp
Go to the documentation of this file.
1//===-- NSDictionary.cpp --------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <mutex>
10
11#include "clang/AST/DeclCXX.h"
12
13#include "CFBasicHash.h"
14#include "NSDictionary.h"
15
18
24#include "lldb/Target/Target.h"
26#include "lldb/Utility/Endian.h"
27#include "lldb/Utility/Status.h"
28#include "lldb/Utility/Stream.h"
29
30using namespace lldb;
31using namespace lldb_private;
32using namespace lldb_private::formatters;
33
36 : m_prefix(p) {}
37
39 ConstString class_name) {
40 return class_name.GetStringRef().startswith(m_prefix.GetStringRef());
41}
42
44 : m_name(n) {}
45
47 ConstString class_name) {
48 return (class_name == m_name);
49}
50
55 return g_map;
56}
57
62 g_map;
63 return g_map;
64}
65
66static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
67 CompilerType compiler_type;
68
69 TypeSystemClangSP scratch_ts_sp =
71
72 if (scratch_ts_sp) {
73 ConstString g_lldb_autogen_nspair("__lldb_autogen_nspair");
74
75 compiler_type = scratch_ts_sp->GetTypeForIdentifier<clang::CXXRecordDecl>(
76 g_lldb_autogen_nspair);
77
78 if (!compiler_type) {
79 compiler_type = scratch_ts_sp->CreateRecordType(
81 g_lldb_autogen_nspair.GetCString(), clang::TTK_Struct,
83
84 if (compiler_type) {
86 CompilerType id_compiler_type =
87 scratch_ts_sp->GetBasicType(eBasicTypeObjCID);
89 compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
91 compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
93 }
94 }
95 }
96 return compiler_type;
97}
98
99namespace lldb_private {
100namespace formatters {
102public:
103 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
104
106
107 size_t CalculateNumChildren() override;
108
109 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
110
111 bool Update() override;
112
113 bool MightHaveChildren() override;
114
115 size_t GetIndexOfChildWithName(ConstString name) override;
116
117private:
121 };
122
124 uint64_t _used : 58;
126 };
127
131 lldb::ValueObjectSP valobj_sp;
132 };
133
135 uint8_t m_ptr_size = 8;
137 DataDescriptor_32 *m_data_32 = nullptr;
138 DataDescriptor_64 *m_data_64 = nullptr;
141 std::vector<DictionaryItemDescriptor> m_children;
142};
143
145public:
146 NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
147
148 size_t CalculateNumChildren() override;
149
150 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
151
152 bool Update() override;
153
154 bool MightHaveChildren() override;
155
156 size_t GetIndexOfChildWithName(ConstString name) override;
157
158private:
161 uint8_t m_ptr_size = 8;
163 unsigned int m_size = 0;
166
170 lldb::ValueObjectSP valobj_sp;
171 };
172
173 std::vector<DictionaryItemDescriptor> m_children;
174};
175
177public:
178 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
179
180 size_t CalculateNumChildren() override;
181
182 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
183
184 bool Update() override;
185
186 bool MightHaveChildren() override;
187
188 size_t GetIndexOfChildWithName(ConstString name) override;
189
190private:
194 lldb::ValueObjectSP valobj_sp;
195 };
196
198 uint8_t m_ptr_size = 8;
200
202
204 std::vector<DictionaryItemDescriptor> m_children;
205};
206
208public:
209 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
210
212
213 size_t CalculateNumChildren() override;
214
215 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
216
217 bool Update() override;
218
219 bool MightHaveChildren() override;
220
221 size_t GetIndexOfChildWithName(ConstString name) override;
222
223private:
224 ValueObjectSP m_pair;
225};
226
227template <typename D32, typename D64>
229public:
230 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
231
233
234 size_t CalculateNumChildren() override;
235
236 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
237
238 bool Update() override;
239
240 bool MightHaveChildren() override;
241
242 size_t GetIndexOfChildWithName(ConstString name) override;
243
244private:
248 lldb::ValueObjectSP valobj_sp;
249 };
250
252 uint8_t m_ptr_size = 8;
257 std::vector<DictionaryItemDescriptor> m_children;
258};
259
260namespace Foundation1100 {
262 public:
263 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
264
266
267 size_t CalculateNumChildren() override;
268
269 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
270
271 bool Update() override;
272
273 bool MightHaveChildren() override;
274
275 size_t GetIndexOfChildWithName(ConstString name) override;
276
277 private:
285 };
286
288 uint64_t _used : 58;
290 uint64_t _size;
291 uint64_t _mutations;
292 uint64_t _objs_addr;
293 uint64_t _keys_addr;
294 };
295
299 lldb::ValueObjectSP valobj_sp;
300 };
301
303 uint8_t m_ptr_size = 8;
305 DataDescriptor_32 *m_data_32 = nullptr;
306 DataDescriptor_64 *m_data_64 = nullptr;
308 std::vector<DictionaryItemDescriptor> m_children;
309 };
310}
311
312namespace Foundation1428 {
313 namespace {
314 struct DataDescriptor_32 {
319 uint64_t GetSize() { return _size; }
320 };
321
322 struct DataDescriptor_64 {
323 uint64_t _used : 58;
324 uint32_t _kvo : 1;
325 uint64_t _size;
326 uint64_t _buffer;
327 uint64_t GetSize() { return _size; }
328 };
329 }
330
333}
334
335namespace Foundation1437 {
336 static const uint64_t NSDictionaryCapacities[] = {
337 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
338 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
339 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
340 6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
341 111638519, 180634607, 292272623, 472907251
342 };
343
344 static const size_t NSDictionaryNumSizeBuckets =
345 sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
346
347 namespace {
348 struct DataDescriptor_32 {
351 uint32_t _used : 25;
352 uint32_t _kvo : 1;
354
355 uint64_t GetSize() {
356 return (_szidx) >= NSDictionaryNumSizeBuckets ?
357 0 : NSDictionaryCapacities[_szidx];
358 }
359 };
360
361 struct DataDescriptor_64 {
362 uint64_t _buffer;
364 uint32_t _used : 25;
365 uint32_t _kvo : 1;
366 uint32_t _szidx : 6;
367
368 uint64_t GetSize() {
371 }
372 };
373 } // namespace
374
377
378 template <typename DD>
379 uint64_t
381 lldb::addr_t valobj_addr, Status &error) {
382 const lldb::addr_t start_of_descriptor =
383 valobj_addr + process.GetAddressByteSize();
384 DD descriptor = DD();
385 process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
386 error);
387 if (error.Fail()) {
388 return 0;
389 }
390 return descriptor._used;
391 }
392
393 uint64_t
395 Status &error) {
396 if (process.GetAddressByteSize() == 4) {
397 return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
398 error);
399 } else {
400 return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
401 error);
402 }
403 }
404
405}
406} // namespace formatters
407} // namespace lldb_private
408
409template <bool name_entries>
411 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
412 static ConstString g_TypeHint("NSDictionary");
413 ProcessSP process_sp = valobj.GetProcessSP();
414 if (!process_sp)
415 return false;
416
417 ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
418
419 if (!runtime)
420 return false;
421
423 runtime->GetNonKVOClassDescriptor(valobj));
424
425 if (!descriptor || !descriptor->IsValid())
426 return false;
427
428 uint32_t ptr_size = process_sp->GetAddressByteSize();
429 bool is_64bit = (ptr_size == 8);
430
431 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
432
433 if (!valobj_addr)
434 return false;
435
436 uint64_t value = 0;
437
438 ConstString class_name(descriptor->GetClassName());
439
440 static const ConstString g_DictionaryI("__NSDictionaryI");
441 static const ConstString g_DictionaryM("__NSDictionaryM");
442 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
443 static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
444 static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
445 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
446 static const ConstString g_Dictionary0("__NSDictionary0");
447 static const ConstString g_DictionaryCF("__CFDictionary");
448 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
449 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
450 static const ConstString g_ConstantDictionary("NSConstantDictionary");
451
452 if (class_name.IsEmpty())
453 return false;
454
455 if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
457 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
458 ptr_size, 0, error);
459 if (error.Fail())
460 return false;
461
462 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
463 } else if (class_name == g_ConstantDictionary) {
465 value = process_sp->ReadUnsignedIntegerFromMemory(
466 valobj_addr + 2 * ptr_size, ptr_size, 0, error);
467 if (error.Fail())
468 return false;
469 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
470 class_name == g_DictionaryMFrozen) {
471 AppleObjCRuntime *apple_runtime =
472 llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
474 if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
475 value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
476 error);
477 } else {
478 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
479 ptr_size, 0, error);
480 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
481 }
482 if (error.Fail())
483 return false;
484 } else if (class_name == g_Dictionary1) {
485 value = 1;
486 } else if (class_name == g_Dictionary0) {
487 value = 0;
488 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
489 class_name == g_DictionaryCFRef) {
490 ExecutionContext exe_ctx(process_sp);
491 CFBasicHash cfbh;
492 if (!cfbh.Update(valobj_addr, exe_ctx))
493 return false;
494 value = cfbh.GetCount();
495 } else {
497 for (auto &candidate : map) {
498 if (candidate.first && candidate.first->Match(class_name))
499 return candidate.second(valobj, stream, options);
500 }
501 return false;
502 }
503
504 std::string prefix, suffix;
505 if (Language *language = Language::FindPlugin(options.GetLanguage())) {
506 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
507 suffix)) {
508 prefix.clear();
509 suffix.clear();
510 }
511 }
512
513 stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair",
514 value == 1 ? "" : "s", suffix.c_str());
515 return true;
516}
517
520 CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
521 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
522 if (!process_sp)
523 return nullptr;
524 AppleObjCRuntime *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
525 ObjCLanguageRuntime::Get(*process_sp));
526 if (!runtime)
527 return nullptr;
528
529 CompilerType valobj_type(valobj_sp->GetCompilerType());
530 Flags flags(valobj_type.GetTypeInfo());
531
532 if (flags.IsClear(eTypeIsPointer)) {
534 valobj_sp = valobj_sp->AddressOf(error);
535 if (error.Fail() || !valobj_sp)
536 return nullptr;
537 }
538
540 runtime->GetClassDescriptor(*valobj_sp));
541
542 if (!descriptor || !descriptor->IsValid())
543 return nullptr;
544
545 ConstString class_name(descriptor->GetClassName());
546
547 static const ConstString g_DictionaryI("__NSDictionaryI");
548 static const ConstString g_DictionaryM("__NSDictionaryM");
549 static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
550 static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
551 static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM");
552 static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
553 static const ConstString g_Dictionary0("__NSDictionary0");
554 static const ConstString g_DictionaryCF("__CFDictionary");
555 static const ConstString g_DictionaryNSCF("__NSCFDictionary");
556 static const ConstString g_DictionaryCFRef("CFDictionaryRef");
557 static const ConstString g_ConstantDictionary("NSConstantDictionary");
558
559 if (class_name.IsEmpty())
560 return nullptr;
561
562 if (class_name == g_DictionaryI) {
563 return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
564 } else if (class_name == g_ConstantDictionary) {
565 return (new NSConstantDictionarySyntheticFrontEnd(valobj_sp));
566 } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) {
567 if (runtime->GetFoundationVersion() >= 1437) {
569 } else if (runtime->GetFoundationVersion() >= 1428) {
571 } else {
573 }
574 } else if (class_name == g_DictionaryMLegacy) {
576 } else if (class_name == g_Dictionary1) {
577 return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
578 } else if (class_name == g_DictionaryCF || class_name == g_DictionaryNSCF ||
579 class_name == g_DictionaryCFRef) {
580 return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
581 } else {
583 for (auto &candidate : map) {
584 if (candidate.first && candidate.first->Match((class_name)))
585 return candidate.second(synth, valobj_sp);
586 }
587 }
588
589 return nullptr;
590}
591
593 NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
594 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
595
598 delete m_data_32;
599 m_data_32 = nullptr;
600 delete m_data_64;
601 m_data_64 = nullptr;
602}
603
606 const char *item_name = name.GetCString();
607 uint32_t idx = ExtractIndexFromString(item_name);
608 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
609 return UINT32_MAX;
610 return idx;
611}
612
615 if (!m_data_32 && !m_data_64)
616 return 0;
617 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
618}
619
621 m_children.clear();
622 delete m_data_32;
623 m_data_32 = nullptr;
624 delete m_data_64;
625 m_data_64 = nullptr;
626 m_ptr_size = 0;
627 ValueObjectSP valobj_sp = m_backend.GetSP();
628 if (!valobj_sp)
629 return false;
630 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
632 error.Clear();
633 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
634 if (!process_sp)
635 return false;
636 m_ptr_size = process_sp->GetAddressByteSize();
637 m_order = process_sp->GetByteOrder();
638 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
639 if (m_ptr_size == 4) {
640 m_data_32 = new DataDescriptor_32();
641 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
642 error);
643 } else {
644 m_data_64 = new DataDescriptor_64();
645 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
646 error);
647 }
648 if (error.Fail())
649 return false;
650 m_data_ptr = data_location + m_ptr_size;
651 return false;
652}
653
656 return true;
657}
658
659lldb::ValueObjectSP
661 size_t idx) {
662 uint32_t num_children = CalculateNumChildren();
663
664 if (idx >= num_children)
665 return lldb::ValueObjectSP();
666
667 if (m_children.empty()) {
668 // do the scan phase
669 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
670
671 uint32_t tries = 0;
672 uint32_t test_idx = 0;
673
674 while (tries < num_children) {
675 key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
676 val_at_idx = key_at_idx + m_ptr_size;
677 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
678 if (!process_sp)
679 return lldb::ValueObjectSP();
681 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
682 if (error.Fail())
683 return lldb::ValueObjectSP();
684 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
685 if (error.Fail())
686 return lldb::ValueObjectSP();
687
688 test_idx++;
689
690 if (!key_at_idx || !val_at_idx)
691 continue;
692 tries++;
693
694 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
695 lldb::ValueObjectSP()};
696
697 m_children.push_back(descriptor);
698 }
699 }
700
701 if (idx >= m_children.size()) // should never happen
702 return lldb::ValueObjectSP();
703
704 DictionaryItemDescriptor &dict_item = m_children[idx];
705 if (!dict_item.valobj_sp) {
706 if (!m_pair_type.IsValid()) {
707 TargetSP target_sp(m_backend.GetTargetSP());
708 if (!target_sp)
709 return ValueObjectSP();
710 m_pair_type = GetLLDBNSPairType(target_sp);
711 }
712 if (!m_pair_type.IsValid())
713 return ValueObjectSP();
714
715 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
716
717 if (m_ptr_size == 8) {
718 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
719 *data_ptr = dict_item.key_ptr;
720 *(data_ptr + 1) = dict_item.val_ptr;
721 } else {
722 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
723 *data_ptr = dict_item.key_ptr;
724 *(data_ptr + 1) = dict_item.val_ptr;
725 }
726
727 StreamString idx_name;
728 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
729 DataExtractor data(buffer_sp, m_order, m_ptr_size);
730 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
731 m_exe_ctx_ref, m_pair_type);
732 }
733 return dict_item.valobj_sp;
734}
735
737 NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
738 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_hashtable(),
739 m_pair_type() {}
740
743 const char *item_name = name.GetCString();
744 const uint32_t idx = ExtractIndexFromString(item_name);
745 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
746 return UINT32_MAX;
747 return idx;
748}
749
752 if (!m_hashtable.IsValid())
753 return 0;
754 return m_hashtable.GetCount();
755}
756
758 m_children.clear();
759 ValueObjectSP valobj_sp = m_backend.GetSP();
760 m_ptr_size = 0;
761 if (!valobj_sp)
762 return false;
763 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
764
765 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
766 if (!process_sp)
767 return false;
768 m_ptr_size = process_sp->GetAddressByteSize();
769 m_order = process_sp->GetByteOrder();
770 return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
771}
772
775 return true;
776}
777
778lldb::ValueObjectSP
780 size_t idx) {
781 lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
782 lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
783
784 const uint32_t num_children = CalculateNumChildren();
785
786 if (idx >= num_children)
787 return lldb::ValueObjectSP();
788
789 if (m_children.empty()) {
790 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
791 if (!process_sp)
792 return lldb::ValueObjectSP();
793
795 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
796
797 uint32_t tries = 0;
798 uint32_t test_idx = 0;
799
800 // Iterate over inferior memory, reading key/value pointers by shifting each
801 // cursor by test_index * m_ptr_size. Returns an empty ValueObject if a read
802 // fails, otherwise, continue until the number of tries matches the number
803 // of childen.
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);
807
808 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
809 if (error.Fail())
810 return lldb::ValueObjectSP();
811 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
812 if (error.Fail())
813 return lldb::ValueObjectSP();
814
815 test_idx++;
816
817 if (!key_at_idx || !val_at_idx)
818 continue;
819 tries++;
820
821 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
822 lldb::ValueObjectSP()};
823
824 m_children.push_back(descriptor);
825 }
826 }
827
828 if (idx >= m_children.size()) // should never happen
829 return lldb::ValueObjectSP();
830
831 DictionaryItemDescriptor &dict_item = m_children[idx];
832 if (!dict_item.valobj_sp) {
833 if (!m_pair_type.IsValid()) {
834 TargetSP target_sp(m_backend.GetTargetSP());
835 if (!target_sp)
836 return ValueObjectSP();
837 m_pair_type = GetLLDBNSPairType(target_sp);
838 }
839 if (!m_pair_type.IsValid())
840 return ValueObjectSP();
841
842 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
843
844 switch (m_ptr_size) {
845 case 0: // architecture has no clue - fail
846 return lldb::ValueObjectSP();
847 case 4: {
848 uint32_t *data_ptr = reinterpret_cast<uint32_t *>(buffer_sp->GetBytes());
849 *data_ptr = dict_item.key_ptr;
850 *(data_ptr + 1) = dict_item.val_ptr;
851 } break;
852 case 8: {
853 uint64_t *data_ptr = reinterpret_cast<uint64_t *>(buffer_sp->GetBytes());
854 *data_ptr = dict_item.key_ptr;
855 *(data_ptr + 1) = dict_item.val_ptr;
856 } break;
857 default:
858 lldbassert(false && "pointer size is not 4 nor 8");
859 }
860
861 StreamString idx_name;
862 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
863 DataExtractor data(buffer_sp, m_order, m_ptr_size);
864 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
865 m_exe_ctx_ref, m_pair_type);
866 }
867 return dict_item.valobj_sp;
868}
869
871 NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
872 : SyntheticChildrenFrontEnd(*valobj_sp) {}
873
876 const char *item_name = name.GetCString();
877 uint32_t idx = ExtractIndexFromString(item_name);
878 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
879 return UINT32_MAX;
880 return idx;
881}
882
885 return m_size;
886}
887
889 ValueObjectSP valobj_sp = m_backend.GetSP();
890 if (!valobj_sp)
891 return false;
892 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
894 error.Clear();
895 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
896 if (!process_sp)
897 return false;
898 m_ptr_size = process_sp->GetAddressByteSize();
899 m_order = process_sp->GetByteOrder();
900 uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0);
901 m_size = process_sp->ReadUnsignedIntegerFromMemory(
902 valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error);
903 if (error.Fail())
904 return false;
905 m_keys_ptr =
906 process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error);
907 if (error.Fail())
908 return false;
909 m_objects_ptr =
910 process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error);
911 return !error.Fail();
912}
913
916 return true;
917}
918
919lldb::ValueObjectSP lldb_private::formatters::
921 uint32_t num_children = CalculateNumChildren();
922
923 if (idx >= num_children)
924 return lldb::ValueObjectSP();
925
926 if (m_children.empty()) {
927 // do the scan phase
928 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
929 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
930 if (!process_sp)
931 return lldb::ValueObjectSP();
932
933 for (unsigned int child = 0; child < num_children; ++child) {
935 key_at_idx = process_sp->ReadPointerFromMemory(
936 m_keys_ptr + child * m_ptr_size, error);
937 if (error.Fail())
938 return lldb::ValueObjectSP();
939 val_at_idx = process_sp->ReadPointerFromMemory(
940 m_objects_ptr + child * m_ptr_size, error);
941 if (error.Fail())
942 return lldb::ValueObjectSP();
943 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
944 lldb::ValueObjectSP()};
945 m_children.push_back(descriptor);
946 }
947 }
948
949 if (idx >= m_children.size()) // should never happen
950 return lldb::ValueObjectSP();
951
952 DictionaryItemDescriptor &dict_item = m_children[idx];
953 if (!dict_item.valobj_sp) {
954 if (!m_pair_type.IsValid()) {
955 TargetSP target_sp(m_backend.GetTargetSP());
956 if (!target_sp)
957 return ValueObjectSP();
958 m_pair_type = GetLLDBNSPairType(target_sp);
959 }
960 if (!m_pair_type.IsValid())
961 return ValueObjectSP();
962
963 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
964
965 if (m_ptr_size == 8) {
966 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
967 *data_ptr = dict_item.key_ptr;
968 *(data_ptr + 1) = dict_item.val_ptr;
969 } else {
970 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
971 *data_ptr = dict_item.key_ptr;
972 *(data_ptr + 1) = dict_item.val_ptr;
973 }
974
975 StreamString idx_name;
976 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
977 DataExtractor data(buffer_sp, m_order, m_ptr_size);
978 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
979 m_exe_ctx_ref, m_pair_type);
980 }
981 return dict_item.valobj_sp;
982}
983
985 NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
986 : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
987
990 static const ConstString g_zero("[0]");
991 return name == g_zero ? 0 : UINT32_MAX;
992}
993
996 return 1;
997}
998
1000 m_pair.reset();
1001 return false;
1002}
1003
1006 return true;
1007}
1008
1009lldb::ValueObjectSP
1011 size_t idx) {
1012 if (idx != 0)
1013 return lldb::ValueObjectSP();
1014
1015 if (m_pair.get())
1016 return m_pair;
1017
1018 auto process_sp(m_backend.GetProcessSP());
1019 if (!process_sp)
1020 return nullptr;
1021
1022 auto ptr_size = process_sp->GetAddressByteSize();
1023
1024 lldb::addr_t key_ptr =
1025 m_backend.GetValueAsUnsigned(LLDB_INVALID_ADDRESS) + ptr_size;
1026 lldb::addr_t value_ptr = key_ptr + ptr_size;
1027
1028 Status error;
1029
1030 lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
1031 if (error.Fail())
1032 return nullptr;
1033 lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
1034 if (error.Fail())
1035 return nullptr;
1036
1037 auto pair_type =
1038 GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
1039
1040 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
1041
1042 if (ptr_size == 8) {
1043 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1044 *data_ptr = key_at_idx;
1045 *(data_ptr + 1) = value_at_idx;
1046 } else {
1047 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1048 *data_ptr = key_at_idx;
1049 *(data_ptr + 1) = value_at_idx;
1050 }
1051
1052 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
1053 m_pair = CreateValueObjectFromData(
1054 "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
1055
1056 return m_pair;
1057}
1058
1059template <typename D32, typename D64>
1061 GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1062 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(),
1063 m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {}
1064
1065template <typename D32, typename D64>
1068 delete m_data_32;
1069 m_data_32 = nullptr;
1070 delete m_data_64;
1071 m_data_64 = nullptr;
1072}
1073
1074template <typename D32, typename D64>
1076 D32, D64>::GetIndexOfChildWithName(ConstString name) {
1077 const char *item_name = name.GetCString();
1078 uint32_t idx = ExtractIndexFromString(item_name);
1079 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1080 return UINT32_MAX;
1081 return idx;
1082}
1083
1084template <typename D32, typename D64>
1085size_t
1087 if (!m_data_32 && !m_data_64)
1088 return 0;
1089 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1090}
1091
1092template <typename D32, typename D64>
1093bool
1095 Update() {
1096 m_children.clear();
1097 ValueObjectSP valobj_sp = m_backend.GetSP();
1098 m_ptr_size = 0;
1099 delete m_data_32;
1100 m_data_32 = nullptr;
1101 delete m_data_64;
1102 m_data_64 = nullptr;
1103 if (!valobj_sp)
1104 return false;
1105 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1106 Status error;
1107 error.Clear();
1108 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1109 if (!process_sp)
1110 return false;
1111 m_ptr_size = process_sp->GetAddressByteSize();
1112 m_order = process_sp->GetByteOrder();
1113 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1114 if (m_ptr_size == 4) {
1115 m_data_32 = new D32();
1116 process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
1117 error);
1118 } else {
1119 m_data_64 = new D64();
1120 process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
1121 error);
1122 }
1123
1124 return error.Success();
1125}
1126
1127template <typename D32, typename D64>
1128bool
1131 return true;
1132}
1133
1134template <typename D32, typename D64>
1135lldb::ValueObjectSP
1137 D32, D64>::GetChildAtIndex(size_t idx) {
1138 lldb::addr_t m_keys_ptr;
1139 lldb::addr_t m_values_ptr;
1140 if (m_data_32) {
1141 uint32_t size = m_data_32->GetSize();
1142 m_keys_ptr = m_data_32->_buffer;
1143 m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
1144 } else {
1145 uint32_t size = m_data_64->GetSize();
1146 m_keys_ptr = m_data_64->_buffer;
1147 m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
1148 }
1149
1150 uint32_t num_children = CalculateNumChildren();
1151
1152 if (idx >= num_children)
1153 return lldb::ValueObjectSP();
1154
1155 if (m_children.empty()) {
1156 // do the scan phase
1157 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1158
1159 uint32_t tries = 0;
1160 uint32_t test_idx = 0;
1161
1162 while (tries < num_children) {
1163 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1164 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1165 ;
1166 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1167 if (!process_sp)
1168 return lldb::ValueObjectSP();
1169 Status error;
1170 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1171 if (error.Fail())
1172 return lldb::ValueObjectSP();
1173 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1174 if (error.Fail())
1175 return lldb::ValueObjectSP();
1176
1177 test_idx++;
1178
1179 if (!key_at_idx || !val_at_idx)
1180 continue;
1181 tries++;
1182
1183 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1184 lldb::ValueObjectSP()};
1185
1186 m_children.push_back(descriptor);
1187 }
1188 }
1189
1190 if (idx >= m_children.size()) // should never happen
1191 return lldb::ValueObjectSP();
1192
1193 DictionaryItemDescriptor &dict_item = m_children[idx];
1194 if (!dict_item.valobj_sp) {
1195 if (!m_pair_type.IsValid()) {
1196 TargetSP target_sp(m_backend.GetTargetSP());
1197 if (!target_sp)
1198 return ValueObjectSP();
1199 m_pair_type = GetLLDBNSPairType(target_sp);
1200 }
1201 if (!m_pair_type.IsValid())
1202 return ValueObjectSP();
1203
1204 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1205
1206 if (m_ptr_size == 8) {
1207 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1208 *data_ptr = dict_item.key_ptr;
1209 *(data_ptr + 1) = dict_item.val_ptr;
1210 } else {
1211 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1212 *data_ptr = dict_item.key_ptr;
1213 *(data_ptr + 1) = dict_item.val_ptr;
1214 }
1215
1216 StreamString idx_name;
1217 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1218 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1219 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1220 m_exe_ctx_ref, m_pair_type);
1221 }
1222 return dict_item.valobj_sp;
1223}
1224
1226 NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
1227 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type() {}
1228
1231 delete m_data_32;
1232 m_data_32 = nullptr;
1233 delete m_data_64;
1234 m_data_64 = nullptr;
1235}
1236
1237size_t
1240 const char *item_name = name.GetCString();
1241 uint32_t idx = ExtractIndexFromString(item_name);
1242 if (idx < UINT32_MAX && idx >= CalculateNumChildren())
1243 return UINT32_MAX;
1244 return idx;
1245}
1246
1247size_t
1250 if (!m_data_32 && !m_data_64)
1251 return 0;
1252 return (m_data_32 ? m_data_32->_used : m_data_64->_used);
1253}
1254
1255bool
1258 m_children.clear();
1259 ValueObjectSP valobj_sp = m_backend.GetSP();
1260 m_ptr_size = 0;
1261 delete m_data_32;
1262 m_data_32 = nullptr;
1263 delete m_data_64;
1264 m_data_64 = nullptr;
1265 if (!valobj_sp)
1266 return false;
1267 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1268 Status error;
1269 error.Clear();
1270 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
1271 if (!process_sp)
1272 return false;
1273 m_ptr_size = process_sp->GetAddressByteSize();
1274 m_order = process_sp->GetByteOrder();
1275 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
1276 if (m_ptr_size == 4) {
1277 m_data_32 = new DataDescriptor_32();
1278 process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
1279 error);
1280 } else {
1281 m_data_64 = new DataDescriptor_64();
1282 process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
1283 error);
1284 }
1285
1286 return error.Success();
1287}
1288
1289bool
1292 return true;
1293}
1294
1295lldb::ValueObjectSP
1298 lldb::addr_t m_keys_ptr =
1299 (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
1300 lldb::addr_t m_values_ptr =
1301 (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
1302
1303 uint32_t num_children = CalculateNumChildren();
1304
1305 if (idx >= num_children)
1306 return lldb::ValueObjectSP();
1307
1308 if (m_children.empty()) {
1309 // do the scan phase
1310 lldb::addr_t key_at_idx = 0, val_at_idx = 0;
1311
1312 uint32_t tries = 0;
1313 uint32_t test_idx = 0;
1314
1315 while (tries < num_children) {
1316 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
1317 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
1318 ;
1319 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
1320 if (!process_sp)
1321 return lldb::ValueObjectSP();
1322 Status error;
1323 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
1324 if (error.Fail())
1325 return lldb::ValueObjectSP();
1326 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
1327 if (error.Fail())
1328 return lldb::ValueObjectSP();
1329
1330 test_idx++;
1331
1332 if (!key_at_idx || !val_at_idx)
1333 continue;
1334 tries++;
1335
1336 DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1337 lldb::ValueObjectSP()};
1338
1339 m_children.push_back(descriptor);
1340 }
1341 }
1342
1343 if (idx >= m_children.size()) // should never happen
1344 return lldb::ValueObjectSP();
1345
1346 DictionaryItemDescriptor &dict_item = m_children[idx];
1347 if (!dict_item.valobj_sp) {
1348 if (!m_pair_type.IsValid()) {
1349 TargetSP target_sp(m_backend.GetTargetSP());
1350 if (!target_sp)
1351 return ValueObjectSP();
1352 m_pair_type = GetLLDBNSPairType(target_sp);
1353 }
1354 if (!m_pair_type.IsValid())
1355 return ValueObjectSP();
1356
1357 WritableDataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1358
1359 if (m_ptr_size == 8) {
1360 uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1361 *data_ptr = dict_item.key_ptr;
1362 *(data_ptr + 1) = dict_item.val_ptr;
1363 } else {
1364 uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1365 *data_ptr = dict_item.key_ptr;
1366 *(data_ptr + 1) = dict_item.val_ptr;
1367 }
1368
1369 StreamString idx_name;
1370 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1371 DataExtractor data(buffer_sp, m_order, m_ptr_size);
1372 dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1373 m_exe_ctx_ref, m_pair_type);
1374 }
1375 return dict_item.valobj_sp;
1376}
1377
1379 ValueObject &, Stream &, const TypeSummaryOptions &);
1380
1382 ValueObject &, Stream &, const TypeSummaryOptions &);
static llvm::raw_ostream & error(Stream &strm)
#define lldbassert(x)
Definition: LLDBAssert.h:15
uint32_t _size
Definition: NSArray.cpp:105
uint32_t _used
Definition: NSArray.cpp:103
uint32_t _muts
uint32_t _kvo
uint32_t _buffer
static CompilerType GetLLDBNSPairType(TargetSP target_sp)
uint32_t _szidx
static size_t CalculateNumChildren(CompilerType container_type, CompilerType element_type, lldb_private::ExecutionContextScope *exe_scope=nullptr)
Definition: VectorType.cpp:172
bool Update(lldb::addr_t addr, ExecutionContextRef exe_ctx_rf)
Definition: CFBasicHash.cpp:20
std::function< SyntheticChildrenFrontEnd *(CXXSyntheticChildren *, lldb::ValueObjectSP)> CreateFrontEndCallback
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
uint32_t GetTypeInfo(CompilerType *pointee_or_element_compiler_type=nullptr) const
A uniqued constant string class.
Definition: ConstString.h:39
bool IsEmpty() const
Test for empty string.
Definition: ConstString.h:303
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:201
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:215
A subclass of DataBuffer that stores a data buffer on the heap.
An data extractor class.
Definition: DataExtractor.h:48
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.
A class to manage flags.
Definition: Flags.h:22
bool IsClear(ValueType bit) const
Test a single flag bit to see if it is clear (zero).
Definition: Flags.h:111
static Language * FindPlugin(lldb::LanguageType language)
Definition: Language.cpp:53
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.
Definition: Process.h:342
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error)
Read of memory from a process.
Definition: Process.cpp:1926
uint32_t GetAddressByteSize() const
Definition: Process.cpp:3367
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.
An error handling class.
Definition: Status.h:44
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
lldb::LanguageType GetLanguage() const
Definition: TypeSummary.cpp:31
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
Definition: ValueObject.h:338
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
std::vector< DictionaryItemDescriptor > m_children
size_t GetIndexOfChildWithName(ConstString name) override
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
size_t GetIndexOfChildWithName(ConstString name) override
std::vector< DictionaryItemDescriptor > m_children
NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
size_t GetIndexOfChildWithName(ConstString name) override
static AdditionalFormatters< CXXFunctionSummaryFormat::Callback > & GetAdditionalSummaries()
std::vector< AdditionalFormatter< FormatterType > > AdditionalFormatters
Definition: NSDictionary.h:82
static AdditionalFormatters< CXXSyntheticChildren::CreateFrontEndCallback > & GetAdditionalSynthetics()
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
#define UINT32_MAX
Definition: lldb-defines.h:19
static const uint64_t NSDictionaryCapacities[]
uint64_t __NSDictionaryMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr, Status &error)
uint64_t __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, Status &error)
template bool NSDictionarySummaryProvider< false >(ValueObject &, Stream &, const TypeSummaryOptions &)
size_t ExtractIndexFromString(const char *item_name)
template bool NSDictionarySummaryProvider< true >(ValueObject &, Stream &, const TypeSummaryOptions &)
bool NSDictionarySummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
SyntheticChildrenFrontEnd * NSDictionarySyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
@ eBasicTypeObjCID
@ eLanguageTypeC
Non-standardized C, such as K&R.
ByteOrder
Byte ordering definitions.
@ eByteOrderInvalid
uint64_t addr_t
Definition: lldb-types.h:83
std::function< bool(ValueObject &, Stream &, const TypeSummaryOptions &)> Callback
Definition: TypeSummary.h:311