mib updated this revision to Diff 258431.
mib marked 2 inline comments as done.
mib added a comment.

Address Davide's comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D78396/new/

https://reviews.llvm.org/D78396

Files:
  lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp
  lldb/source/Plugins/Language/ObjC/CFBasicHash.h
  lldb/source/Plugins/Language/ObjC/CMakeLists.txt
  lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
  lldb/source/Plugins/Language/ObjC/NSDictionary.h
  lldb/source/Plugins/Language/ObjC/NSSet.cpp
  lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
  
lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
  lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m

Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/main.m
@@ -376,10 +376,12 @@
 	    [newMutableDictionary setObject:@"foo" forKey:@"bar19"];
 	    [newMutableDictionary setObject:@"foo" forKey:@"bar20"];
 
-	    id cfKeys[2] = { @"foo", @"bar", @"baz", @"quux" };
-	    id cfValues[2] = { @"foo", @"bar", @"baz", @"quux" };
-	    NSDictionary *nsDictionary = CFBridgingRelease(CFDictionaryCreate(nil, (void *)cfKeys, (void *)cfValues, 2, nil, nil));
-	    CFDictionaryRef cfDictionaryRef = CFDictionaryCreate(nil, (void *)cfKeys, (void *)cfValues, 3, nil, nil);
+            id cfKeys[4] = {@"foo", @"bar", @"baz", @"quux"};
+            id cfValues[4] = {@"foo", @"bar", @"baz", @"quux"};
+            NSDictionary *nsDictionary = CFBridgingRelease(CFDictionaryCreate(nil, (void *)cfKeys, (void *)cfValues, 2, nil, nil));
+            NSDictionary *nscfDictionary = CFBridgingRelease(CFDictionaryCreate(
+                nil, (void *)cfKeys, (void *)cfValues, 4, nil, nil));
+            CFDictionaryRef cfDictionaryRef = CFDictionaryCreate(nil, (void *)cfKeys, (void *)cfValues, 3, nil, nil);
 
 	    NSAttributedString* attrString = [[NSAttributedString alloc] initWithString:@"hello world from foo" attributes:newDictionary];
 	    [attrString isEqual:nil];
@@ -412,8 +414,10 @@
 	    NSSet* nsset = [[NSSet alloc] initWithObjects:str1,str2,str3,nil];
 	    NSSet *nsmutableset = [[NSMutableSet alloc] initWithObjects:str1,str2,str3,nil];
 	    [nsmutableset addObject:str4];
+            NSSet *nscfSet =
+                CFBridgingRelease(CFSetCreate(nil, (void *)cfValues, 2, nil));
 
-	    CFDataRef data_ref = CFDataCreate(kCFAllocatorDefault, [immutableData bytes], 5);
+            CFDataRef data_ref = CFDataCreate(kCFAllocatorDefault, [immutableData bytes], 5);
 
 	    CFMutableDataRef mutable_data_ref = CFDataCreateMutable(kCFAllocatorDefault, 8);
 	    CFDataAppendBytes(mutable_data_ref, [mutableData bytes], 5);
Index: lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSContainer.py
@@ -20,6 +20,7 @@
         self.appkit_tester_impl(self.nscontainers_data_formatter_commands)
 
     def nscontainers_data_formatter_commands(self):
+        
         self.expect(
             'frame variable newArray nsDictionary newDictionary nscfDictionary cfDictionaryRef newMutableDictionary cfarray_ref mutable_array_ref',
             substrs=[
@@ -29,6 +30,8 @@
                 ' 2 key/value pairs',
                 '(NSDictionary *) newDictionary = ',
                 ' 12 key/value pairs',
+                '(NSDictionary *) nscfDictionary = ',
+                ' 4 key/value pairs',
                 '(CFDictionaryRef) cfDictionaryRef = ',
                 ' 3 key/value pairs',
                 '(NSDictionary *) newMutableDictionary = ',
@@ -39,6 +42,36 @@
                 ' @"11 elements"',
             ])
 
