This revision was automatically updated to reflect the committed changes.
Closed by commit rGfc43703481d8: [lldb] Use objc_getRealizedClassList_trylock 
on macOS Ventura and later (authored by JDevlieghere).

Changed prior to commit:
  https://reviews.llvm.org/D127252?vs=434941&id=435269#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D127252

Files:
  lldb/packages/Python/lldbsuite/test/decorators.py
  
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
  lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
  
lldb/test/API/lang/objc/conflicting-class-list-function-from-user/TestObjCClassListFunctionFromUser.py

Index: lldb/test/API/lang/objc/conflicting-class-list-function-from-user/TestObjCClassListFunctionFromUser.py
===================================================================
--- lldb/test/API/lang/objc/conflicting-class-list-function-from-user/TestObjCClassListFunctionFromUser.py
+++ lldb/test/API/lang/objc/conflicting-class-list-function-from-user/TestObjCClassListFunctionFromUser.py
@@ -10,7 +10,7 @@
     @skipUnlessDarwin
     # LLDB ends up calling the user-defined function (but at least doesn't
     # crash).
-    @expectedFailureDarwin
+    @skipIf(macos_version=["<", "13.0"])
     def test(self):
         """
         Tests LLDB's behaviour if the user defines their own conflicting
Index: lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -313,13 +313,15 @@
   };
 
   /// We can read the class info from the Objective-C runtime using
-  /// gdb_objc_realized_classes or objc_copyRealizedClassList. The latter is
-  /// preferred because it includes lazily named classes, but it's not always
-  /// available or safe to call.
+  /// gdb_objc_realized_classes, objc_copyRealizedClassList or
+  /// objc_getRealizedClassList_trylock. The RealizedClassList variants are
+  /// preferred because they include lazily named classes, but they are not
+  /// always available or safe to call.
   ///
-  /// We potentially need both for the same process, because we may need to use
-  /// gdb_objc_realized_classes until dyld is initialized and then switch over
-  /// to objc_copyRealizedClassList for lazily named classes.
+  /// We potentially need more than one helper for the same process, because we
+  /// may need to use gdb_objc_realized_classes until dyld is initialized and
+  /// then switch over to objc_copyRealizedClassList or
+  /// objc_getRealizedClassList_trylock for lazily named classes.
   class DynamicClassInfoExtractor : public ClassInfoExtractor {
   public:
     DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
@@ -329,11 +331,16 @@
     UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table);
 
   private:
-    enum Helper { gdb_objc_realized_classes, objc_copyRealizedClassList };
+    enum Helper {
+      gdb_objc_realized_classes,
+      objc_copyRealizedClassList,
+      objc_getRealizedClassList_trylock
+    };
 
-    /// Compute which helper to use. Prefer objc_copyRealizedClassList if it's
-    /// available and it's safe to call (i.e. dyld is fully initialized). Use
-    /// gdb_objc_realized_classes otherwise.
+    /// Compute which helper to use. If dyld is not yet fully initialized we
+    /// must use gdb_objc_realized_classes. Otherwise, we prefer
+    /// objc_getRealizedClassList_trylock and objc_copyRealizedClassList
+    /// respectively, depending on availability.
     Helper ComputeHelper() const;
 
     UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx,
@@ -341,23 +348,17 @@
     lldb::addr_t &GetClassInfoArgs(Helper helper);
 
     std::unique_ptr<UtilityFunction>
-    GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, std::string code,
-                                    std::string name);
-
-    /// Helper to read class info using the gdb_objc_realized_classes.
-    struct gdb_objc_realized_classes_helper {
-      std::unique_ptr<UtilityFunction> utility_function;
-      lldb::addr_t args = LLDB_INVALID_ADDRESS;
-    };
+    GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, Helper helper,
+                                    std::string code, std::string name);
 
-    /// Helper to read class info using objc_copyRealizedClassList.
-    struct objc_copyRealizedClassList_helper {
+    struct UtilityFunctionHelper {
       std::unique_ptr<UtilityFunction> utility_function;
       lldb::addr_t args = LLDB_INVALID_ADDRESS;
     };
 
-    gdb_objc_realized_classes_helper m_gdb_objc_realized_classes_helper;
-    objc_copyRealizedClassList_helper m_objc_copyRealizedClassList_helper;
+    UtilityFunctionHelper m_gdb_objc_realized_classes_helper;
+    UtilityFunctionHelper m_objc_copyRealizedClassList_helper;
+    UtilityFunctionHelper m_objc_getRealizedClassList_trylock_helper;
   };
 
   /// Abstraction to read the Objective-C class info from the shared cache.
@@ -429,6 +430,7 @@
   HashTableSignature m_hash_signature;
   bool m_has_object_getClass;
   bool m_has_objc_copyRealizedClassList;
+  bool m_has_objc_getRealizedClassList_trylock;
   bool m_loaded_objc_opt;
   std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up;
   std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up;
Index: lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -6,20 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <cstdint>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-
-#include "lldb/Host/OptionParser.h"
-#include "lldb/Symbol/CompilerType.h"
-#include "lldb/lldb-enumerations.h"
-
+#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/DebuggerEvents.h"
 #include "lldb/Core/Module.h"
@@ -30,11 +19,13 @@
 #include "lldb/Expression/DiagnosticManager.h"
 #include "lldb/Expression/FunctionCaller.h"
 #include "lldb/Expression/UtilityFunction.h"
+#include "lldb/Host/OptionParser.h"
 #include "lldb/Interpreter/CommandObject.h"
 #include "lldb/Interpreter/CommandObjectMultiword.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Interpreter/OptionArgParser.h"
 #include "lldb/Interpreter/OptionValueBoolean.h"
+#include "lldb/Symbol/CompilerType.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/Symbol.h"
 #include "lldb/Symbol/TypeList.h"
@@ -56,6 +47,7 @@
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/Timer.h"
+#include "lldb/lldb-enumerations.h"
 
 #include "AppleObjCClassDescriptorV2.h"
 #include "AppleObjCDeclVendor.h"
@@ -66,9 +58,11 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/ScopeExit.h"
 
-#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
-
+#include <cstdint>
+#include <memory>
+#include <string>
 #include <vector>
 
 using namespace lldb;
@@ -235,6 +229,78 @@
 }
 )";
 
+static const char *g_get_dynamic_class_info3_name =
+    "__lldb_apple_objc_v2_get_dynamic_class_info3";
+
+static const char *g_get_dynamic_class_info3_body = R"(
+
+extern "C" {
+    int printf(const char * format, ...);
+    void free(void *ptr);
+    size_t objc_getRealizedClassList_trylock(Class *buffer, size_t len);
+    const char* objc_debug_class_getNameRaw(Class cls);
+}
+
+#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
+
+struct ClassInfo
+{
+    Class isa;
+    uint32_t hash;
+} __attribute__((__packed__));
+
+uint32_t
+__lldb_apple_objc_v2_get_dynamic_class_info3(void *gdb_objc_realized_classes_ptr,
+                                             void *class_infos_ptr,
+                                             uint32_t class_infos_byte_size,
+                                             void *class_buffer,
+                                             uint32_t class_buffer_len,
+                                             uint32_t should_log)
+{
+    DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
+    DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
+
+    const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
+    DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);
+
+    ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
+
+    Class *realized_class_list = (Class*)class_buffer;
+
+    uint32_t count = objc_getRealizedClassList_trylock(realized_class_list,
+                                                       class_buffer_len);
+    DEBUG_PRINTF ("count = %u\n", count);
+
+    uint32_t idx = 0;
+    for (uint32_t i=0; i<=count; ++i)
+    {
+        if (idx < max_class_infos)
+        {
+            Class isa = realized_class_list[i];
+            const char *name_ptr = objc_debug_class_getNameRaw(isa);
+            if (name_ptr == NULL)
+                continue;
+            const char *s = name_ptr;
+            uint32_t h = 5381;
+            for (unsigned char c = *s; c; c = *++s)
+                h = ((h << 5) + h) + c;
+            class_infos[idx].hash = h;
+            class_infos[idx].isa = isa;
+            DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);
+        }
+        idx++;
+    }
+
+    if (idx < max_class_infos)
+    {
+        class_infos[idx].isa = NULL;
+        class_infos[idx].hash = 0;
+    }
+
+    return count;
+}
+)";
+
 // We'll substitute in class_getName or class_getNameRaw depending
 // on which is present.
 static const char *g_shared_cache_class_name_funcptr = R"(
@@ -663,7 +729,8 @@
       m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS),
       m_relative_selector_base(LLDB_INVALID_ADDRESS), m_hash_signature(),
       m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false),
-      m_loaded_objc_opt(false), m_non_pointer_isa_cache_up(),
+      m_has_objc_getRealizedClassList_trylock(false), m_loaded_objc_opt(false),
+      m_non_pointer_isa_cache_up(),
       m_tagged_pointer_vendor_up(
           TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)),
       m_encoding_to_type_sp(), m_CFBoolean_values(),
@@ -672,7 +739,11 @@
   m_has_object_getClass = HasSymbol(g_gdb_object_getClass);
   static const ConstString g_objc_copyRealizedClassList(
       "_ZL33objc_copyRealizedClassList_nolockPj");
+  static const ConstString g_objc_getRealizedClassList_trylock(
+      "_objc_getRealizedClassList_trylock");
   m_has_objc_copyRealizedClassList = HasSymbol(g_objc_copyRealizedClassList);
+  m_has_objc_getRealizedClassList_trylock =
+      HasSymbol(g_objc_getRealizedClassList_trylock);
   WarnIfNoExpandedSharedCache();
   RegisterObjCExceptionRecognizer(process);
 }
@@ -1539,7 +1610,8 @@
 
 std::unique_ptr<UtilityFunction>
 AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunctionImpl(
-    ExecutionContext &exe_ctx, std::string code, std::string name) {
+    ExecutionContext &exe_ctx, Helper helper, std::string code,
+    std::string name) {
   Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
 
   LLDB_LOG(log, "Creating utility function {0}", name);
@@ -1574,6 +1646,15 @@
   value.SetValueType(Value::ValueType::Scalar);
   value.SetCompilerType(clang_uint32_t_type);
   arguments.PushValue(value);
+
+  // objc_getRealizedClassList_trylock takes an additional buffer and length.
+  if (helper == Helper::objc_getRealizedClassList_trylock) {
+    value.SetCompilerType(clang_void_pointer_type);
+    arguments.PushValue(value);
+    value.SetCompilerType(clang_uint32_t_type);
+    arguments.PushValue(value);
+  }
+
   arguments.PushValue(value);
 
   std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
@@ -1599,7 +1680,7 @@
   case gdb_objc_realized_classes: {
     if (!m_gdb_objc_realized_classes_helper.utility_function)
       m_gdb_objc_realized_classes_helper.utility_function =
-          GetClassInfoUtilityFunctionImpl(exe_ctx,
+          GetClassInfoUtilityFunctionImpl(exe_ctx, helper,
                                           g_get_dynamic_class_info_body,
                                           g_get_dynamic_class_info_name);
     return m_gdb_objc_realized_classes_helper.utility_function.get();
@@ -1607,11 +1688,19 @@
   case objc_copyRealizedClassList: {
     if (!m_objc_copyRealizedClassList_helper.utility_function)
       m_objc_copyRealizedClassList_helper.utility_function =
-          GetClassInfoUtilityFunctionImpl(exe_ctx,
+          GetClassInfoUtilityFunctionImpl(exe_ctx, helper,
                                           g_get_dynamic_class_info2_body,
                                           g_get_dynamic_class_info2_name);
     return m_objc_copyRealizedClassList_helper.utility_function.get();
   }
+  case objc_getRealizedClassList_trylock: {
+    if (!m_objc_getRealizedClassList_trylock_helper.utility_function)
+      m_objc_copyRealizedClassList_helper.utility_function =
+          GetClassInfoUtilityFunctionImpl(exe_ctx, helper,
+                                          g_get_dynamic_class_info3_body,
+                                          g_get_dynamic_class_info3_name);
+    return m_objc_copyRealizedClassList_helper.utility_function.get();
+  }
   }
   llvm_unreachable("Unexpected helper");
 }
@@ -1623,19 +1712,26 @@
     return m_gdb_objc_realized_classes_helper.args;
   case objc_copyRealizedClassList:
     return m_objc_copyRealizedClassList_helper.args;
+  case objc_getRealizedClassList_trylock:
+    return m_objc_getRealizedClassList_trylock_helper.args;
   }
   llvm_unreachable("Unexpected helper");
 }
 
 AppleObjCRuntimeV2::DynamicClassInfoExtractor::Helper
 AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper() const {
-  if (!m_runtime.m_has_objc_copyRealizedClassList)
+  if (!m_runtime.m_has_objc_copyRealizedClassList &&
+      !m_runtime.m_has_objc_getRealizedClassList_trylock)
     return DynamicClassInfoExtractor::gdb_objc_realized_classes;
 
   if (Process *process = m_runtime.GetProcess()) {
     if (DynamicLoader *loader = process->GetDynamicLoader()) {
-      if (loader->IsFullyInitialized())
-        return DynamicClassInfoExtractor::objc_copyRealizedClassList;
+      if (loader->IsFullyInitialized()) {
+        if (m_runtime.m_has_objc_getRealizedClassList_trylock)
+          return DynamicClassInfoExtractor::objc_getRealizedClassList_trylock;
+        if (m_runtime.m_has_objc_copyRealizedClassList)
+          return DynamicClassInfoExtractor::objc_copyRealizedClassList;
+      }
     }
   }
 
@@ -1815,19 +1911,55 @@
     return DescriptorMapUpdateResult::Fail();
   }
 
+  auto deallocate_class_infos = llvm::make_scope_exit([&] {
+    // Deallocate the memory we allocated for the ClassInfo array
+    if (class_infos_addr != LLDB_INVALID_ADDRESS)
+      process->DeallocateMemory(class_infos_addr);
+  });
+
+  lldb::addr_t class_buffer_addr = LLDB_INVALID_ADDRESS;
+  const uint32_t class_byte_size = addr_size;
+  const uint32_t class_buffer_len = num_classes;
+  const uint32_t class_buffer_byte_size = class_buffer_len * class_byte_size;
+  if (helper == Helper::objc_getRealizedClassList_trylock) {
+    class_buffer_addr = process->AllocateMemory(
+        class_buffer_byte_size, ePermissionsReadable | ePermissionsWritable,
+        err);
+    if (class_buffer_addr == LLDB_INVALID_ADDRESS) {
+      LLDB_LOGF(log,
+                "unable to allocate %" PRIu32
+                " bytes in process for shared cache read",
+                class_buffer_byte_size);
+      return DescriptorMapUpdateResult::Fail();
+    }
+  }
+
+  auto deallocate_class_buffer = llvm::make_scope_exit([&] {
+    // Deallocate the memory we allocated for the Class array
+    if (class_buffer_addr != LLDB_INVALID_ADDRESS)
+      process->DeallocateMemory(class_buffer_addr);
+  });
+
   std::lock_guard<std::mutex> guard(m_mutex);
 
   // Fill in our function argument values
-  arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
-  arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
-  arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
+  uint32_t index = 0;
+  arguments.GetValueAtIndex(index++)->GetScalar() =
+      hash_table.GetTableLoadAddress();
+  arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_addr;
+  arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_byte_size;
+
+  if (class_buffer_addr != LLDB_INVALID_ADDRESS) {
+    arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_addr;
+    arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_byte_size;
+  }
 
   // Only dump the runtime classes from the expression evaluation if the log is
   // verbose:
   Log *type_log = GetLog(LLDBLog::Types);
   bool dump_log = type_log && type_log->GetVerbose();
 
-  arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0;
+  arguments.GetValueAtIndex(index++)->GetScalar() = dump_log ? 1 : 0;
 
   bool success = false;
 
@@ -1888,9 +2020,6 @@
     }
   }
 
-  // Deallocate the memory we allocated for the ClassInfo array
-  process->DeallocateMemory(class_infos_addr);
-
   return DescriptorMapUpdateResult(success, num_class_infos);
 }
 
Index: lldb/packages/Python/lldbsuite/test/decorators.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/decorators.py
+++ lldb/packages/Python/lldbsuite/test/decorators.py
@@ -284,7 +284,7 @@
                          archs=archs, triple=triple,
                          debug_info=debug_info,
                          swig_version=swig_version, py_version=py_version,
-                         macos_version=None,
+                         macos_version=macos_version,
                          remote=remote,dwarf_version=dwarf_version,
                          setting=setting)
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to