Skip to content

Support dynamic value object pointing to host address #9989

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

Merged
merged 4 commits into from
Feb 10, 2025
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
6 changes: 4 additions & 2 deletions lldb/source/Plugins/Language/Swift/SwiftLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1114,13 +1114,14 @@ SwiftLanguage::GetHardcodedSynthetics() {
TypeAndOrName type_or_name;
Address address;
Value::ValueType value_type;
llvm::ArrayRef<uint8_t> local_buffer;
// Try to find the dynamic type of the Swift type.
// TODO: find a way to get the dyamic value type from the
// command.
if (swift_runtime->GetDynamicTypeAndAddress(
*casted_to_swift.get(),
lldb::DynamicValueType::eDynamicCanRunTarget, type_or_name,
address, value_type)) {
address, value_type, local_buffer)) {
if (type_or_name.HasCompilerType()) {
swift_type = type_or_name.GetCompilerType();
// Cast it to the more specific type.
Expand Down Expand Up @@ -1268,8 +1269,9 @@ SwiftLanguage::GetPossibleFormattersMatches(
TypeAndOrName type_and_or_name;
Address address;
Value::ValueType value_type;
llvm::ArrayRef<uint8_t> local_buffer;
if (!runtime->GetDynamicTypeAndAddress(valobj, use_dynamic, type_and_or_name,
address, value_type))
address, value_type, local_buffer))
return result;
if (ConstString name = type_and_or_name.GetName())
result.push_back(
Expand Down
24 changes: 13 additions & 11 deletions lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ class SwiftLanguageRuntime : public LanguageRuntime {
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) override;

CompilerType BindGenericTypeParameters(
CompilerType unbound_type,
Expand Down Expand Up @@ -569,7 +569,8 @@ class SwiftLanguageRuntime : public LanguageRuntime {
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type);
Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer);
#ifndef NDEBUG
ConstString GetDynamicTypeName_ClassRemoteAST(ValueObject &in_value,
lldb::addr_t instance_ptr);
Expand All @@ -596,18 +597,18 @@ class SwiftLanguageRuntime : public LanguageRuntime {
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type);
Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer);

bool GetDynamicTypeAndAddress_IndirectEnumCase(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type);
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer);

bool GetDynamicTypeAndAddress_ClangType(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type);
bool GetDynamicTypeAndAddress_ClangType(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer);

/// Dynamic type resolution tends to want to generate scalar data -
/// but there are caveats Per original comment here "Our address is
Expand All @@ -618,7 +619,8 @@ class SwiftLanguageRuntime : public LanguageRuntime {
Value::ValueType GetValueType(ValueObject &in_value,
CompilerType dynamic_type,
Value::ValueType static_value_type,
bool is_indirect_enum_case);
bool is_indirect_enum_case,
llvm::ArrayRef<uint8_t> &local_buffer);