+        self.expect(
+            'frame variable -d run-target *nscfDictionary',
+            patterns=[
+                '\(__NSCFDictionary\) \*nscfDictionary =',
+                'key = 0x.* @"foo"',
+                'value = 0x.* @"foo"',
+                'key = 0x.* @"bar"',
+                'value = 0x.* @"bar"',
+                'key = 0x.* @"baz"',
+                'value = 0x.* @"baz"',
+                'key = 0x.* @"quux"',
+                'value = 0x.* @"quux"',
+                ])
+                
+                
+        self.expect(
+          'frame var nscfSet',
+          substrs=[
+          '(NSSet *) nscfSet = ',
+          '2 elements',
+          ])
+          
+        self.expect(
+          'frame variable -d run-target *nscfSet',
+          patterns=[
+              '\(__NSCFSet\) \*nscfSet =',
+              '\[0\] = 0x.* @".*"',
+              '\[1\] = 0x.* @".*"',
+                    ])
+                  
         self.expect(
             'frame variable iset1 iset2 imset',
             substrs=['4 indexes', '512 indexes', '10 indexes'])
Index: lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -606,6 +606,11 @@
                   lldb_private::formatters::NSSetSyntheticFrontEndCreator,
                   "__NSSetM synthetic children", ConstString("__NSSetM"),
                   ScriptedSyntheticChildren::Flags());
+  AddCXXSynthetic(objc_category_sp,
+                  lldb_private::formatters::NSSetSyntheticFrontEndCreator,
+                  "__NSCFSet synthetic children", ConstString("__NSCFSet"),
+                  ScriptedSyntheticChildren::Flags());
+
   AddCXXSynthetic(
       objc_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator,
       "NSMutableSet synthetic children", ConstString("NSMutableSet"),
Index: lldb/source/Plugins/Language/ObjC/NSSet.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/NSSet.cpp
+++ lldb/source/Plugins/Language/ObjC/NSSet.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "NSSet.h"
+#include "CFBasicHash.h"
 
 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
@@ -79,6 +80,54 @@
   std::vector<SetItemDescriptor> m_children;
 };
 
+class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+  NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+  ~NSCFSetSyntheticFrontEnd() override;
+
+  size_t CalculateNumChildren() override;
+
+  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+  bool Update() override;
+
+  bool MightHaveChildren() override;
+
+  size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+  struct SetItemDescriptor {
+    lldb::addr_t item_ptr;
+    lldb::ValueObjectSP valobj_sp;
+  };
+
+  ExecutionContextRef m_exe_ctx_ref;
+  uint8_t m_ptr_size;
+  lldb::ByteOrder m_order;
+
+  CFBasicHash m_hashtable;
+
+  CompilerType m_pair_type;
+  std::vector<SetItemDescriptor> m_children;
+
+private:
+  // Prime numbers. Values above 100 have been adjusted up so that the
+  // malloced block size will be just below a multiple of 512; values
+  // above 1200 have been adjusted up to just below a multiple of 4096.
+  constexpr static const uintptr_t NSDictionaryCapacities[] = {
+      0,        3,        6,         11,        19,        32,       52,
+      85,       118,      155,       237,       390,       672,      1065,
+      1732,     2795,     4543,      7391,      12019,     19302,    31324,
+      50629,    81956,    132580,    214215,    346784,    561026,   907847,
+      1468567,  2376414,  3844982,   6221390,   10066379,  16287773, 26354132,
+      42641916, 68996399, 111638327, 180634415, 292272755,
+  };
+
+  static const size_t NSDictionaryNumSizeBuckets =
+      sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
+};
+
 template <typename D32, typename D64>
 class GenericNSSetMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
 public:
@@ -245,21 +294,24 @@
 
   uint64_t value = 0;
 
-  ConstString class_name_cs = descriptor->GetClassName();
-  const char *class_name = class_name_cs.GetCString();
+  ConstString class_name(descriptor->GetClassName());
 
-  if (!class_name || !*class_name)
+  static const ConstString g_SetI("__NSSetI");
+  static const ConstString g_OrderedSetI("__NSOrderedSetI");
+  static const ConstString g_SetM("__NSSetM");
+  static const ConstString g_SetCF("__NSCFSet");
+
+  if (class_name.IsEmpty())
     return false;
 
