Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 54 additions & 11 deletions lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<ClangPersistentVariables>(
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<CompilerDecl> compiler_decls;
runtime_vendor->FindDecls(class_name, false, UINT32_MAX, compiler_decls);
if (compiler_decls.empty())
return {};

auto *ctx =
llvm::dyn_cast<TypeSystemClang>(compiler_decls[0].GetTypeSystem());
if (!ctx)
return {};

return ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl());
}

std::optional<CompilerType>
ObjCLanguageRuntime::GetRuntimeType(CompilerType base_type) {
CompilerType class_type;
Expand All @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
57 changes: 0 additions & 57 deletions lldb/source/ValueObject/ValueObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,63 +277,6 @@ CompilerType ValueObject::MaybeCalculateCompleteType() {
}
}

std::vector<clang::NamedDecl *> 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<ClangPersistentVariables>(
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<CompilerDecl> compiler_decls;
runtime_vendor->FindDecls(class_name, false, UINT32_MAX, compiler_decls);
if (!compiler_decls.empty()) {
auto *ctx =
llvm::dyn_cast<TypeSystemClang>(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;
}

Expand Down
6 changes: 6 additions & 0 deletions lldb/test/API/lang/objc/ivar-in-framework-base/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
OBJC_SOURCES := main.m lib.m
LD_EXTRAS = -framework Foundation

include Makefile.rules

lib.o: CFLAGS = $(CFLAGS_NO_DEBUG)
Original file line number Diff line number Diff line change
@@ -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"),
],
)
6 changes: 6 additions & 0 deletions lldb/test/API/lang/objc/ivar-in-framework-base/lib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#import <Foundation/Foundation.h>

@interface Foo : NSObject
@property int fooProp;
- (id)init;
@end
8 changes: 8 additions & 0 deletions lldb/test/API/lang/objc/ivar-in-framework-base/lib.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#import "lib.h"

@implementation Foo
- (id)init {
self.fooProp = 10;
return self;
}
@end
22 changes: 22 additions & 0 deletions lldb/test/API/lang/objc/ivar-in-framework-base/main.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#import "lib.h"
#include <stdio.h>

@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;
}