diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index c33760eccd127..2b2ca080c7f55 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -423,6 +423,46 @@ Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition( return error; } +CompilerType ObjCLanguageRuntime::LookupInModulesVendor(ConstString class_name, + Target &target) { + assert(class_name); + + auto *persistent_state = llvm::cast( + target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); + if (!persistent_state) + return {}; + + auto clang_modules_decl_vendor_sp = + persistent_state->GetClangModulesDeclVendor(); + if (!clang_modules_decl_vendor_sp) + return {}; + + auto types = clang_modules_decl_vendor_sp->FindTypes( + class_name, /*max_matches*/ UINT32_MAX); + if (types.empty()) + return {}; + + return types.front(); +} + +CompilerType ObjCLanguageRuntime::LookupInRuntime(ConstString class_name) { + auto *runtime_vendor = GetDeclVendor(); + if (!runtime_vendor) + return {}; + + std::vector compiler_decls; + runtime_vendor->FindDecls(class_name, false, UINT32_MAX, compiler_decls); + if (compiler_decls.empty()) + return {}; + + auto *ctx = + llvm::dyn_cast(compiler_decls[0].GetTypeSystem()); + if (!ctx) + return {}; + + return ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl()); +} + std::optional ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) { CompilerType class_type; @@ -442,18 +482,21 @@ ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) { if (!class_name) return std::nullopt; - TypeSP complete_objc_class_type_sp = LookupInCompleteClassCache(class_name); - if (!complete_objc_class_type_sp) - return std::nullopt; - - CompilerType complete_class( - complete_objc_class_type_sp->GetFullCompilerType()); - if (complete_class.GetCompleteType()) { - if (is_pointer_type) - return complete_class.GetPointerType(); - else - return complete_class; + if (TypeSP complete_objc_class_type_sp = + LookupInCompleteClassCache(class_name)) { + if (CompilerType complete_class = + complete_objc_class_type_sp->GetFullCompilerType(); + complete_class.GetCompleteType()) + return is_pointer_type ? complete_class.GetPointerType() : complete_class; } + assert(m_process); + if (CompilerType found = + LookupInModulesVendor(class_name, m_process->GetTarget())) + return is_pointer_type ? found.GetPointerType() : found; + + if (CompilerType found = LookupInRuntime(class_name)) + return is_pointer_type ? found.GetPointerType() : found; + return std::nullopt; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h index 45de098c15f51..cc8281e9d1a02 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -465,6 +465,10 @@ class ObjCLanguageRuntime : public LanguageRuntime { ObjCLanguageRuntime(const ObjCLanguageRuntime &) = delete; const ObjCLanguageRuntime &operator=(const ObjCLanguageRuntime &) = delete; + +private: + CompilerType LookupInRuntime(ConstString class_name); + CompilerType LookupInModulesVendor(ConstString class_name, Target &process); }; } // namespace lldb_private diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index ca4ddc6e8f4cb..f5d2a8ff1144a 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -277,63 +277,6 @@ CompilerType ValueObject::MaybeCalculateCompleteType() { } } - std::vector decls; - CompilerType class_type; - bool is_pointer_type = false; - if (TypeSystemClang::IsObjCObjectPointerType(compiler_type, &class_type)) - is_pointer_type = true; - else if (TypeSystemClang::IsObjCObjectOrInterfaceType(compiler_type)) - class_type = compiler_type; - else - return compiler_type; - - ConstString class_name(class_type.GetTypeName()); - if (!class_name) - return compiler_type; - - // try the modules - if (TargetSP target_sp = GetTargetSP()) { - auto *persistent_state = llvm::cast( - target_sp->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); - if (!persistent_state) - return compiler_type; - - if (auto clang_modules_decl_vendor = - persistent_state->GetClangModulesDeclVendor()) { - ConstString key_cs(class_name); - auto types = clang_modules_decl_vendor->FindTypes( - key_cs, /*max_matches*/ UINT32_MAX); - if (!types.empty()) { - auto module_type = types.front(); - m_override_type = - is_pointer_type ? module_type.GetPointerType() : module_type; - } - - if (m_override_type.IsValid()) - return m_override_type; - } - } - - // then try the runtime - if (auto *objc_language_runtime = ObjCLanguageRuntime::Get(*process_sp)) { - if (auto *runtime_vendor = objc_language_runtime->GetDeclVendor()) { - std::vector compiler_decls; - runtime_vendor->FindDecls(class_name, false, UINT32_MAX, compiler_decls); - if (!compiler_decls.empty()) { - auto *ctx = - llvm::dyn_cast(compiler_decls[0].GetTypeSystem()); - if (ctx) { - CompilerType runtime_type = - ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl()); - m_override_type = - is_pointer_type ? runtime_type.GetPointerType() : runtime_type; - } - } - - if (m_override_type.IsValid()) - return m_override_type; - } - } return compiler_type; } diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/Makefile b/lldb/test/API/lang/objc/ivar-in-framework-base/Makefile new file mode 100644 index 0000000000000..c7947fc138c18 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/Makefile @@ -0,0 +1,6 @@ +OBJC_SOURCES := main.m lib.m +LD_EXTRAS = -framework Foundation + +include Makefile.rules + +lib.o: CFLAGS = $(CFLAGS_NO_DEBUG) diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/TestIvarInFrameworkBase.py b/lldb/test/API/lang/objc/ivar-in-framework-base/TestIvarInFrameworkBase.py new file mode 100644 index 0000000000000..40fc6b7a68995 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/TestIvarInFrameworkBase.py @@ -0,0 +1,39 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestIvarInFrameworkBase(TestBase): + """ + Tests whether LLDB's data inspection commands can correctly retrieve + information about ivars from the Objective-C runtime. + In this test-case we have a base class type for which we don't have access + to the debug-info of the implementation (mimicking the scenario of subclassing + a type from a system framework). LLDB won't be able to see the backing ivar for + 'fooProp' from just debug-info, but it will fall back on the runtime to get the + necessary information. + """ + + def test_frame_var(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.m")) + self.expect("frame variable *bar", substrs=["_fooProp = 10", "_barProp = 15"]) + + def test_expr(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.m")) + self.expect_expr( + "*bar", + result_type="Bar", + result_children=[ + ValueCheck( + name="Foo", + children=[ + ValueCheck(name="NSObject"), + ValueCheck(name="_fooProp", value="10"), + ], + ), + ValueCheck(name="_barProp", value="15"), + ], + ) diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/lib.h b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.h new file mode 100644 index 0000000000000..31ceb53dc6885 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.h @@ -0,0 +1,6 @@ +#import + +@interface Foo : NSObject +@property int fooProp; +- (id)init; +@end diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/lib.m b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.m new file mode 100644 index 0000000000000..e1bf80ac4bd4c --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/lib.m @@ -0,0 +1,8 @@ +#import "lib.h" + +@implementation Foo +- (id)init { + self.fooProp = 10; + return self; +} +@end diff --git a/lldb/test/API/lang/objc/ivar-in-framework-base/main.m b/lldb/test/API/lang/objc/ivar-in-framework-base/main.m new file mode 100644 index 0000000000000..1fd352ec92c54 --- /dev/null +++ b/lldb/test/API/lang/objc/ivar-in-framework-base/main.m @@ -0,0 +1,22 @@ +#import "lib.h" +#include + +@interface Bar : Foo +@property int barProp; +- (id)init; +@end + +@implementation Bar + +- (id)init { + self = [super init]; + self.barProp = 15; + return self; +} +@end + +int main() { + Bar *bar = [Bar new]; + puts("break here"); + return 0; +}