-  if (!strcmp(class_name, "__NSSetI") ||
-      !strcmp(class_name, "__NSOrderedSetI")) {
+  if (class_name == g_SetI || class_name == g_OrderedSetI) {
     Status error;
     value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
                                                       ptr_size, 0, error);
     if (error.Fail())
       return false;
     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
-  } else if (!strcmp(class_name, "__NSSetM")) {
+  } else if (class_name == g_SetM) {
     AppleObjCRuntime *apple_runtime =
         llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
     Status error;
@@ -272,9 +324,15 @@
     }
     if (error.Fail())
       return false;
+  } else if (class_name == g_SetCF) {
+    ExecutionContext exe_ctx(process_sp);
+    CFBasicHash cfbh;
+    if (!cfbh.Update(valobj_addr, exe_ctx))
+      return false;
+    value = cfbh.GetCount();
   } else {
     auto &map(NSSet_Additionals::GetAdditionalSummaries());
-    auto iter = map.find(class_name_cs), end = map.end();
+    auto iter = map.find(class_name), end = map.end();
     if (iter != end)
       return iter->second(valobj, stream, options);
     else
@@ -321,16 +379,19 @@
   if (!descriptor || !descriptor->IsValid())
     return nullptr;
 
-  ConstString class_name_cs = descriptor->GetClassName();
-  const char *class_name = class_name_cs.GetCString();
+  ConstString class_name = descriptor->GetClassName();
 
-  if (!class_name || !*class_name)
+  static const ConstString g_SetI("__NSSetI");
+  static const ConstString g_OrderedSetI("__NSOrderedSetI");
+  static const ConstString g_SetM("__NSSetM");
+  static const ConstString g_SetCF("__NSCFSet");
+
+  if (class_name.IsEmpty())
     return nullptr;
 
-  if (!strcmp(class_name, "__NSSetI") ||
-      !strcmp(class_name, "__NSOrderedSetI")) {
+  if (class_name == g_SetI || class_name == g_OrderedSetI) {
     return (new NSSetISyntheticFrontEnd(valobj_sp));
-  } else if (!strcmp(class_name, "__NSSetM")) {
+  } else if (class_name == g_SetM) {
     AppleObjCRuntime *apple_runtime =
         llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
     if (apple_runtime) {
@@ -343,9 +404,11 @@
     } else {
       return (new Foundation1300::NSSetMSyntheticFrontEnd(valobj_sp));
     }
+  } else if (class_name == g_SetCF) {
+    return (new NSCFSetSyntheticFrontEnd(valobj_sp));
   } else {
     auto &map(NSSet_Additionals::GetAdditionalSynthetics());
-    auto iter = map.find(class_name_cs), end = map.end();
+    auto iter = map.find(class_name), end = map.end();
     if (iter != end)
       return iter->second(synth, valobj_sp);
     return nullptr;
@@ -501,6 +564,124 @@
   return set_item.valobj_sp;
 }
 
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::NSCFSetSyntheticFrontEnd(
+    lldb::ValueObjectSP valobj_sp)
+    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
+      m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {}
+
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::
+    ~NSCFSetSyntheticFrontEnd() {}
+
+size_t
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName(
+    ConstString name) {
+  const char *item_name = name.GetCString();
+  uint32_t idx = ExtractIndexFromString(item_name);
+  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+    return UINT32_MAX;
+  return idx;
+}
+
+size_t
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() {
+  if (!m_hashtable.IsValid())
+    return 0;
+  return m_hashtable.GetCount();
+}
+
+bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() {
+  m_children.clear();
+  ValueObjectSP valobj_sp = m_backend.GetSP();
+  m_ptr_size = 0;
+  if (!valobj_sp)
+    return false;
+  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+  if (!process_sp)
+    return false;
+  m_ptr_size = process_sp->GetAddressByteSize();
+  m_order = process_sp->GetByteOrder();
+  return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
+}
+
+bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() {
+  return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex(
+    size_t idx) {
+  lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
+
+  uint32_t num_children = CalculateNumChildren();
+
+  if (idx >= num_children)
+    return lldb::ValueObjectSP();
+
+  if (m_children.empty()) {
+    ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+    if (!process_sp)
+      return lldb::ValueObjectSP();
+
+    Status error;
+    lldb::addr_t val_at_idx = 0;
+
+    uint32_t tries = 0;
+    uint32_t test_idx = 0;
+
+    while (tries < num_children) {
+      val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
+
+      val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+      if (error.Fail())
+        return lldb::ValueObjectSP();
+
+      test_idx++;
+
+      if (!val_at_idx)
+        continue;
+      tries++;
+
+      SetItemDescriptor descriptor = {val_at_idx, lldb::ValueObjectSP()};
+
+      m_children.push_back(descriptor);
+    }
+  }
+
+  if (idx >= m_children.size()) // should never happen
+    return lldb::ValueObjectSP();
+
+  SetItemDescriptor &set_item = m_children[idx];
+  if (!set_item.valobj_sp) {
+    auto ptr_size = m_ptr_size;
+    DataBufferHeap buffer(ptr_size, 0);
+    switch (ptr_size) {
+    case 0: // architecture has no clue?? - fail
+      return lldb::ValueObjectSP();
+    case 4:
+      *((uint32_t *)buffer.GetBytes()) = (uint32_t)set_item.item_ptr;
+      break;
+    case 8:
+      *((uint64_t *)buffer.GetBytes()) = (uint64_t)set_item.item_ptr;
+      break;
+    default:
+      assert(false && "pointer size is not 4 nor 8 - get out of here ASAP");
+    }
+    StreamString idx_name;
+    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+
+    DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), m_order,
+                       m_ptr_size);
+
+    set_item.valobj_sp = CreateValueObjectFromData(
+        idx_name.GetString(), data, m_exe_ctx_ref,
+        m_backend.GetCompilerType().GetBasicTypeFromAST(
+            lldb::eBasicTypeObjCID));
+  }
+  return set_item.valobj_sp;
+}
+
 template <typename D32, typename D64>
 lldb_private::formatters::
   GenericNSSetMSyntheticFrontEnd<D32, D64>::GenericNSSetMSyntheticFrontEnd(
Index: lldb/source/Plugins/Language/ObjC/NSDictionary.h
===================================================================
--- lldb/source/Plugins/Language/ObjC/NSDictionary.h
+++ lldb/source/Plugins/Language/ObjC/NSDictionary.h
@@ -1,5 +1,4 @@
-//===-- NSDictionary.h ---------------------------------------------------*- C++
-//-*-===//
+//===-- NSDictionary.h ------------------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
Index: lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
===================================================================
--- lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
+++ lldb/source/Plugins/Language/ObjC/NSDictionary.cpp
@@ -10,6 +10,7 @@
 
 #include "clang/AST/DeclCXX.h"
 
+#include "CFBasicHash.h"
 #include "NSDictionary.h"
 
 #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
@@ -140,6 +141,55 @@
   std::vector<DictionaryItemDescriptor> m_children;
 };
 
+class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
+public:
+  NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+  ~NSCFDictionarySyntheticFrontEnd() override;
+
+  size_t CalculateNumChildren() override;
+
+  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+  bool Update() override;
+
+  bool MightHaveChildren() override;
+
+  size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+  struct DictionaryItemDescriptor {
+    lldb::addr_t key_ptr;
+    lldb::addr_t val_ptr;
+    lldb::ValueObjectSP valobj_sp;
+  };
+
+  ExecutionContextRef m_exe_ctx_ref;
+  uint8_t m_ptr_size;
+  lldb::ByteOrder m_order;
+
+  CFBasicHash m_hashtable;
+
+  CompilerType m_pair_type;
+  std::vector<DictionaryItemDescriptor> m_children;
+
+private:
+  // Prime numbers. Values above 100 have been adjusted up so that the
+  // malloced block size will be just below a multiple of 512; values
+  // above 1200 have been adjusted up to just below a multiple of 4096.
+  constexpr static const uintptr_t NSDictionaryCapacities[] = {
+      0,        3,        6,         11,        19,        32,       52,
+      85,       118,      155,       237,       390,       672,      1065,
+      1732,     2795,     4543,      7391,      12019,     19302,    31324,
+      50629,    81956,    132580,    214215,    346784,    561026,   907847,
+      1468567,  2376414,  3844982,   6221390,   10066379,  16287773, 26354132,
+      42641916, 68996399, 111638327, 180634415, 292272755,
+  };
+
+  static const size_t NSDictionaryNumSizeBuckets =
+      sizeof(NSDictionaryCapacities) / sizeof(uint64_t);
+};
+
 class NSDictionary1SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
 public:
   NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@@ -377,6 +427,7 @@
   static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
   static const ConstString g_Dictionary0("__NSDictionary0");
   static const ConstString g_DictionaryCF("__NSCFDictionary");