lldb::UnwindPlanSP
GetRuntimeUnwindPlan(lldb::ProcessSP process_sp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1847,7 +1847,8 @@ static bool IsPrivateNSClass(NodePointer node) {
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Class(
ValueObject &in_value, CompilerType class_type,
lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name,
Address &address, Value::ValueType &value_type) {
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) {
AddressType address_type;
lldb::addr_t instance_ptr = in_value.GetPointerValue(&address_type);
value_type = Value::GetValueTypeFromAddressType(address_type);
Expand All @@ -1873,8 +1874,9 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Class(
if (auto *objc_runtime =
SwiftLanguageRuntime::GetObjCRuntime(GetProcess())) {
Value::ValueType value_type;
if (objc_runtime->GetDynamicTypeAndAddress(
in_value, use_dynamic, class_type_or_name, address, value_type)) {
if (objc_runtime->GetDynamicTypeAndAddress(in_value, use_dynamic,
class_type_or_name, address,
value_type, local_buffer)) {
bool found = false;
// Return the most specific class which we can get the typeref.
ForEachSuperClassType(in_value, [&](SuperClassType sc) -> bool {
Expand Down Expand Up @@ -2436,17 +2438,40 @@ bool SwiftLanguageRuntime::GetAbstractTypeName(StreamString &name,
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Value(
ValueObject &in_value, CompilerType &bound_type,
lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name,
Address &address, Value::ValueType &value_type) {
Address &address, Value::ValueType &value_type,
llvm::ArrayRef<uint8_t> &local_buffer) {
auto static_type = in_value.GetCompilerType();
value_type = Value::ValueType::Invalid;
class_type_or_name.SetCompilerType(bound_type);

ExecutionContext exe_ctx = in_value.GetExecutionContextRef().Lock(true);
ExecutionContextScope *exe_scope = exe_ctx.GetBestExecutionContextScope();
if (!exe_scope)
return false;
std::optional<uint64_t> size =
bound_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
if (!size)
return false;
AddressType address_type;
lldb::addr_t val_address = in_value.GetAddressOf(true, &address_type);
// If we couldn't find a load address, but the value object has a local
// buffer, use that.
if (val_address == LLDB_INVALID_ADDRESS && address_type == eAddressTypeHost) {
// Check if the dynamic type fits in the value object's buffer.
auto in_value_buffer = in_value.GetLocalBuffer();

// If we can't find the local buffer we can't safely know if the
// dynamic type fits in it.
if (in_value_buffer.empty())
return false;
// If the dynamic type doesn't in the buffer we can't use it either.
if (in_value_buffer.size() < bound_type.GetByteSize(exe_scope))
return false;

value_type = Value::GetValueTypeFromAddressType(address_type);
local_buffer = in_value_buffer;
return true;
}
if (*size && (!val_address || val_address == LLDB_INVALID_ADDRESS))
return false;

Expand All @@ -2458,7 +2483,7 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Value(
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_IndirectEnumCase(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
Status error;
CompilerType child_type = in_value.GetCompilerType();
class_type_or_name.SetCompilerType(child_type);
Expand Down Expand Up @@ -2490,7 +2515,7 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_IndirectEnumCase(
return false;

return GetDynamicTypeAndAddress(*valobj_sp, use_dynamic, class_type_or_name,
address, value_type);
address, value_type, local_buffer);
} else {
// This is most likely a statically known type.
address.SetLoadAddress(box_value, &GetProcess().GetTarget());
Expand All @@ -2516,7 +2541,8 @@ void SwiftLanguageRuntime::DumpTyperef(CompilerType type,

Value::ValueType SwiftLanguageRuntime::GetValueType(
ValueObject &in_value, CompilerType dynamic_type,
Value::ValueType static_value_type, bool is_indirect_enum_case) {
Value::ValueType static_value_type, bool is_indirect_enum_case,
llvm::ArrayRef<uint8_t> &local_buffer) {
CompilerType static_type = in_value.GetCompilerType();
Flags static_type_flags(static_type.GetTypeInfo());
Flags dynamic_type_flags(dynamic_type.GetTypeInfo());
Expand Down Expand Up @@ -2570,6 +2596,12 @@ Value::ValueType SwiftLanguageRuntime::GetValueType(
// If the data is not inlined, we have a pointer.
return Value::ValueType::LoadAddress;
}
// If we found a host address and the dynamic type fits in there, and
// this is not a pointer from an existential container, then this points to
// the local buffer.
if (static_value_type == Value::ValueType::HostAddress &&
!local_buffer.empty())
return static_value_type;

if (static_type_flags.AllSet(eTypeIsSwift | eTypeIsGenericTypeParam)) {
// if I am handling a non-pointer Swift type obtained from an archetype,
Expand Down Expand Up @@ -2677,7 +2709,7 @@ std::optional<SwiftNominalType> GetSwiftClass(ValueObject &valobj,
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_ClangType(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
AppleObjCRuntime *objc_runtime =
SwiftLanguageRuntime::GetObjCRuntime(GetProcess());
if (!objc_runtime)
Expand All @@ -2690,8 +2722,9 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_ClangType(
// resolution first, and then map the dynamic Objective-C type back
// into Swift.
TypeAndOrName dyn_class_type_or_name = class_type_or_name;
if (!objc_runtime->GetDynamicTypeAndAddress(
in_value, use_dynamic, dyn_class_type_or_name, address, value_type))
if (!objc_runtime->GetDynamicTypeAndAddress(in_value, use_dynamic,
dyn_class_type_or_name, address,
value_type, local_buffer))
return false;

StringRef dyn_name = dyn_class_type_or_name.GetName().GetStringRef();
Expand Down Expand Up @@ -2797,7 +2830,7 @@ static bool CouldHaveDynamicValue(ValueObject &in_value) {
bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
class_type_or_name.Clear();
if (use_dynamic == lldb::eNoDynamicValues)
return false;
Expand All @@ -2806,8 +2839,9 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(

// Try to import a Clang type into Swift.
if (in_value.GetObjectRuntimeLanguage() == eLanguageTypeObjC)
return GetDynamicTypeAndAddress_ClangType(
in_value, use_dynamic, class_type_or_name, address, value_type);
return GetDynamicTypeAndAddress_ClangType(in_value, use_dynamic,
class_type_or_name, address,
value_type, local_buffer);

if (!CouldHaveDynamicValue(in_value))
return false;
Expand All @@ -2823,7 +2857,8 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
// Type kinds with instance metadata don't need generic type resolution.
if (is_indirect_enum_case)
success = GetDynamicTypeAndAddress_IndirectEnumCase(
in_value, use_dynamic, class_type_or_name, address, static_value_type);
in_value, use_dynamic, class_type_or_name, address, static_value_type,
local_buffer);
else if (type_info.AnySet(eTypeIsPack))
success = GetDynamicTypeAndAddress_Pack(in_value, val_type, use_dynamic,
class_type_or_name, address,
Expand All @@ -2832,7 +2867,7 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
type_info.AllSet(eTypeIsBuiltIn | eTypeIsPointer | eTypeHasValue))
success = GetDynamicTypeAndAddress_Class(in_value, val_type, use_dynamic,
class_type_or_name, address,
static_value_type);
static_value_type, local_buffer);
else if (type_info.AllSet(eTypeIsMetatype | eTypeIsProtocol))
success = GetDynamicTypeAndAddress_ExistentialMetatype(
in_value, val_type, use_dynamic, class_type_or_name, address);
Expand All @@ -2856,16 +2891,16 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(

Flags subst_type_info(bound_type.GetTypeInfo());
if (subst_type_info.AnySet(eTypeIsClass)) {
success = GetDynamicTypeAndAddress_Class(in_value, bound_type,
use_dynamic, class_type_or_name,
address, static_value_type);
success = GetDynamicTypeAndAddress_Class(
in_value, bound_type, use_dynamic, class_type_or_name, address,
static_value_type, local_buffer);
} else if (subst_type_info.AnySet(eTypeIsProtocol)) {
success = GetDynamicTypeAndAddress_Existential(
in_value, bound_type, use_dynamic, class_type_or_name, address);
} else {
success = GetDynamicTypeAndAddress_Value(in_value, bound_type,
use_dynamic, class_type_or_name,
address, static_value_type);
success = GetDynamicTypeAndAddress_Value(
in_value, bound_type, use_dynamic, class_type_or_name, address,
static_value_type, local_buffer);
}
}

Expand All @@ -2875,8 +2910,9 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress(
if (static_value_type == Value::ValueType::Invalid)
static_value_type = in_value.GetValue().GetValueType();

value_type = GetValueType(in_value, class_type_or_name.GetCompilerType(),
static_value_type, is_indirect_enum_case);
value_type =
GetValueType(in_value, class_type_or_name.GetCompilerType(),
static_value_type, is_indirect_enum_case, local_buffer);
}
return success;
}
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/ValueObject/ValueObjectDynamicValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ bool ValueObjectDynamicValue::UpdateValue() {
if (runtime)
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
value_type);
value_type, local_buffer);
}
#endif // LLDB_ENABLE_SWIFT
if (!found_dynamic_type &&
Expand Down
18 changes: 18 additions & 0 deletions lldb/test/API/lang/swift/enable_testing/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
SWIFT_SOURCES := main.swift

all: libPublic.dylib a.out

include Makefile.rules
LD_EXTRAS = -lPublic -L$(BUILDDIR)
SWIFTFLAGS_EXTRAS = -I$(BUILDDIR)

libPublic.dylib: Public.swift
"$(MAKE)" MAKE_DSYM=YES CC=$(CC) SWIFTC=$(SWIFTC) \
ARCH=$(ARCH) DSYMUTIL=$(DSYMUTIL) \
BASENAME=Public \
SWIFTFLAGS_EXTRAS="-I$(BUILDDIR) -enable-library-evolution -enable-testing" \
VPATH=$(SRCDIR) -I $(SRCDIR) \
DYLIB_ONLY:=YES DYLIB_NAME=Public \
DYLIB_SWIFT_SOURCES:=Public.swift \
-f $(MAKEFILE_RULES)

15 changes: 15 additions & 0 deletions lldb/test/API/lang/swift/enable_testing/Public.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class SomeClass {
let value = 42
}

class ClassWithProperty {
private var v = SomeClass()

func f() {
print("break here")
}
}

public func entry() {
ClassWithProperty().f()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil


class TestSwiftEnableTesting(TestBase):

@skipUnlessDarwin
@swiftTest
def test(self):
"""Test that expression evaluation generates a direct member access to a private property in a module compiled with -enable-library-evolution and -enable-testing"""

self.build()
target, process, _, _ = lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("Public.swift"), extra_images=["Public"]
)

self.expect("expression v", substrs=["Public.SomeClass", "value = 42"])
3 changes: 3 additions & 0 deletions lldb/test/API/lang/swift/enable_testing/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Public

entry()
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test(self):
self.expect("expr --bind-generic-types true -- self", error=True, substrs=["Hint"])
# This should work because expression evaluation automatically falls back
# to not binding generic parameters.
self.expect("expression self", substrs=['Generic', '<T>', 'n', '23'])
self.expect("expression self", substrs=['Generic', '<Builder.Private>', 'n', '23'])

process.Continue()
# This should work.
Expand Down
Loading