Skip to content

Commit addc6fb

Browse files
authored
Merge pull request #8105 from augusto2112/class-res-embedded
[lldb] Adapt class resolution to work without reflection in binaries
2 parents 512cde7 + 305488b commit addc6fb

File tree

3 files changed

+150
-58
lines changed

3 files changed

+150
-58
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/ReflectionContext.cpp

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,28 @@ class TargetReflectionContext : public ReflectionContextInterface {
129129
return type_ref_or_err.getType();
130130
}
131131

132-
const swift::reflection::TypeInfo *GetClassInstanceTypeInfo(
132+
const swift::reflection::RecordTypeInfo *GetClassInstanceTypeInfo(
133133
const swift::reflection::TypeRef *type_ref,
134134
swift::remote::TypeInfoProvider *provider,
135135
swift::reflection::DescriptorFinder *descriptor_finder) override {
136136
auto on_exit = SetDescriptorFinderAndClearOnExit(descriptor_finder);
137137
if (!type_ref)
138138
return nullptr;
139-
return m_type_converter.getClassInstanceTypeInfo(type_ref, 0, provider);
139+
140+
auto start =
141+
m_reflection_ctx.computeUnalignedFieldStartOffset(type_ref);
142+
if (!start) {
143+
if (auto *log = GetLog(LLDBLog::Types)) {
144+
std::stringstream ss;
145+
type_ref->dump(ss);
146+
LLDB_LOG(log, "Could not compute start field offset for typeref: ",
147+
ss.str());
148+
}
149+
return nullptr;
150+
}
151+
152+
return m_type_converter.getClassInstanceTypeInfo(type_ref, *start,
153+
provider);
140154
}
141155

142156
const swift::reflection::TypeInfo *
@@ -195,6 +209,23 @@ class TargetReflectionContext : public ReflectionContextInterface {
195209
return m_reflection_ctx.getBuilder().lookupSuperclass(tr);
196210
}
197211

212+
bool
213+
ForEachSuperClassType(swift::remote::TypeInfoProvider *tip,
214+
swift::reflection::DescriptorFinder *descriptor_finder,
215+
const swift::reflection::TypeRef *tr,
216+
std::function<bool(SuperClassType)> fn) override {
217+
while (tr) {
218+
if (fn({[=]() -> const swift::reflection::RecordTypeInfo * {
219+
return GetRecordTypeInfo(tr, tip, descriptor_finder);
220+
},
221+
[=]() -> const swift::reflection::TypeRef * { return tr; }}))
222+
return true;
223+
224+
tr = LookupSuperclass(tr, descriptor_finder);
225+
}
226+
return false;
227+
}
228+
198229
bool
199230
ForEachSuperClassType(swift::remote::TypeInfoProvider *tip,
200231
swift::reflection::DescriptorFinder *descriptor_finder,
@@ -299,8 +330,29 @@ class TargetReflectionContext : public ReflectionContextInterface {
299330
StripSignedPointer(swift::remote::RemoteAbsolutePointer pointer) override {
300331
return m_reflection_ctx.stripSignedPointer(pointer);
301332
}
302-
};
303333

334+
private:
335+
/// Return a description of the layout of the record (classes, structs and
336+
/// tuples) type given its typeref.
337+
const swift::reflection::RecordTypeInfo *
338+
GetRecordTypeInfo(const swift::reflection::TypeRef *type_ref,
339+
swift::remote::TypeInfoProvider *tip,
340+
swift::reflection::DescriptorFinder *descriptor_finder) {
341+
auto *type_info = GetTypeInfo(type_ref, tip, descriptor_finder);
342+
if (auto record_type_info =
343+
llvm::dyn_cast_or_null<swift::reflection::RecordTypeInfo>(
344+
type_info))
345+
return record_type_info;
346+
if (llvm::isa_and_nonnull<swift::reflection::ReferenceTypeInfo>(type_info))
347+
return GetClassInstanceTypeInfo(type_ref, tip, descriptor_finder);
348+
if (auto *log = GetLog(LLDBLog::Types)) {
349+
std::stringstream ss;
350+
type_ref->dump(ss);
351+
LLDB_LOG(log, "Could not get record type info for typeref: ", ss.str());
352+
}
353+
return nullptr;
354+
}
355+
};
304356
} // namespace
305357