+  static const ConstString g_DictionaryCFRef("CFDictionaryRef");
 
   if (class_name.IsEmpty())
     return false;
@@ -388,8 +439,7 @@
     if (error.Fail())
       return false;
     value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
-  } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy ||
-             class_name == g_DictionaryCF) {
+  } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) {
     AppleObjCRuntime *apple_runtime =
     llvm::dyn_cast_or_null<AppleObjCRuntime>(runtime);
     Status error;
@@ -407,8 +457,13 @@
     value = 1;
   } else if (class_name == g_Dictionary0) {
     value = 0;
-  }
-  else {
+  } else if (class_name == g_DictionaryCF || class_name == g_DictionaryCFRef) {
+    ExecutionContext exe_ctx(process_sp);
+    CFBasicHash cfbh;
+    if (!cfbh.Update(valobj_addr, exe_ctx))
+      return false;
+    value = cfbh.GetCount();
+  } else {
     auto &map(NSDictionary_Additionals::GetAdditionalSummaries());
     for (auto &candidate : map) {
       if (candidate.first && candidate.first->Match(class_name))
@@ -466,6 +521,8 @@
   static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
   static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
   static const ConstString g_Dictionary0("__NSDictionary0");
+  static const ConstString g_DictionaryCF("__NSCFDictionary");
+  static const ConstString g_DictionaryCFRef("CFDictionaryRef");
 
   if (class_name.IsEmpty())
     return nullptr;
@@ -484,6 +541,8 @@
       return (new Foundation1100::NSDictionaryMSyntheticFrontEnd(valobj_sp));
   } else if (class_name == g_Dictionary1) {
     return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
+  } else if (class_name == g_DictionaryCF || class_name == g_DictionaryCFRef) {
+    return (new NSCFDictionarySyntheticFrontEnd(valobj_sp));
   } else {
     auto &map(NSDictionary_Additionals::GetAdditionalSynthetics());
     for (auto &candidate : map) {
@@ -641,6 +700,132 @@
   return dict_item.valobj_sp;
 }
 
+lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+    NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+    : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
+      m_order(lldb::eByteOrderInvalid), m_hashtable(), m_pair_type() {}
+
+lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+    ~NSCFDictionarySyntheticFrontEnd() {}
+
+size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+    GetIndexOfChildWithName(ConstString name) {
+  const char *item_name = name.GetCString();
+  uint32_t idx = ExtractIndexFromString(item_name);
+  if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+    return UINT32_MAX;
+  return idx;
+}
+
+size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+    CalculateNumChildren() {
+  if (!m_hashtable.IsValid())
+    return 0;
+  return m_hashtable.GetCount();
+}
+
+bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() {
+  m_children.clear();
+  ValueObjectSP valobj_sp = m_backend.GetSP();
+  m_ptr_size = 0;
+  if (!valobj_sp)
+    return false;
+  m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+  lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+  if (!process_sp)
+    return false;
+  m_ptr_size = process_sp->GetAddressByteSize();
+  m_order = process_sp->GetByteOrder();
+  return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref);
+}
+
+bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::
+    MightHaveChildren() {
+  return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex(
+    size_t idx) {
+  lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer();
+  lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer();
+
+  uint32_t num_children = CalculateNumChildren();
+
+  if (idx >= num_children)
+    return lldb::ValueObjectSP();
+
+  if (m_children.empty()) {
+    ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+    if (!process_sp)
+      return lldb::ValueObjectSP();
+
+    Status error;
+    lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+    uint32_t tries = 0;
+    uint32_t test_idx = 0;
+
+    while (tries < num_children) {
+      key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
+      val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
+
+      key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
+      if (error.Fail())
+        return lldb::ValueObjectSP();
+      val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+      if (error.Fail())
+        return lldb::ValueObjectSP();
+
+      test_idx++;
+
+      if (!key_at_idx || !val_at_idx)
+        continue;
+      tries++;
+
+      DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
+                                             lldb::ValueObjectSP()};
+
+      m_children.push_back(descriptor);
+    }
+  }
+
+  if (idx >= m_children.size()) // should never happen
+    return lldb::ValueObjectSP();
+
+  DictionaryItemDescriptor &dict_item = m_children[idx];
+  if (!dict_item.valobj_sp) {
+    if (!m_pair_type.IsValid()) {
+      TargetSP target_sp(m_backend.GetTargetSP());
+      if (!target_sp)
+        return ValueObjectSP();
+      m_pair_type = GetLLDBNSPairType(target_sp);
+    }
+    if (!m_pair_type.IsValid())
+      return ValueObjectSP();
+
+    DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
+
+    if (m_ptr_size == 8) {
+      uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+      *data_ptr = dict_item.key_ptr;
+      *(data_ptr + 1) = dict_item.val_ptr;
+    } else {
+      uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+      *data_ptr = dict_item.key_ptr;
+      *(data_ptr + 1) = dict_item.val_ptr;
+    }
+
+    StreamString idx_name;
+    idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
+    DataExtractor data(buffer_sp, m_order, m_ptr_size);
+    dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
+                                                    m_exe_ctx_ref, m_pair_type);
+  }
+  return dict_item.valobj_sp;
+}
+
 lldb_private::formatters::NSDictionary1SyntheticFrontEnd::
     NSDictionary1SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
     : SyntheticChildrenFrontEnd(*valobj_sp.get()), m_pair(nullptr) {}
