-
Notifications
You must be signed in to change notification settings - Fork 341
[lldb] Adapt class resolution to work without reflection in binaries #8105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -999,8 +999,9 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex( | |
}; | ||
|
||
// Try the static type metadata. | ||
auto *ti = | ||
GetSwiftRuntimeTypeInfo(type, exe_ctx.GetBestExecutionContextScope()); | ||
const swift::reflection::TypeRef *tr = nullptr; | ||
auto *ti = GetSwiftRuntimeTypeInfo( | ||
type, exe_ctx.GetBestExecutionContextScope(), &tr); | ||
if (!ti) | ||
return {}; | ||
// Structs and Tuples. | ||
|
@@ -1066,6 +1067,29 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex( | |
if (auto *rti = | ||
llvm::dyn_cast_or_null<swift::reflection::ReferenceTypeInfo>(ti)) { | ||
// Objects. | ||
switch (rti->getReferenceKind()) { | ||
case swift::reflection::ReferenceKind::Weak: | ||
case swift::reflection::ReferenceKind::Unowned: | ||
case swift::reflection::ReferenceKind::Unmanaged: | ||
// Weak references are implicitly Optionals, so report the one | ||
// child of Optional here. | ||
if (idx != 0) | ||
break; // Maybe assert that type is not an Optional? | ||
child_name = "some"; | ||
child_byte_size = ts->GetPointerByteSize(); | ||
child_byte_offset = 0; | ||
child_bitfield_bit_size = 0; | ||
child_bitfield_bit_offset = 0; | ||
child_is_base_class = false; | ||
child_is_deref_of_parent = false; | ||
language_flags = 0; | ||
if (CompilerType optional = GetWeakReferent(*ts, type)) | ||
return optional; | ||
break; | ||
default: | ||
break; | ||
} | ||
|
||
// Try the instance type metadata. | ||
if (!valobj) | ||
return {}; | ||
|
@@ -1085,61 +1109,58 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex( | |
instance_type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>(); | ||
if (!instance_ts) | ||
return {}; | ||
|
||
// LLDBTypeInfoProvider needs to be kept alive while supers gets accessed. | ||
llvm::SmallVector<SuperClassType, 2> supers; | ||
LLDBTypeInfoProvider tip(*this, *instance_ts); | ||
reflection_ctx->ForEachSuperClassType( | ||
&tip, ts->GetDescriptorFinder(), pointer, | ||
[&](SuperClassType sc) -> bool { | ||
// If the typeref is invalid, we don't want to process it (for | ||
// example, this could be an artifical ObjC class). | ||
if (!sc.get_typeref()) | ||
return false; | ||
auto superclass_finder = [&](SuperClassType sc) -> bool { | ||
// If the typeref is invalid, we don't want to process it (for | ||
// example, this could be an artifical ObjC class). | ||
if (!sc.get_typeref()) | ||
return false; | ||
|
||
if (!found_start) { | ||
// The ValueObject always points to the same class instance, | ||
// even when querying base classes. Drop base classes until we | ||
// reach the requested type. | ||
if (auto *tr = sc.get_typeref()) { | ||
NodePointer base_class = tr->getDemangling(dem); | ||
if (TypeSystemSwiftTypeRef::GetBaseName(base_class) != type_name) | ||
return false; | ||
found_start = true; | ||
} | ||
} | ||
supers.push_back(sc); | ||
return supers.size() >= 2; | ||
}); | ||
if (!found_start) { | ||
// The ValueObject always points to the same class instance, | ||
// even when querying base classes. Drop base classes until we | ||
// reach the requested type. | ||
if (auto *tr = sc.get_typeref()) { | ||
NodePointer base_class = tr->getDemangling(dem); | ||
if (TypeSystemSwiftTypeRef::GetBaseName(base_class) != type_name) | ||
return false; | ||
found_start = true; | ||
} | ||
} | ||
supers.push_back(sc); | ||
return supers.size() >= 2; | ||
}; | ||
|
||
if (supers.size() == 0) { | ||
LLDBTypeInfoProvider tip(*this, *instance_ts); | ||
// Try out the instance pointer based super class traversal first, as its | ||
// usually faster. | ||
reflection_ctx->ForEachSuperClassType(&tip, ts->GetDescriptorFinder(), | ||
pointer, superclass_finder); | ||
|
||
if (supers.empty()) | ||
// If the pointer based super class traversal failed (this may happen | ||
// when metadata is not present in the binary, for example: embedded | ||
// Swift), try the typeref based one next. | ||
reflection_ctx->ForEachSuperClassType(&tip, ts->GetDescriptorFinder(), tr, | ||
superclass_finder); | ||
|
||
if (supers.empty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why twice the same condition in a row? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dynamic type resolution first tries the pointer-based There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think my question was aiming at: does ForEachSuperClassType modify
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it's being captured by reference by the |
||
LLDB_LOG(GetLog(LLDBLog::Types), | ||
"Couldn't find the type metadata for {0} in instance", | ||
type.GetTypeName()); | ||
return {}; | ||
} | ||
|
||
switch (rti->getReferenceKind()) { | ||
case swift::reflection::ReferenceKind::Weak: | ||
case swift::reflection::ReferenceKind::Unowned: | ||
case swift::reflection::ReferenceKind::Unmanaged: | ||
// Weak references are implicitly Optionals, so report the one | ||
// child of Optional here. | ||
if (idx != 0) | ||
break; // Maybe assert that type is not an Optional? | ||
child_name = "some"; | ||
child_byte_size = ts->GetPointerByteSize(); | ||
child_byte_offset = 0; | ||
child_bitfield_bit_size = 0; | ||
child_bitfield_bit_offset = 0; | ||
child_is_base_class = false; | ||
child_is_deref_of_parent = false; | ||
language_flags = 0; | ||
if (CompilerType optional = GetWeakReferent(*ts, type)) | ||
return optional; | ||
break; | ||
default: | ||
break; | ||
auto *cti = reflection_ctx->GetClassInstanceTypeInfo( | ||
tr, &tip, ts->GetDescriptorFinder()); | ||
if (auto *rti = | ||
llvm::dyn_cast_or_null<swift::reflection::RecordTypeInfo>(cti)) { | ||
auto fields = rti->getFields(); | ||
if (idx < fields.size()) { | ||
llvm::Optional<TypeSystemSwift::TupleElement> tuple; | ||
return get_from_field_info(fields[idx], tuple, true); | ||
} | ||
} | ||
return {}; | ||
} | ||
|
||
// Handle the artificial base class fields. | ||
|
@@ -1587,6 +1608,14 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress_Class( | |
|
||
const auto *typeref = reflection_ctx->ReadTypeFromInstance( | ||
instance_ptr, ts.GetDescriptorFinder(), true); | ||
|
||
// If we couldn't find the typeref from the instance, the best we can do is | ||
// use the static type. This is a valid use case when the binary doesn't | ||
// contain any metadata (for example, embedded Swift). | ||
if (!typeref) | ||
typeref = reflection_ctx->GetTypeRefOrNull(class_type.GetMangledTypeName(), | ||
ts.GetDescriptorFinder()); | ||
|
||
if (!typeref) { | ||
LLDB_LOGF(log, | ||
"could not read typeref for type: %s (instance_ptr = 0x%" PRIx64 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you wrap this in if(GetLog(LLDBLog::Types)), so we don't do the string operations if we don't log?