LLDB  mainline
NSDictionary.cpp
Go to the documentation of this file.
1 //===-- NSDictionary.cpp ----------------------------------------*- C++ -*-===//
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 "NSDictionary.h"
14 
16 
17 #include "lldb/Core/ValueObject.h"
21 #include "lldb/Target/Language.h"
23 #include "lldb/Target/StackFrame.h"
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 
30 using namespace lldb;
31 using namespace lldb_private;
32 using namespace lldb_private::formatters;
33 
34 NSDictionary_Additionals::AdditionalFormatterMatching::Prefix::Prefix(
35  ConstString p)
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 
66 static CompilerType GetLLDBNSPairType(TargetSP target_sp) {
67  CompilerType compiler_type;
68 
69  ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
70 
71  if (target_ast_context) {
72  ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair");
73 
74  compiler_type =
75  target_ast_context->GetTypeForIdentifier<clang::CXXRecordDecl>(
76  g___lldb_autogen_nspair);
77 
78  if (!compiler_type) {
79  compiler_type = target_ast_context->CreateRecordType(
80  nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(),
81  clang::TTK_Struct, lldb::eLanguageTypeC);
82 
83  if (compiler_type) {
85  CompilerType id_compiler_type =
86  target_ast_context->GetBasicType(eBasicTypeObjCID);
88  compiler_type, "key", id_compiler_type, lldb::eAccessPublic, 0);
90  compiler_type, "value", id_compiler_type, lldb::eAccessPublic, 0);
92  }
93  }
94  }
95  return compiler_type;
96 }
97 
98 namespace lldb_private {
99 namespace formatters {
101 public:
102  NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
103 
104  ~NSDictionaryISyntheticFrontEnd() override;
105 
106  size_t CalculateNumChildren() override;
107 
108  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
109 
110  bool Update() override;
111 
112  bool MightHaveChildren() override;
113 
114  size_t GetIndexOfChildWithName(ConstString name) override;
115 
116 private:
117  struct DataDescriptor_32 {
118  uint32_t _used : 26;
119  uint32_t _szidx : 6;
120  };
121 
122  struct DataDescriptor_64 {
123  uint64_t _used : 58;
124  uint32_t _szidx : 6;
125  };
126 
127  struct DictionaryItemDescriptor {
128  lldb::addr_t key_ptr;
129  lldb::addr_t val_ptr;
130  lldb::ValueObjectSP valobj_sp;
131  };
132 
133  ExecutionContextRef m_exe_ctx_ref;
134  uint8_t m_ptr_size;
135  lldb::ByteOrder m_order;
136  DataDescriptor_32 *m_data_32;
137  DataDescriptor_64 *m_data_64;
138  lldb::addr_t m_data_ptr;
139  CompilerType m_pair_type;
140  std::vector<DictionaryItemDescriptor> m_children;
141 };
142 
144 public:
145  NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
146 
147  ~NSDictionary1SyntheticFrontEnd() override = default;
148 
149  size_t CalculateNumChildren() override;
150 
151  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
152 
153  bool Update() override;
154 
155  bool MightHaveChildren() override;
156 
157  size_t GetIndexOfChildWithName(ConstString name) override;
158 
159 private:
160  ValueObjectSP m_pair;
161 };
162 
163 template <typename D32, typename D64>
165 public:
166  GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
167 
169 
170  size_t CalculateNumChildren() override;
171 
172  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
173 
174  bool Update() override;
175 
176  bool MightHaveChildren() override;
177 
178  size_t GetIndexOfChildWithName(ConstString name) override;
179 
180 private:
181  struct DictionaryItemDescriptor {
182  lldb::addr_t key_ptr;
183  lldb::addr_t val_ptr;
184  lldb::ValueObjectSP valobj_sp;
185  };
186 
187  ExecutionContextRef m_exe_ctx_ref;
188  uint8_t m_ptr_size;
189  lldb::ByteOrder m_order;
190  D32 *m_data_32;
191  D64 *m_data_64;
192  CompilerType m_pair_type;
193  std::vector<DictionaryItemDescriptor> m_children;
194 };
195 
196 namespace Foundation1100 {
198  public:
199  NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
200 
201  ~NSDictionaryMSyntheticFrontEnd() override;
202 
203  size_t CalculateNumChildren() override;
204 
205  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
206 
207  bool Update() override;
208 
209  bool MightHaveChildren() override;
210 
211  size_t GetIndexOfChildWithName(ConstString name) override;
212 
213  private:
214  struct DataDescriptor_32 {
215  uint32_t _used : 26;
216  uint32_t _kvo : 1;
217  uint32_t _size;
218  uint32_t _mutations;
219  uint32_t _objs_addr;
220  uint32_t _keys_addr;
221  };
222 
223  struct DataDescriptor_64 {
224  uint64_t _used : 58;
225  uint32_t _kvo : 1;
226  uint64_t _size;
227  uint64_t _mutations;
228  uint64_t _objs_addr;
229  uint64_t _keys_addr;
230  };
231 
232  struct DictionaryItemDescriptor {
233  lldb::addr_t key_ptr;
234  lldb::addr_t val_ptr;
235  lldb::ValueObjectSP valobj_sp;
236  };
237 
238  ExecutionContextRef m_exe_ctx_ref;
239  uint8_t m_ptr_size;
240  lldb::ByteOrder m_order;
241  DataDescriptor_32 *m_data_32;
242  DataDescriptor_64 *m_data_64;
243  CompilerType m_pair_type;
244  std::vector<DictionaryItemDescriptor> m_children;
245  };
246 }
247 
248 namespace Foundation1428 {
249  struct DataDescriptor_32 {
250  uint32_t _used : 26;
252  uint32_t _size;
254  uint64_t GetSize() { return _size; }
255  };
256 
257  struct DataDescriptor_64 {
258  uint64_t _used : 58;
260  uint64_t _size;
261  uint64_t _buffer;
262  uint64_t GetSize() { return _size; }
263  };
264 
265 
266 
269 }
270 
271 namespace Foundation1437 {
272  static const uint64_t NSDictionaryCapacities[] = {
273  0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723,
274  2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607,
275  214519, 346607, 561109, 907759, 1468927, 2376191, 3845119,
276  6221311, 10066421, 16287743, 26354171, 42641881, 68996069,
277  111638519, 180634607, 292272623, 472907251
278  };
279 
280  static const size_t NSDictionaryNumSizeBuckets = sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
281 
288 
289  uint64_t GetSize() {
290  return (_szidx) >= NSDictionaryNumSizeBuckets ?
291  0 : NSDictionaryCapacities[_szidx];
292  }
293  };
294 
296  uint64_t _buffer;
301 
302  uint64_t GetSize() {
303  return (_szidx) >= NSDictionaryNumSizeBuckets ?
304  0 : NSDictionaryCapacities[_szidx];
305  }
306  };
307 
310 
311  template <typename DD>
312  uint64_t
314  lldb::addr_t valobj_addr, Status &error) {
315  const lldb::addr_t start_of_descriptor =
316  valobj_addr + process.GetAddressByteSize();
317  DD descriptor = DD();
318  process.ReadMemory(start_of_descriptor, &descriptor, sizeof(descriptor),
319  error);
320  if (error.Fail()) {
321  return 0;
322  }
323  return descriptor._used;
324  }
325 
326  uint64_t
328  Status &error) {
329  if (process.GetAddressByteSize() == 4) {
330  return __NSDictionaryMSize_Impl<DataDescriptor_32>(process, valobj_addr,
331  error);
332  } else {
333  return __NSDictionaryMSize_Impl<DataDescriptor_64>(process, valobj_addr,
334  error);
335  }
336  }
337 
338 }
339 } // namespace formatters
340 } // namespace lldb_private
341 
342 template <bool name_entries>
344  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
345  static ConstString g_TypeHint("NSDictionary");
346  ProcessSP process_sp = valobj.GetProcessSP();
347  if (!process_sp)
348  return false;
349 
350  ObjCLanguageRuntime *runtime =
351  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
353 
354  if (!runtime)
355  return false;
356 
358  runtime->GetClassDescriptor(valobj));
359 
360  if (!descriptor || !descriptor->IsValid())
361  return false;
362 
363  uint32_t ptr_size = process_sp->GetAddressByteSize();
364  bool is_64bit = (ptr_size == 8);
365 
366  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
367 
368  if (!valobj_addr)
369  return false;
370 
371  uint64_t value = 0;
372 
373  ConstString class_name(descriptor->GetClassName());
374 
375  static const ConstString g_DictionaryI("__NSDictionaryI");
376  static const ConstString g_DictionaryM("__NSDictionaryM");
377  static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
378  static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
379  static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
380  static const ConstString g_Dictionary0("__NSDictionary0");
381  static const ConstString g_DictionaryCF("__NSCFDictionary");
382 
383  if (class_name.IsEmpty())
384  return false;
385 
386  if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
387  Status error;
388  value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
389  ptr_size, 0, error);
390  if (error.Fail())
391  return false;
392  value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
393  } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
394  class_name == g_DictionaryCF) {
395  AppleObjCRuntime *apple_runtime =
396  llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
397  Status error;
398  if (apple_runtime && apple_runtime->GetFoundationVersion() >= 1437) {
399  value = Foundation1437::__NSDictionaryMSize(*process_sp, valobj_addr,
400  error);
401  } else {
402  value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
403  ptr_size, 0, error);
404  value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
405  }
406  if (error.Fail())
407  return false;
408  } else if (class_name == g_Dictionary1) {
409  value = 1;
410  } else if (class_name == g_Dictionary0) {
411  value = 0;
412  }
413  else {
415  for (auto &candidate : map) {
416  if (candidate.first && candidate.first->Match(class_name))
417  return candidate.second(valobj, stream, options);
418  }
419  return false;
420  }
421 
422  std::string prefix, suffix;
423  if (Language *language = Language::FindPlugin(options.GetLanguage())) {
424  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
425  suffix)) {
426  prefix.clear();
427  suffix.clear();
428  }
429  }
430 
431  stream.Printf("%s%" PRIu64 " %s%s%s", prefix.c_str(), value, "key/value pair",
432  value == 1 ? "" : "s", suffix.c_str());
433  return true;
434 }
435 
438  CXXSyntheticChildren *synth, lldb::ValueObjectSP valobj_sp) {
439  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
440  if (!process_sp)
441  return nullptr;
442  AppleObjCRuntime *runtime =
443  llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
444  if (!runtime)
445  return nullptr;
446 
447  CompilerType valobj_type(valobj_sp->GetCompilerType());
448  Flags flags(valobj_type.GetTypeInfo());
449 
450  if (flags.IsClear(eTypeIsPointer)) {
451  Status error;
452  valobj_sp = valobj_sp->AddressOf(error);
453  if (error.Fail() || !valobj_sp)
454  return nullptr;
455  }
456 
458  runtime->GetClassDescriptor(*valobj_sp));
459 
460  if (!descriptor || !descriptor->IsValid())
461  return nullptr;
462 
463  ConstString class_name(descriptor->GetClassName());
464 
465  static const ConstString g_DictionaryI("__NSDictionaryI");
466  static const ConstString g_DictionaryM("__NSDictionaryM");
467  static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
468  static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
469  static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
470  static const ConstString g_Dictionary0("__NSDictionary0");
471 
472  if (class_name.IsEmpty())
473  return nullptr;
474 
475  if (class_name == g_DictionaryI) {
476  return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
477  } else if (class_name == g_DictionaryM) {
478  if (runtime->GetFoundationVersion() >= 1437) {
479  return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp));
480  } else if (runtime->GetFoundationVersion() >= 1428) {
481  return (new Foundation1428::NSDictionaryMSyntheticFrontEnd(valobj_sp));
482  } else {
483  return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
484  }
485  } else if (class_name == g_DictionaryMLegacy) {
486  return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
487  } else if (class_name == g_Dictionary1) {
488  return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
489  } else {
491  for (auto &candidate : map) {
492  if (candidate.first && candidate.first->Match((class_name)))
493  return candidate.second(synth, valobj_sp);
494  }
495  }
496 
497  return nullptr;
498 }
499 
501  NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
502  : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
503  m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
504  m_pair_type() {}
505 
508  delete m_data_32;
509  m_data_32 = nullptr;
510  delete m_data_64;
511  m_data_64 = nullptr;
512 }
513 
516  const char *item_name = name.GetCString();
517  uint32_t idx = ExtractIndexFromString(item_name);
518  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
519  return UINT32_MAX;
520  return idx;
521 }
522 
525  if (!m_data_32 && !m_data_64)
526  return 0;
527  return (m_data_32 ? m_data_32->_used : m_data_64->_used);
528 }
529 
531  m_children.clear();
532  delete m_data_32;
533  m_data_32 = nullptr;
534  delete m_data_64;
535  m_data_64 = nullptr;
536  m_ptr_size = 0;
537  ValueObjectSP valobj_sp = m_backend.GetSP();
538  if (!valobj_sp)
539  return false;
540  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
541  Status error;
542  error.Clear();
543  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
544  if (!process_sp)
545  return false;
546  m_ptr_size = process_sp->GetAddressByteSize();
547  m_order = process_sp->GetByteOrder();
548  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
549  if (m_ptr_size == 4) {
550  m_data_32 = new DataDescriptor_32();
551  process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
552  error);
553  } else {
554  m_data_64 = new DataDescriptor_64();
555  process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
556  error);
557  }
558  if (error.Fail())
559  return false;
560  m_data_ptr = data_location + m_ptr_size;
561  return false;
562 }
563 
566  return true;
567 }
568 
569 lldb::ValueObjectSP
571  size_t idx) {
572  uint32_t num_children = CalculateNumChildren();
573 
574  if (idx >= num_children)
575  return lldb::ValueObjectSP();
576 
577  if (m_children.empty()) {
578  // do the scan phase
579  lldb::addr_t key_at_idx = 0, val_at_idx = 0;
580 
581  uint32_t tries = 0;
582  uint32_t test_idx = 0;
583 
584  while (tries < num_children) {
585  key_at_idx = m_data_ptr + (2 * test_idx * m_ptr_size);
586  val_at_idx = key_at_idx + m_ptr_size;
587  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
588  if (!process_sp)
589  return lldb::ValueObjectSP();
590  Status error;
591  key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
592  if (error.Fail())
593  return lldb::ValueObjectSP();
594  val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
595  if (error.Fail())
596  return lldb::ValueObjectSP();
597 
598  test_idx++;
599 
600  if (!key_at_idx || !val_at_idx)
601  continue;
602  tries++;
603 
604  DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
605  lldb::ValueObjectSP()};
606 
607  m_children.push_back(descriptor);
608  }
609  }
610 
611  if (idx >= m_children.size()) // should never happen
612  return lldb::ValueObjectSP();
613 
614  DictionaryItemDescriptor &dict_item = m_children[idx];
615  if (!dict_item.valobj_sp) {
616  if (!m_pair_type.IsValid()) {
617  TargetSP target_sp(m_backend.GetTargetSP());
618  if (!target_sp)
619  return ValueObjectSP();
620  m_pair_type = GetLLDBNSPairType(target_sp);
621  }
622  if (!m_pair_type.IsValid())
623  return ValueObjectSP();
624 
625  DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
626 
627  if (m_ptr_size == 8) {
628  uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
629  *data_ptr = dict_item.key_ptr;
630  *(data_ptr + 1) = dict_item.val_ptr;
631  } else {
632  uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
633  *data_ptr = dict_item.key_ptr;
634  *(data_ptr + 1) = dict_item.val_ptr;
635  }
636 
637  StreamString idx_name;
638  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
639  DataExtractor data(buffer_sp, m_order, m_ptr_size);
640  dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
641  m_exe_ctx_ref, m_pair_type);
642  }
643  return dict_item.valobj_sp;
644 }
645 
647  NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
648  : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
649 
652  static const ConstString g_zero("[0]");
653  return name == g_zero ? 0 : UINT32_MAX;
654 }
655 
658  return 1;
659 }
660 
662  m_pair.reset();
663  return false;
664 }
665 
668  return true;
669 }
670 
671 lldb::ValueObjectSP
673  size_t idx) {
674  if (idx != 0)
675  return lldb::ValueObjectSP();
676 
677  if (m_pair.get())
678  return m_pair;
679 
680  auto process_sp(m_backend.GetProcessSP());
681  if (!process_sp)
682  return nullptr;
683 
684  auto ptr_size = process_sp->GetAddressByteSize();
685 
686  lldb::addr_t key_ptr =
688  lldb::addr_t value_ptr = key_ptr + ptr_size;
689 
690  Status error;
691 
692  lldb::addr_t value_at_idx = process_sp->ReadPointerFromMemory(key_ptr, error);
693  if (error.Fail())
694  return nullptr;
695  lldb::addr_t key_at_idx = process_sp->ReadPointerFromMemory(value_ptr, error);
696  if (error.Fail())
697  return nullptr;
698 
699  auto pair_type =
700  GetLLDBNSPairType(process_sp->GetTarget().shared_from_this());
701 
702  DataBufferSP buffer_sp(new DataBufferHeap(2 * ptr_size, 0));
703 
704  if (ptr_size == 8) {
705  uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
706  *data_ptr = key_at_idx;
707  *(data_ptr + 1) = value_at_idx;
708  } else {
709  uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
710  *data_ptr = key_at_idx;
711  *(data_ptr + 1) = value_at_idx;
712  }
713 
714  DataExtractor data(buffer_sp, process_sp->GetByteOrder(), ptr_size);
715  m_pair = CreateValueObjectFromData(
716  "[0]", data, m_backend.GetExecutionContextRef(), pair_type);
717 
718  return m_pair;
719 }
720 
721 template <typename D32, typename D64>
723  GenericNSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
724  : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
725  m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
726  m_pair_type() {}
727 
728 template <typename D32, typename D64>
731  delete m_data_32;
732  m_data_32 = nullptr;
733  delete m_data_64;
734  m_data_64 = nullptr;
735 }
736 
737 template <typename D32, typename D64>
738 size_t
740  const char *item_name = name.GetCString();
741  uint32_t idx = ExtractIndexFromString(item_name);
742  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
743  return UINT32_MAX;
744  return idx;
745 }
746 
747 template <typename D32, typename D64>
748 size_t
750  if (!m_data_32 && !m_data_64)
751  return 0;
752  return (m_data_32 ? m_data_32->_used : m_data_64->_used);
753 }
754 
755 template <typename D32, typename D64>
756 bool
759  m_children.clear();
760  ValueObjectSP valobj_sp = m_backend.GetSP();
761  m_ptr_size = 0;
762  delete m_data_32;
763  m_data_32 = nullptr;
764  delete m_data_64;
765  m_data_64 = nullptr;
766  if (!valobj_sp)
767  return false;
768  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
769  Status error;
770  error.Clear();
771  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
772  if (!process_sp)
773  return false;
774  m_ptr_size = process_sp->GetAddressByteSize();
775  m_order = process_sp->GetByteOrder();
776  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
777  if (m_ptr_size == 4) {
778  m_data_32 = new D32();
779  process_sp->ReadMemory(data_location, m_data_32, sizeof(D32),
780  error);
781  } else {
782  m_data_64 = new D64();
783  process_sp->ReadMemory(data_location, m_data_64, sizeof(D64),
784  error);
785  }
786  if (error.Fail())
787  return false;
788  return false;
789 }
790 
791 template <typename D32, typename D64>
792 bool
795  return true;
796 }
797 
798 template <typename D32, typename D64>
799 lldb::ValueObjectSP
802  size_t idx) {
803  lldb::addr_t m_keys_ptr;
804  lldb::addr_t m_values_ptr;
805  if (m_data_32) {
806  uint32_t size = m_data_32->GetSize();
807  m_keys_ptr = m_data_32->_buffer;
808  m_values_ptr = m_data_32->_buffer + (m_ptr_size * size);
809  } else {
810  uint32_t size = m_data_64->GetSize();
811  m_keys_ptr = m_data_64->_buffer;
812  m_values_ptr = m_data_64->_buffer + (m_ptr_size * size);
813  }
814 
815  uint32_t num_children = CalculateNumChildren();
816 
817  if (idx >= num_children)
818  return lldb::ValueObjectSP();
819 
820  if (m_children.empty()) {
821  // do the scan phase
822  lldb::addr_t key_at_idx = 0, val_at_idx = 0;
823 
824  uint32_t tries = 0;
825  uint32_t test_idx = 0;
826 
827  while (tries < num_children) {
828  key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
829  val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
830  ;
831  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
832  if (!process_sp)
833  return lldb::ValueObjectSP();
834  Status error;
835  key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
836  if (error.Fail())
837  return lldb::ValueObjectSP();
838  val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
839  if (error.Fail())
840  return lldb::ValueObjectSP();
841 
842  test_idx++;
843 
844  if (!key_at_idx || !val_at_idx)
845  continue;
846  tries++;
847 
848  DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
849  lldb::ValueObjectSP()};
850 
851  m_children.push_back(descriptor);
852  }
853  }
854 
855  if (idx >= m_children.size()) // should never happen
856  return lldb::ValueObjectSP();
857 
858  DictionaryItemDescriptor &dict_item = m_children[idx];
859  if (!dict_item.valobj_sp) {
860  if (!m_pair_type.IsValid()) {
861  TargetSP target_sp(m_backend.GetTargetSP());
862  if (!target_sp)
863  return ValueObjectSP();
864  m_pair_type = GetLLDBNSPairType(target_sp);
865  }
866  if (!m_pair_type.IsValid())
867  return ValueObjectSP();
868 
869  DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
870 
871  if (m_ptr_size == 8) {
872  uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
873  *data_ptr = dict_item.key_ptr;
874  *(data_ptr + 1) = dict_item.val_ptr;
875  } else {
876  uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
877  *data_ptr = dict_item.key_ptr;
878  *(data_ptr + 1) = dict_item.val_ptr;
879  }
880 
881  StreamString idx_name;
882  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
883  DataExtractor data(buffer_sp, m_order, m_ptr_size);
884  dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
885  m_exe_ctx_ref, m_pair_type);
886  }
887  return dict_item.valobj_sp;
888 }
889 
890 
893  NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
894  : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
895  m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
896  m_pair_type() {}
897 
900  delete m_data_32;
901  m_data_32 = nullptr;
902  delete m_data_64;
903  m_data_64 = nullptr;
904 }
905 
906 size_t
909  const char *item_name = name.GetCString();
910  uint32_t idx = ExtractIndexFromString(item_name);
911  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
912  return UINT32_MAX;
913  return idx;
914 }
915 
916 size_t
919  if (!m_data_32 && !m_data_64)
920  return 0;
921  return (m_data_32 ? m_data_32->_used : m_data_64->_used);
922 }
923 
924 bool
927  m_children.clear();
928  ValueObjectSP valobj_sp = m_backend.GetSP();
929  m_ptr_size = 0;
930  delete m_data_32;
931  m_data_32 = nullptr;
932  delete m_data_64;
933  m_data_64 = nullptr;
934  if (!valobj_sp)
935  return false;
936  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
937  Status error;
938  error.Clear();
939  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
940  if (!process_sp)
941  return false;
942  m_ptr_size = process_sp->GetAddressByteSize();
943  m_order = process_sp->GetByteOrder();
944  uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
945  if (m_ptr_size == 4) {
946  m_data_32 = new DataDescriptor_32();
947  process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
948  error);
949  } else {
950  m_data_64 = new DataDescriptor_64();
951  process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
952  error);
953  }
954  if (error.Fail())
955  return false;
956  return false;
957 }
958 
959 bool
962  return true;
963 }
964 
965 lldb::ValueObjectSP
968  lldb::addr_t m_keys_ptr =
969  (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
970  lldb::addr_t m_values_ptr =
971  (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
972 
973  uint32_t num_children = CalculateNumChildren();
974 
975  if (idx >= num_children)
976  return lldb::ValueObjectSP();
977 
978  if (m_children.empty()) {
979  // do the scan phase
980  lldb::addr_t key_at_idx = 0, val_at_idx = 0;
981 
982  uint32_t tries = 0;
983  uint32_t test_idx = 0;
984 
985  while (tries < num_children) {
986  key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
987  val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
988  ;
989  ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
990  if (!process_sp)
991  return lldb::ValueObjectSP();
992  Status error;
993  key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
994  if (error.Fail())
995  return lldb::ValueObjectSP();
996  val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
997  if (error.Fail())
998  return lldb::ValueObjectSP();
999 
1000  test_idx++;
1001 
1002  if (!key_at_idx || !val_at_idx)
1003  continue;
1004  tries++;
1005 
1006  DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
1007  lldb::ValueObjectSP()};
1008 
1009  m_children.push_back(descriptor);
1010  }
1011  }
1012 
1013  if (idx >= m_children.size()) // should never happen
1014  return lldb::ValueObjectSP();
1015 
1016  DictionaryItemDescriptor &dict_item = m_children[idx];
1017  if (!dict_item.valobj_sp) {
1018  if (!m_pair_type.IsValid()) {
1019  TargetSP target_sp(m_backend.GetTargetSP());
1020  if (!target_sp)
1021  return ValueObjectSP();
1022  m_pair_type = GetLLDBNSPairType(target_sp);
1023  }
1024  if (!m_pair_type.IsValid())
1025  return ValueObjectSP();
1026 
1027  DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
1028 
1029  if (m_ptr_size == 8) {
1030  uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
1031  *data_ptr = dict_item.key_ptr;
1032  *(data_ptr + 1) = dict_item.val_ptr;
1033  } else {
1034  uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
1035  *data_ptr = dict_item.key_ptr;
1036  *(data_ptr + 1) = dict_item.val_ptr;
1037  }
1038 
1039  StreamString idx_name;
1040  idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
1041  DataExtractor data(buffer_sp, m_order, m_ptr_size);
1042  dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
1043  m_exe_ctx_ref, m_pair_type);
1044  }
1045  return dict_item.valobj_sp;
1046 }
1047 
1049  ValueObject &, Stream &, const TypeSummaryOptions &);
1050 
1052  ValueObject &, Stream &, const TypeSummaryOptions &);
GenericNSDictionaryMSyntheticFrontEnd< DataDescriptor_32, DataDescriptor_64 > NSDictionaryMSyntheticFrontEnd
static bool CompleteTagDeclarationDefinition(const CompilerType &type)
An data extractor class.
Definition: DataExtractor.h:47
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
template bool NSDictionarySummaryProvider< false >(ValueObject &, Stream &, const TypeSummaryOptions &)
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
std::function< bool(ValueObject &, Stream &, const TypeSummaryOptions &)> Callback
Definition: TypeSummary.h:312
lldb::ProcessSP GetProcessSP() const
Get accessor that creates a strong reference from the weak process reference contained in this object...
std::vector< AdditionalFormatter< FormatterType > > AdditionalFormatters
Definition: NSDictionary.h:83
static AdditionalFormatters< CXXFunctionSummaryFormat::Callback > & GetAdditionalSummaries()
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
lldb::TargetSP GetTargetSP() const
Definition: ValueObject.h:357
A subclass of DataBuffer that stores a data buffer on the heap.
static CompilerType GetLLDBNSPairType(TargetSP target_sp)
lldb::LanguageType GetLanguage() const
Definition: TypeSummary.cpp:42
CompilerType CreateRecordType(clang::DeclContext *decl_ctx, lldb::AccessType access_type, const char *name, int kind, lldb::LanguageType language, ClangASTMetadata *metadata=nullptr)
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
size_t ExtractIndexFromString(const char *item_name)
#define UINT32_MAX
Definition: lldb-defines.h:31
SyntheticChildrenFrontEnd * NSDictionarySyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type)
static bool StartTagDeclarationDefinition(const CompilerType &type)
static const uint64_t NSDictionaryCapacities[]
void Clear()
Clear the object state.
Definition: Status.cpp:167
uint32_t GetAddressByteSize() const
Definition: Process.cpp:3370
llvm::StringRef GetString() const
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:233
NSDictionaryISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
const ExecutionContextRef & GetExecutionContextRef() const
Definition: ValueObject.h:353
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
Execution context objects refer to objects in the execution of the program that is being debugged...
static clang::FieldDecl * AddFieldToRecordType(const CompilerType &type, llvm::StringRef name, const CompilerType &field_type, lldb::AccessType access, uint32_t bitfield_bit_size)
static size_t CalculateNumChildren(CompilerType container_type, CompilerType element_type, lldb_private::ExecutionContextScope *exe_scope=nullptr)
Definition: VectorType.cpp:168
uint64_t __NSDictionaryMSize_Impl(lldb_private::Process &process, lldb::addr_t valobj_addr, Status &error)
static AdditionalFormatters< CXXSyntheticChildren::CreateFrontEndCallback > & GetAdditionalSynthetics()
A class to manage flags.
Definition: Flags.h:22
uint64_t addr_t
Definition: lldb-types.h:83
A uniqued constant string class.
Definition: ConstString.h:38
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:247
lldb::ProcessSP GetProcessSP() const
Definition: ValueObject.h:361
Non-standardized C, such as K&R.
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
Definition: SBAddress.h:15
lldb::ValueObjectSP GetSP()
Definition: ValueObject.h:565
bool NSDictionarySummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
uint64_t __NSDictionaryMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, Status &error)
CompilerType GetTypeForIdentifier(ConstString type_name, clang::DeclContext *decl_context=nullptr)
static Language * FindPlugin(lldb::LanguageType language)
Definition: Language.cpp:54
size_t GetIndexOfChildWithName(ConstString name) override
template bool NSDictionarySummaryProvider< true >(ValueObject &, Stream &, const TypeSummaryOptions &)
size_t GetIndexOfChildWithName(ConstString name) override
CompilerType GetBasicType(lldb::BasicType type)
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
std::function< SyntheticChildrenFrontEnd *(CXXSyntheticChildren *, lldb::ValueObjectSP)> CreateFrontEndCallback
An error handling class.
Definition: Status.h:44
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:1966