@@ -733,8 +918,8 @@
 }
 
 template <typename D32, typename D64>
-size_t
-lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::    GetIndexOfChildWithName(ConstString name) {
+size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
+    D32, D64>::GetIndexOfChildWithName(ConstString name) {
   const char *item_name = name.GetCString();
   uint32_t idx = ExtractIndexFromString(item_name);
   if (idx < UINT32_MAX && idx >= CalculateNumChildren())
@@ -783,7 +968,7 @@
   }
   if (error.Fail())
     return false;
-  return false;
+  return true;
 }
 
 template <typename D32, typename D64>
@@ -795,9 +980,8 @@
 
 template <typename D32, typename D64>
 lldb::ValueObjectSP
-lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::
-    GetChildAtIndex(
-    size_t idx) {
+lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<
+    D32, D64>::GetChildAtIndex(size_t idx) {
   lldb::addr_t m_keys_ptr;
   lldb::addr_t m_values_ptr;
   if (m_data_32) {
@@ -885,7 +1069,6 @@
   return dict_item.valobj_sp;
 }
 
-
 lldb_private::formatters::Foundation1100::
   NSDictionaryMSyntheticFrontEnd::
     NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
Index: lldb/source/Plugins/Language/ObjC/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Language/ObjC/CMakeLists.txt
+++ lldb/source/Plugins/Language/ObjC/CMakeLists.txt
@@ -11,6 +11,7 @@
 add_lldb_library(lldbPluginObjCLanguage PLUGIN
   ObjCLanguage.cpp
   CF.cpp
+  CFBasicHash.cpp
   Cocoa.cpp
   CoreMedia.cpp
   NSArray.cpp
Index: lldb/source/Plugins/Language/ObjC/CFBasicHash.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Language/ObjC/CFBasicHash.h
@@ -0,0 +1,126 @@
+//===-- CFBasicHash.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H
+#define LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+namespace lldb_private {
+
+class CFBasicHash {
+public:
+  enum class HashType { set = 0, dict };
+
+  CFBasicHash();
+  ~CFBasicHash();
+
+  bool Update(lldb::addr_t addr, ExecutionContextRef exe_ctx_rf);
+
+  bool IsValid() const;
+
+  bool IsMutable() const { return m_mutable; };
+  bool IsMultiVariant() const { return m_multi; }
+  HashType GetType() const { return m_type; }
+
+  size_t GetCount() const;
+  lldb::addr_t GetKeyPointer() const;
+  lldb::addr_t GetValuePointer() const;
+
+  constexpr static const uintptr_t __CFBasicHashTableSizes[64] = {0,
+                                                                  3,
+                                                                  7,
+                                                                  13,
+                                                                  23,
+                                                                  41,
+                                                                  71,
+                                                                  127,
+                                                                  191,
+                                                                  251,
+                                                                  383,
+                                                                  631,
+                                                                  1087,
+                                                                  1723,
+                                                                  2803,
+                                                                  4523,
+                                                                  7351,
+                                                                  11959,
+                                                                  19447,
+                                                                  31231,
+                                                                  50683,
+                                                                  81919,
+                                                                  132607,
+                                                                  214519,
+                                                                  346607,
+                                                                  561109,
+                                                                  907759,
+                                                                  1468927,
+                                                                  2376191,
+                                                                  3845119,
+                                                                  6221311,
+                                                                  10066421,
+                                                                  16287743,
+                                                                  26354171,
+                                                                  42641881,
+                                                                  68996069,
+                                                                  111638519,
+                                                                  180634607,
+                                                                  292272623,
+                                                                  472907251,
+                                                                  765180413UL,
+                                                                  1238087663UL,
+                                                                  2003267557UL,
+                                                                  3241355263UL,
+                                                                  5244622819UL};
+
+private:
+  template <typename T> struct __CFBasicHash {
+    struct RuntimeBase {
+      T cfisa;
+      T cfinfoa;
+    } base;
+
+    struct Bits {
+      uint16_t __reserved0;
+      uint16_t __reserved1 : 2;
+      uint16_t keys_offset : 1;
+      uint16_t counts_offset : 2;
+      uint16_t counts_width : 2;
+      uint16_t __reserved2 : 9;
+      uint32_t used_buckets;        // number of used buckets
+      uint64_t deleted : 16;        // number of elements deleted
+      uint64_t num_buckets_idx : 8; // index to number of buckets
+      uint64_t __reserved3 : 40;
+      uint64_t __reserved4;
+    } bits;
+
+    T pointers[3];
+  };
+
+  size_t GetPointerCount() const;
+
+private:
+  uint32_t m_ptr_size;
+  lldb::ByteOrder m_byte_order;
+
+  Address m_address;
+
+  __CFBasicHash<uint32_t> *m_ht_32;
+  __CFBasicHash<uint64_t> *m_ht_64;
+
+  ExecutionContextRef m_exe_ctx_ref;
+
+  bool m_mutable;
+  bool m_multi;
+  HashType m_type;
+};
+
+}; // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_OBJC_CFBASICHASH_H
Index: lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Language/ObjC/CFBasicHash.cpp
@@ -0,0 +1,183 @@
+#include "CFBasicHash.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CFBasicHash::CFBasicHash()
+    : m_ptr_size(UINT32_MAX), m_byte_order(eByteOrderInvalid),
+      m_address(LLDB_INVALID_ADDRESS) {}
+
+CFBasicHash::~CFBasicHash() { }
+
+bool CFBasicHash::IsValid() const {
+  if (m_address != LLDB_INVALID_ADDRESS) {
+    if (m_ptr_size == 4 && m_ht_32)
+      return true;
+    else if (m_ptr_size == 8 && m_ht_64)
+      return true;
+  }
+  return false;
+}
+
+bool CFBasicHash::Update(addr_t addr, ExecutionContextRef exe_ctx_rf) {
+  if (addr == LLDB_INVALID_ADDRESS || !addr)
+    return false;
+
+  m_address = addr;
+  m_exe_ctx_ref = exe_ctx_rf;
+  m_ptr_size =
+      m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetAddressByteSize();
+  m_byte_order = m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetByteOrder();
+  Status error;
+  size_t size = 0;
+
+  if (m_ptr_size == 4) {
+
+    size = sizeof(__CFBasicHash<uint32_t>::RuntimeBase);
+    size += sizeof(__CFBasicHash<uint32_t>::Bits);
+
+    DataBufferHeap buffer(size, 0);
+    m_exe_ctx_ref.GetProcessSP()->ReadMemory(addr, buffer.GetBytes(), size,
+                                             error);
+    if (error.Fail())
+      return false;
+
+    DataExtractor data_extractor = DataExtractor(
+        buffer.GetBytes(), buffer.GetByteSize(), m_byte_order, m_ptr_size);
+
+    m_ht_32 = new __CFBasicHash<uint32_t>();
+    size_t copied = data_extractor.CopyData(0, size, m_ht_32);
+
+    if (copied != size) {
+      delete m_ht_32;
+      m_ht_32 = nullptr;
+      return false;
+    }
+
+    m_mutable = !(m_ht_32->base.cfinfoa & (1 << 6));
+    m_multi = m_ht_32->bits.counts_offset;
+    m_type = static_cast<HashType>(m_ht_32->bits.keys_offset);
+    addr_t ptr_offset = addr + size;
+    size_t ptr_count = GetPointerCount();
+    size = ptr_count * sizeof(uint32_t);
+    buffer = DataBufferHeap(size, 0);
+    m_exe_ctx_ref.GetProcessSP()->ReadMemory(ptr_offset, buffer.GetBytes(),
+                                             size, error);
+
+    if (error.Fail()) {
+      delete m_ht_32;
+      m_ht_32 = nullptr;
+      return false;
+    }
+
+    data_extractor = DataExtractor(buffer.GetBytes(), buffer.GetByteSize(),
+                                   m_byte_order, m_ptr_size);
+
+    copied = data_extractor.CopyData(0, size, m_ht_32->pointers);
+
+    if (copied != size) {
+      delete m_ht_32;
+      m_ht_32 = nullptr;
+      return false;
+    }
+
+    return true;
+
+  } else if (m_ptr_size == 8) {
+
+    size = sizeof(__CFBasicHash<uint64_t>::RuntimeBase);
+    size += sizeof(__CFBasicHash<uint64_t>::Bits);
+
+    DataBufferHeap buffer(size, 0);
+    m_exe_ctx_ref.GetProcessSP()->ReadMemory(addr, buffer.GetBytes(), size,
+                                             error);
+    if (error.Fail())
+      return false;
+
+    DataExtractor data_extractor = DataExtractor(
+        buffer.GetBytes(), buffer.GetByteSize(), m_byte_order, m_ptr_size);
+
+    m_ht_64 = new __CFBasicHash<uint64_t>();
+    size_t copied = data_extractor.CopyData(0, size, m_ht_64);
+
+    if (copied != size) {
+      delete m_ht_64;
+      m_ht_64 = nullptr;
+      return false;
+    }
+
+    m_mutable = !(m_ht_64->base.cfinfoa & (1 << 6));
+    m_multi = m_ht_64->bits.counts_offset;
+    m_type = static_cast<HashType>(m_ht_64->bits.keys_offset);
+    addr_t ptr_offset = addr + size;
+    size_t ptr_count = GetPointerCount();
+    size = ptr_count * sizeof(uint64_t);
+    buffer = DataBufferHeap(size, 0);
+    m_exe_ctx_ref.GetProcessSP()->ReadMemory(ptr_offset, buffer.GetBytes(),
+                                             size, error);
+
+    if (error.Fail()) {
+      delete m_ht_64;
+      m_ht_64 = nullptr;
+      return false;
+    }
+
+    data_extractor = DataExtractor(buffer.GetBytes(), buffer.GetByteSize(),
+                                   m_byte_order, m_ptr_size);
+
+    copied = data_extractor.CopyData(0, size, m_ht_64->pointers);
+
+    if (copied != size) {
+      delete m_ht_64;
+      m_ht_64 = nullptr;
+      return false;
+    }
+
+    return true;
+  }
+
+  llvm_unreachable("Unsupported architecture. Only 32bits and 64bits supported.");
+}
+
+size_t CFBasicHash::GetCount() const {
+  if (!IsValid())
+    return 0;
+
+  if (!m_multi)
+    return (m_ptr_size == 4) ? m_ht_32->bits.used_buckets
+                             : m_ht_64->bits.used_buckets;
+
+  //  FIXME: Add support for multi
+  return 0;
+}
+
+size_t CFBasicHash::GetPointerCount() const {
+  if (!IsValid())
+    return 0;
+
+  if (m_multi)
+    return 3; // Bits::counts_offset;
+  return (m_type == HashType::dict) + 1;
+}
+
+addr_t CFBasicHash::GetKeyPointer() const {
+  if (!IsValid())
+    return LLDB_INVALID_ADDRESS;
+
+  if (m_ptr_size == 4)
+    return m_ht_32->pointers[m_ht_32->bits.keys_offset];
+
+  return m_ht_64->pointers[m_ht_64->bits.keys_offset];
+}
+
+addr_t CFBasicHash::GetValuePointer() const {
+  if (!IsValid())
+    return LLDB_INVALID_ADDRESS;
+
+  if (m_ptr_size == 4)
+    return m_ht_32->pointers[0];
+
+  return m_ht_64->pointers[0];
+}
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to