306358
namespace lldb_private {

lldb/source/Plugins/LanguageRuntime/Swift/ReflectionContextInterface.h

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,33 @@ class ReflectionContextInterface {
9090
const swift::reflection::TypeRef *type_ref,
9191
swift::remote::TypeInfoProvider *provider,
9292
swift::reflection::DescriptorFinder *descriptor_finder) = 0;
93-
virtual const swift::reflection::TypeInfo *GetTypeInfo(
94-
const swift::reflection::TypeRef *type_ref,
95-
swift::remote::TypeInfoProvider *provider,
96-
swift::reflection::DescriptorFinder *descriptor_finder) = 0;
93+
virtual const swift::reflection::TypeInfo *
94+
GetTypeInfo(const swift::reflection::TypeRef *type_ref,
95+
swift::remote::TypeInfoProvider *provider,
96+
swift::reflection::DescriptorFinder *descriptor_finder) = 0;
9797
virtual const swift::reflection::TypeInfo *GetTypeInfoFromInstance(
9898
lldb::addr_t instance, swift::remote::TypeInfoProvider *provider,
9999
swift::reflection::DescriptorFinder *descriptor_finder) = 0;
100100
virtual swift::remote::MemoryReader &GetReader() = 0;
101101
virtual const swift::reflection::TypeRef *LookupSuperclass(
102102
const swift::reflection::TypeRef *tr,
103103
swift::reflection::DescriptorFinder *descriptor_finder) = 0;
104-
virtual bool ForEachSuperClassType(
105-
swift::remote::TypeInfoProvider *tip,
106-
swift::reflection::DescriptorFinder *descriptor_finder,
107-
lldb::addr_t pointer, std::function<bool(SuperClassType)> fn) = 0;
104+
virtual bool
105+
ForEachSuperClassType(swift::remote::TypeInfoProvider *tip,
106+
swift::reflection::DescriptorFinder *descriptor_finder,
107+
lldb::addr_t pointer,
108+
std::function<bool(SuperClassType)> fn) = 0;
109+
110+
/// Traverses the superclass hierarchy using the typeref, as opposed to the
111+
/// other version of the function that uses the instance's pointer. This
112+
/// version is useful when reflection metadata has been stripped from the
113+
/// binary (for example, when debugging embedded Swift programs).
114+
virtual bool
115+
ForEachSuperClassType(swift::remote::TypeInfoProvider *tip,
116+
swift::reflection::DescriptorFinder *descriptor_finder,
117+
const swift::reflection::TypeRef *tr,
118+
std::function<bool(SuperClassType)> fn) = 0;
119+
108120
virtual llvm::Optional<std::pair<const swift::reflection::TypeRef *,
109121
swift::remote::RemoteAddress>>
110122
ProjectExistentialAndUnwrapClass(

lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp

Lines changed: 75 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,29 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
11961196
}
11971197

11981198
// Objects.
1199+
switch (rti->getReferenceKind()) {
1200+
case swift::reflection::ReferenceKind::Weak:
1201+
case swift::reflection::ReferenceKind::Unowned:
1202+
case swift::reflection::ReferenceKind::Unmanaged:
1203+
// Weak references are implicitly Optionals, so report the one
1204+
// child of Optional here.
1205+
if (idx != 0)
1206+
break; // Maybe assert that type is not an Optional?
1207+
child_name = "some";
1208+
child_byte_size = ts->GetPointerByteSize();
1209+
child_byte_offset = 0;
1210+
child_bitfield_bit_size = 0;
1211+
child_bitfield_bit_offset = 0;
1212+
child_is_base_class = false;
1213+
child_is_deref_of_parent = false;
1214+
language_flags = 0;
1215+
if (CompilerType optional = GetWeakReferent(*ts, type))
1216+
return optional;
1217+
break;
1218+
default:
1219+
break;
1220+
}
1221+
11991222
// Try the instance type metadata.
12001223
if (!valobj)
12011224
return {};
@@ -1215,61 +1238,58 @@ CompilerType SwiftLanguageRuntimeImpl::GetChildCompilerTypeAtIndex(
12151238
instance_type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>();
12161239
if (!instance_ts)
12171240
return {};
1218-
12191241
// LLDBTypeInfoProvider needs to be kept alive while supers gets accessed.
12201242
llvm::SmallVector<SuperClassType, 2> supers;
1221-
LLDBTypeInfoProvider tip(*this, *instance_ts);
1222-
reflection_ctx->ForEachSuperClassType(
1223-
&tip, ts->GetDescriptorFinder(), pointer,
1224-
[&](SuperClassType sc) -> bool {
1225-
// If the typeref is invalid, we don't want to process it (for
1226-
// example, this could be an artifical ObjC class).
1227-
if (!sc.get_typeref())
1228-
return false;
1243+
auto superclass_finder = [&](SuperClassType sc) -> bool {
1244+
// If the typeref is invalid, we don't want to process it (for
1245+
// example, this could be an artifical ObjC class).
1246+
if (!sc.get_typeref())
1247+
return false;
12291248

1230-
if (!found_start) {
1231-
// The ValueObject always points to the same class instance,
1232-
// even when querying base classes. Drop base classes until we
1233-
// reach the requested type.
1234-
if (auto *tr = sc.get_typeref()) {
1235-
NodePointer base_class = tr->getDemangling(dem);
1236-
if (TypeSystemSwiftTypeRef::GetBaseName(base_class) != type_name)
1237-
return false;
1238-
found_start = true;
1239-
}
1240-
}
1241-
supers.push_back(sc);
1242-
return supers.size() >= 2;
1243-
});
1249+
if (!found_start) {
1250+
// The ValueObject always points to the same class instance,
1251+
// even when querying base classes. Drop base classes until we
1252+
// reach the requested type.
1253+
if (auto *tr = sc.get_typeref()) {
1254+
NodePointer base_class = tr->getDemangling(dem);
1255+
if (TypeSystemSwiftTypeRef::GetBaseName(base_class) != type_name)
1256+
return false;
1257+
found_start = true;
1258+
}
1259+
}
1260+
supers.push_back(sc);
1261+
return supers.size() >= 2;
1262+
};
12441263

1245-
if (supers.size() == 0) {
1264+
LLDBTypeInfoProvider tip(*this, *instance_ts);
1265+
// Try out the instance pointer based super class traversal first, as its
1266+
// usually faster.
1267+
reflection_ctx->ForEachSuperClassType(&tip, ts->GetDescriptorFinder(),
1268+
pointer, superclass_finder);
1269+
1270+
if (supers.empty())
1271+
// If the pointer based super class traversal failed (this may happen
1272+
// when metadata is not present in the binary, for example: embedded
1273+
// Swift), try the typeref based one next.
1274+
reflection_ctx->ForEachSuperClassType(&tip, ts->GetDescriptorFinder(), tr,
1275+
superclass_finder);
1276+
1277+
if (supers.empty()) {
12461278
LLDB_LOG(GetLog(LLDBLog::Types),
12471279
"Couldn't find the type metadata for {0} in instance",
12481280
type.GetTypeName());
1249-
return {};
1250-
}
12511281

1252-
switch (rti->getReferenceKind()) {
1253-
case swift::reflection::ReferenceKind::Weak:
1254-
case swift::reflection::ReferenceKind::Unowned:
1255-
case swift::reflection::ReferenceKind::Unmanaged:
1256-
// Weak references are implicitly Optionals, so report the one
1257-
// child of Optional here.
1258-
if (idx != 0)
1259-
break; // Maybe assert that type is not an Optional?
1260-
child_name = "some";
1261-
child_byte_size = ts->GetPointerByteSize();
1262-
child_byte_offset = 0;
1263-
child_bitfield_bit_size = 0;
1264-
child_bitfield_bit_offset = 0;
1265-
child_is_base_class = false;
1266-
child_is_deref_of_parent = false;
1267-
language_flags = 0;
1268-
if (CompilerType optional = GetWeakReferent(*ts, type))
1269-
return optional;
1270-
break;
1271-
default:
1272-
break;
1282+
auto *cti = reflection_ctx->GetClassInstanceTypeInfo(
1283+
tr, &tip, ts->GetDescriptorFinder());
1284+
if (auto *rti =
1285+
llvm::dyn_cast_or_null<swift::reflection::RecordTypeInfo>(cti)) {
1286+
auto fields = rti->getFields();
1287+
if (idx < fields.size()) {
1288+
llvm::Optional<TypeSystemSwift::TupleElement> tuple;
1289+
return get_from_field_info(fields[idx], tuple, true);
1290+
}
1291+
}
1292+
return {};
12731293
}
12741294

12751295
// Handle the artificial base class fields.
@@ -1722,6 +1742,14 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress_Class(
17221742

17231743
const auto *typeref = reflection_ctx->ReadTypeFromInstance(
17241744
instance_ptr, ts.GetDescriptorFinder(), true);
1745+
1746+
// If we couldn't find the typeref from the instance, the best we can do is
1747+
// use the static type. This is a valid use case when the binary doesn't
1748+
// contain any metadata (for example, embedded Swift).
1749+
if (!typeref)
1750+
typeref = reflection_ctx->GetTypeRefOrNull(class_type.GetMangledTypeName(),
1751+
ts.GetDescriptorFinder());
1752+
17251753
if (!typeref) {
17261754
LLDB_LOGF(log,
17271755
"could not read typeref for type: %s (instance_ptr = 0x%" PRIx64

0 commit comments

Comments
 (0)