Skip to content

Commit fcfd3d5

Browse files
committed
[lldb] Identify Swift-implemented ObjC classes
Classes implemented in Swift can be exposed to ObjC. For those classes, the ObjC metadata is incomplete. Specifically, the encoded types of the ivars are incomplete. As one might expect, the Swift metadata _is_ complete. In such cases, the Swift runtime should be consulted when determining the dynamic type of a value. Differential Revision: https://reviews.llvm.org/D152837
1 parent 85562f7 commit fcfd3d5

File tree

7 files changed

+58
-1
lines changed

7 files changed

+58
-1
lines changed

lldb/include/lldb/Target/LanguageRuntime.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ class LanguageRuntime : public Runtime, public PluginInterface {
6767

6868
virtual lldb::LanguageType GetLanguageType() const = 0;
6969

70+
/// Return the preferred language runtime instance, which in most cases will
71+
/// be the current instance.
72+
virtual LanguageRuntime *GetPreferredLanguageRuntime(ValueObject &in_value) {
73+
return nullptr;
74+
}
75+
7076
virtual bool GetObjectDescription(Stream &str, ValueObject &object) = 0;
7177

7278
virtual bool GetObjectDescription(Stream &str, Value &value,

lldb/source/Core/ValueObjectDynamicValue.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,18 @@ bool ValueObjectDynamicValue::UpdateValue() {
181181
known_type != lldb::eLanguageTypeUnknown &&
182182
known_type != lldb::eLanguageTypeC) {
183183
runtime = process->GetLanguageRuntime(known_type);
184-
if (runtime)
184+
if (auto *preferred_runtime =
185+
runtime->GetPreferredLanguageRuntime(*m_parent)) {
186+
// Try the preferred runtime first.
187+
found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress(
188+
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
189+
value_type);
190+
if (found_dynamic_type)
191+
// Set the operative `runtime` for later use in this function.
192+
runtime = preferred_runtime;
193+
}
194+
if (!found_dynamic_type)
195+
// Fallback to the runtime for `known_type`.
185196
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
186197
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
187198
value_type);

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010

1111
#include "lldb/Expression/FunctionCaller.h"
1212
#include "lldb/Target/ABI.h"
13+
#include "lldb/Target/Language.h"
1314
#include "lldb/Utility/LLDBLog.h"
1415
#include "lldb/Utility/Log.h"
16+
#include "lldb/lldb-enumerations.h"
1517

1618
using namespace lldb;
1719
using namespace lldb_private;
@@ -668,6 +670,19 @@ uint64_t ClassDescriptorV2::GetInstanceSize() {
668670
return 0;
669671
}
670672

673+
// From the ObjC runtime.
674+
static uint8_t IS_SWIFT_STABLE = 1U << 1;
675+
676+
LanguageType ClassDescriptorV2::GetImplementationLanguage() const {
677+
std::unique_ptr<objc_class_t> objc_class;
678+
if (auto *process = m_runtime.GetProcess())
679+
if (Read_objc_class(process, objc_class))
680+
if (objc_class->m_flags & IS_SWIFT_STABLE)
681+
return lldb::eLanguageTypeSwift;
682+
683+
return lldb::eLanguageTypeObjC;
684+
}
685+
671686
ClassDescriptorV2::iVarsStorage::iVarsStorage() : m_ivars(), m_mutex() {}
672687

673688
size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); }

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <mutex>
1313

1414
#include "AppleObjCRuntimeV2.h"
15+
#include "lldb/lldb-enumerations.h"
1516
#include "lldb/lldb-private.h"
1617

1718
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
@@ -34,6 +35,8 @@ class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
3435
return true; // any Objective-C v2 runtime class descriptor we vend is valid
3536
}
3637

38+
lldb::LanguageType GetImplementationLanguage() const override;
39+
3740
// a custom descriptor is used for tagged pointers
3841
bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
3942
uint64_t *value_bits = nullptr,

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "lldb/Target/ABI.h"
3434
#include "lldb/Target/DynamicLoader.h"
3535
#include "lldb/Target/ExecutionContext.h"
36+
#include "lldb/Target/LanguageRuntime.h"
3637
#include "lldb/Target/Platform.h"
3738
#include "lldb/Target/Process.h"
3839
#include "lldb/Target/RegisterContext.h"
@@ -758,6 +759,19 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
758759
RegisterObjCExceptionRecognizer(process);
759760
}
760761

762+
LanguageRuntime *
763+
AppleObjCRuntimeV2::GetPreferredLanguageRuntime(ValueObject &in_value) {
764+
if (auto process_sp = in_value.GetProcessSP()) {
765+
assert(process_sp.get() == m_process);
766+
if (auto descriptor_sp = GetNonKVOClassDescriptor(in_value)) {
767+
LanguageType impl_lang = descriptor_sp->GetImplementationLanguage();
768+
if (impl_lang != eLanguageTypeUnknown)
769+
return process_sp->GetLanguageRuntime(impl_lang);
770+
}
771+
}
772+
return nullptr;
773+
}
774+
761775
bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(
762776
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
763777
TypeAndOrName &class_type_or_name, Address &address,

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
3737

3838
static llvm::StringRef GetPluginNameStatic() { return "apple-objc-v2"; }
3939

40+
LanguageRuntime *GetPreferredLanguageRuntime(ValueObject &in_value) override;
41+
4042
static char ID;
4143

4244
bool isA(const void *ClassID) const override {

lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "lldb/Symbol/Type.h"
2424
#include "lldb/Target/LanguageRuntime.h"
2525
#include "lldb/Utility/ConstString.h"
26+
#include "lldb/lldb-enumerations.h"
2627
#include "lldb/lldb-private.h"
2728

2829
class CommandObjectObjC_ClassTable_Dump;
@@ -84,6 +85,11 @@ class ObjCLanguageRuntime : public LanguageRuntime {
8485
return (m_is_cf == eLazyBoolYes);
8586
}
8687

88+
/// Determine whether this class is implemented in Swift.
89+
virtual lldb::LanguageType GetImplementationLanguage() const {
90+
return lldb::eLanguageTypeObjC;
91+
}
92+
8793
virtual bool IsValid() = 0;
8894

8995
/// There are two routines in the ObjC runtime that tagged pointer clients

0 commit comments

Comments
 (0)