Index: lldb/include/lldb/Target/Target.h =================================================================== --- lldb/include/lldb/Target/Target.h +++ lldb/include/lldb/Target/Target.h @@ -71,6 +71,13 @@ eImportStdModuleTrue, }; +enum DynamicClassInfoHelper { + eDynamicClassInfoHelperAuto, + eDynamicClassInfoHelperRealizedClassesStruct, + eDynamicClassInfoHelperCopyRealizedClassList, + eDynamicClassInfoHelperGetRealizedClassList, +}; + class TargetExperimentalProperties : public Properties { public: TargetExperimentalProperties(); @@ -152,6 +159,8 @@ ImportStdModule GetImportStdModule() const; + DynamicClassInfoHelper GetDynamicClassInfoHelper() const; + bool GetEnableAutoApplyFixIts() const; uint64_t GetNumberOfRetriesWithFixits() const; 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 @@ -341,7 +341,7 @@ /// must use gdb_objc_realized_classes. Otherwise, we prefer /// objc_getRealizedClassList_trylock and objc_copyRealizedClassList /// respectively, depending on availability. - Helper ComputeHelper() const; + Helper ComputeHelper(ExecutionContext &exe_ctx) const; UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx, Helper helper); 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 @@ -1724,7 +1724,8 @@ } AppleObjCRuntimeV2::DynamicClassInfoExtractor::Helper -AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper() const { +AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper( + ExecutionContext &exe_ctx) const { if (!m_runtime.m_has_objc_copyRealizedClassList && !m_runtime.m_has_objc_getRealizedClassList_trylock) return DynamicClassInfoExtractor::gdb_objc_realized_classes; @@ -1732,10 +1733,20 @@ if (Process *process = m_runtime.GetProcess()) { if (DynamicLoader *loader = process->GetDynamicLoader()) { 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; + switch (exe_ctx.GetTargetRef().GetDynamicClassInfoHelper()) { + case eDynamicClassInfoHelperAuto: + [[clang::fallthrough]]; + case eDynamicClassInfoHelperGetRealizedClassList: + if (m_runtime.m_has_objc_getRealizedClassList_trylock) + return DynamicClassInfoExtractor::objc_getRealizedClassList_trylock; + [[clang::fallthrough]]; + case eDynamicClassInfoHelperCopyRealizedClassList: + if (m_runtime.m_has_objc_copyRealizedClassList) + return DynamicClassInfoExtractor::objc_copyRealizedClassList; + [[clang::fallthrough]]; + case eDynamicClassInfoHelperRealizedClassesStruct: + return DynamicClassInfoExtractor::gdb_objc_realized_classes; + } } } } @@ -1872,7 +1883,7 @@ Status err; // Compute which helper we're going to use for this update. - const DynamicClassInfoExtractor::Helper helper = ComputeHelper(); + const DynamicClassInfoExtractor::Helper helper = ComputeHelper(exe_ctx); // Read the total number of classes from the hash table const uint32_t num_classes = Index: lldb/source/Target/Target.cpp =================================================================== --- lldb/source/Target/Target.cpp +++ lldb/source/Target/Target.cpp @@ -3801,6 +3801,22 @@ }, }; +static constexpr OptionEnumValueElement + g_dynamic_class_info_helper_value_types[] = { + { + eDynamicClassInfoHelperAuto, + "auto", + "Automatically determine the most appropriate method for the " + "target OS.", + }, + {eDynamicClassInfoHelperRealizedClassesStruct, "RealizedClassesStruct", + "Prefer using the realized classes struct."}, + {eDynamicClassInfoHelperCopyRealizedClassList, "CopyRealizedClassList", + "Prefer using the CopyRealizedClassList API."}, + {eDynamicClassInfoHelperGetRealizedClassList, "GetRealizedClassList", + "Prefer using the GetRealizedClassList API."}, +}; + static constexpr OptionEnumValueElement g_hex_immediate_style_values[] = { { Disassembler::eHexStyleC, @@ -4299,6 +4315,13 @@ nullptr, idx, g_target_properties[idx].default_uint_value); } +DynamicClassInfoHelper TargetProperties::GetDynamicClassInfoHelper() const { + const uint32_t idx = ePropertyDynamicClassInfoHelper; + return (DynamicClassInfoHelper) + m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_target_properties[idx].default_uint_value); +} + bool TargetProperties::GetEnableAutoApplyFixIts() const { const uint32_t idx = ePropertyAutoApplyFixIts; return m_collection_sp->GetPropertyAtIndexAsBoolean( Index: lldb/source/Target/TargetProperties.td =================================================================== --- lldb/source/Target/TargetProperties.td +++ lldb/source/Target/TargetProperties.td @@ -54,6 +54,10 @@ EnumValues<"OptionEnumValues(g_import_std_module_value_types)">, Desc<"Import the 'std' C++ module to improve expression parsing involving " " C++ standard library types.">; + def DynamicClassInfoHelper: Property<"objc-dynamic-class-extractor", "Enum">, + DefaultEnumValue<"eDynamicClassInfoHelperAuto">, + EnumValues<"OptionEnumValues(g_dynamic_class_info_helper_value_types)">, + Desc<"Configure how LLDB parses dynamic Objective-C class metadata. By default LLDB will choose the most appropriate method for the target OS.">; def AutoApplyFixIts: Property<"auto-apply-fixits", "Boolean">, DefaultTrue, Desc<"Automatically apply fix-it hints to expressions.">;