[Lldb-commits] [lldb] [lldb] Make ValueObjectDynamicValue::UpdateValue() point to a host b… (PR #125143)
Augusto Noronha via lldb-commits
lldb-commits at lists.llvm.org
Wed Feb 5 17:53:51 PST 2025
https://github.com/augusto2112 updated https://github.com/llvm/llvm-project/pull/125143
>From a280e7bc731818143cc89f3ce1150694a44784b3 Mon Sep 17 00:00:00 2001
From: Augusto Noronha <anoronha at apple.com>
Date: Thu, 30 Jan 2025 16:33:09 -0800
Subject: [PATCH 1/6] [lldb] Make ValueObjectDynamicValue::UpdateValue() point
to a host buffer
ValueObjectDynamicValue::UpdateValue() assumes that the dynamic type
found by GetDynamicTypeAndAddress() would return an address in the
inferior. This commit makes it so it can deal with being passed a
host address instead.
This is needed downstream by the Swift fork.
rdar://143357274
---
lldb/include/lldb/Target/LanguageRuntime.h | 4 +++-
.../ValueObject/ValueObjectDynamicValue.cpp | 24 ++++++++++++++-----
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h
index 4a0214b04e235e6..08db8a17a67e69e 100644
--- a/lldb/include/lldb/Target/LanguageRuntime.h
+++ b/lldb/include/lldb/Target/LanguageRuntime.h
@@ -105,7 +105,9 @@ class LanguageRuntime : public Runtime, public PluginInterface {
"language doesn't support getting vtable information");
}
- // this call should return true if it could set the name and/or the type
+ // This call should return true if it could set the name and/or the type.
+ // address can be either a legitimate address on the inferior, or an address
+ // in lldb, if value_type == HostAddress.
virtual bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
diff --git a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
index 588c644bbfd07b6..10a5a9d0b769190 100644
--- a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
+++ b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
@@ -239,11 +239,19 @@ bool ValueObjectDynamicValue::UpdateValue() {
if (m_address.IsValid())
SetValueDidChange(true);
- // We've moved, so we should be fine...
- m_address = dynamic_address;
- lldb::TargetSP target_sp(GetTargetSP());
- lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
- m_value.GetScalar() = load_address;
+ // If we found a host address, point to the buffer in host memory.
+ // Later on this function will copy the buffer over.
+ if (value_type == Value::ValueType::HostAddress) {
+ m_value.GetScalar() = dynamic_address.GetOffset();
+ m_address = LLDB_INVALID_ADDRESS;
+ } else {
+ // Otherwise we have a legitimate address on the target. Point to the load
+ // address.
+ m_address = dynamic_address;
+ lldb::TargetSP target_sp(GetTargetSP());
+ lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
+ m_value.GetScalar() = load_address;
+ }
}
if (runtime)
@@ -258,7 +266,11 @@ bool ValueObjectDynamicValue::UpdateValue() {
LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(),
static_cast<void *>(this), GetTypeName().GetCString());
- if (m_address.IsValid() && m_dynamic_type_info) {
+ // m_address could be invalid but we could still have a local buffer
+ // containing the dynamic value.
+ if ((m_address.IsValid() ||
+ m_value.GetValueType() == Value::ValueType::HostAddress) &&
+ m_dynamic_type_info) {
// The variable value is in the Scalar value inside the m_value. We can
// point our m_data right to it.
m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
>From f914d611f2a9c9758e75fe490cdaedcd40007207 Mon Sep 17 00:00:00 2001
From: Augusto Noronha <anoronha at apple.com>
Date: Mon, 3 Feb 2025 11:23:41 -0800
Subject: [PATCH 2/6] Added a new local_buffer parameter to
GetDynamicTypeAndAddress
---
lldb/include/lldb/Target/LanguageRuntime.h | 16 ++++++++--------
lldb/include/lldb/ValueObject/ValueObject.h | 12 ++++++++++++
.../ItaniumABI/ItaniumABILanguageRuntime.cpp | 2 +-
.../ItaniumABI/ItaniumABILanguageRuntime.h | 4 ++--
.../ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp | 2 +-
.../ObjC/AppleObjCRuntime/AppleObjCRuntime.h | 4 ++--
.../ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp | 2 +-
.../ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h | 4 ++--
.../ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 2 +-
.../ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h | 4 ++--
.../GNUstepObjCRuntime/GNUstepObjCRuntime.cpp | 2 +-
.../ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h | 4 ++--
lldb/source/ValueObject/ValueObject.cpp | 16 ++++++++++++++++
.../ValueObject/ValueObjectDynamicValue.cpp | 13 +++++++------
14 files changed, 58 insertions(+), 29 deletions(-)
diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h
index 08db8a17a67e69e..da7b4801be6691a 100644
--- a/lldb/include/lldb/Target/LanguageRuntime.h
+++ b/lldb/include/lldb/Target/LanguageRuntime.h
@@ -105,14 +105,14 @@ class LanguageRuntime : public Runtime, public PluginInterface {
"language doesn't support getting vtable information");
}
- // This call should return true if it could set the name and/or the type.
- // address can be either a legitimate address on the inferior, or an address
- // in lldb, if value_type == HostAddress.
- virtual bool GetDynamicTypeAndAddress(ValueObject &in_value,
- lldb::DynamicValueType use_dynamic,
- TypeAndOrName &class_type_or_name,
- Address &address,
- Value::ValueType &value_type) = 0;
+ /// This call should return true if it could set the name and/or the type
+ /// Sets address to the address of the dynamic type if value_type is set to
+ /// a file or load address. Sets local_buffer to a buffer containing the data
+ /// of the dynamic type if value_type is set to a host address.
+ virtual bool GetDynamicTypeAndAddress(
+ ValueObject &in_value, lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name, Address &address,
+ Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) = 0;
// This call should return a CompilerType given a generic type name and an
// ExecutionContextScope in which one can actually fetch any specialization
diff --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h
index 4f77384bb8f1361..c8d5c2723106d6d 100644
--- a/lldb/include/lldb/ValueObject/ValueObject.h
+++ b/lldb/include/lldb/ValueObject/ValueObject.h
@@ -865,6 +865,18 @@ class ValueObject {
virtual void SetLanguageFlags(uint64_t flags) { m_language_flags = flags; }
+ /// Returns the size of the local buffer if it's available.
+ /// \return
+ /// The size of the local buffer if this value object's value points to a
+ /// host address, and if that size can be determined. Otherwise, returns
+ /// LLDB_INVALID_ADDRESS.
+ ///
+ /// TODO: Because a ValueObject's Value can point to any arbitrary memory
+ /// location, it is possible that the size of the local buffer can't be
+ /// determined at all. See the comment in Value::m_value for a more thorough
+ /// explanation of why that is.
+ uint64_t GetLocalBufferSize();
+
protected:
typedef ClusterManager<ValueObject> ValueObjectManager;
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index 66cdab1307ce9b9..8faf7135217acfa 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -289,7 +289,7 @@ llvm::Expected<LanguageRuntime::VTableInfo>
bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &dynamic_address,
- Value::ValueType &value_type) {
+ Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
// For Itanium, if the type has a vtable pointer in the object, it will be at
// offset 0 in the object. That will point to the "address point" within the
// vtable (not the beginning of the vtable.) We can then look up the symbol
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
index 0f7e73cfee07546..7abf2f8547cd508 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
@@ -54,8 +54,8 @@ class ItaniumABILanguageRuntime : public lldb_private::CPPLanguageRuntime {
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;
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index ceee19c136d253d..ad60290382c02dd 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -276,7 +276,7 @@ bool AppleObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
bool AppleObjCRuntime::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) {
return false;
}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
index da58d44db19a890..425a608d65c2cf3 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
@@ -54,8 +54,8 @@ class AppleObjCRuntime : public lldb_private::ObjCLanguageRuntime {
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;
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index 93168c23f3547b6..db1317d70d060c9 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -48,7 +48,7 @@ AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process)
bool AppleObjCRuntimeV1::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();
value_type = Value::ValueType::Scalar;
if (CouldHaveDynamicValue(in_value)) {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
index 46d8e89c906e321..c51ac24e690b808 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
@@ -100,8 +100,8 @@ class AppleObjCRuntimeV1 : public AppleObjCRuntime {
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;
llvm::Expected<std::unique_ptr<UtilityFunction>>
CreateObjectChecker(std::string, ExecutionContext &exe_ctx) override;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index c43871b08191db2..a57099f3df4543e 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -770,7 +770,7 @@ AppleObjCRuntimeV2::GetPreferredLanguageRuntime(ValueObject &in_value) {
bool AppleObjCRuntimeV2::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) {
// We should never get here with a null process...
assert(m_process != nullptr);
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index 2422539b13f13dd..79840f9be79b3a2 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -53,8 +53,8 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime {
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;
llvm::Expected<std::unique_ptr<UtilityFunction>>
CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override;
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
index d6ffb03ab55e2c3..a4b3e26474a550e 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp
@@ -127,7 +127,7 @@ bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
bool GNUstepObjCRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
- Value::ValueType &value_type) {
+ Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {
return false;
}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
index de24466ebb003cd..94a5c9e1261a823 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h
@@ -67,8 +67,8 @@ class GNUstepObjCRuntime : public lldb_private::ObjCLanguageRuntime {
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;
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index 2864af107b925fc..551d882a48d40f6 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -849,6 +849,22 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) {
return true;
}
+uint64_t ValueObject::GetLocalBufferSize() {
+ if (m_value.GetValueType() != Value::ValueType::HostAddress)
+ return LLDB_INVALID_ADDRESS;
+ auto start = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (start == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+ // Does our pointer point to this value object's m_data buffer?
+ if ((uint64_t)m_data.GetDataStart() == start)
+ return m_data.GetByteSize();
+ // Does our pointer point to the value's buffer?
+ if ((uint64_t)m_value.GetBuffer().GetBytes() == start)
+ return m_value.GetBuffer().GetByteSize();
+ // Our pointer points to something else. We can't know what the size is.
+ return LLDB_INVALID_ADDRESS;
+}
+
static bool CopyStringDataToBufferSP(const StreamString &source,
lldb::WritableDataBufferSP &destination) {
llvm::StringRef src = source.GetString();
diff --git a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
index 10a5a9d0b769190..6d6e589b534067a 100644
--- a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
+++ b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
@@ -145,6 +145,7 @@ bool ValueObjectDynamicValue::UpdateValue() {
Address dynamic_address;
bool found_dynamic_type = false;
Value::ValueType value_type;
+ llvm::ArrayRef<uint8_t> local_buffer;
LanguageRuntime *runtime = nullptr;
@@ -157,7 +158,7 @@ bool ValueObjectDynamicValue::UpdateValue() {
// Try the preferred runtime first.
found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
- value_type);
+ value_type, local_buffer);
if (found_dynamic_type)
// Set the operative `runtime` for later use in this function.
runtime = preferred_runtime;
@@ -166,20 +167,20 @@ bool ValueObjectDynamicValue::UpdateValue() {
// Fallback to the runtime for `known_type`.
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
- value_type);
+ value_type, local_buffer);
} else {
runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus);
if (runtime)
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
- value_type);
+ value_type, local_buffer);
if (!found_dynamic_type) {
runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC);
if (runtime)
found_dynamic_type = runtime->GetDynamicTypeAndAddress(
*m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
- value_type);
+ value_type, local_buffer);
}
}
@@ -241,8 +242,8 @@ bool ValueObjectDynamicValue::UpdateValue() {
// If we found a host address, point to the buffer in host memory.
// Later on this function will copy the buffer over.
- if (value_type == Value::ValueType::HostAddress) {
- m_value.GetScalar() = dynamic_address.GetOffset();
+ if (value_type == Value::ValueType::HostAddress && !local_buffer.empty()) {
+ m_value.GetScalar() = (uint64_t)local_buffer.data();
m_address = LLDB_INVALID_ADDRESS;
} else {
// Otherwise we have a legitimate address on the target. Point to the load
>From 50218a6ea96278bea914353b32a7812f289559dd Mon Sep 17 00:00:00 2001
From: Augusto Noronha <anoronha at apple.com>
Date: Mon, 3 Feb 2025 11:59:49 -0800
Subject: [PATCH 3/6] Check the buffer size in ValueObjectDynamicValue
---
lldb/source/ValueObject/ValueObjectDynamicValue.cpp | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
index 6d6e589b534067a..3f668b8bd173f62 100644
--- a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
+++ b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
@@ -240,9 +240,13 @@ bool ValueObjectDynamicValue::UpdateValue() {
if (m_address.IsValid())
SetValueDidChange(true);
- // If we found a host address, point to the buffer in host memory.
- // Later on this function will copy the buffer over.
- if (value_type == Value::ValueType::HostAddress && !local_buffer.empty()) {
+ auto *exe_scope = exe_ctx.GetBestExecutionContextScope();
+ // If we found a host address, and the dynamic type fits in the local buffer
+ // that was found, point to thar buffer. Later on this function will copy
+ // the buffer over.
+ if (value_type == Value::ValueType::HostAddress && !local_buffer.empty() &&
+ local_buffer.size() <=
+ m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope)) {
m_value.GetScalar() = (uint64_t)local_buffer.data();
m_address = LLDB_INVALID_ADDRESS;
} else {
>From c12459aec4289799ee4ef20a29a54e10ea6cf107 Mon Sep 17 00:00:00 2001
From: Augusto Noronha <anoronha at apple.com>
Date: Mon, 3 Feb 2025 16:44:23 -0800
Subject: [PATCH 4/6] Clarify ownership of buffer
---
lldb/include/lldb/Target/LanguageRuntime.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h
index da7b4801be6691a..4af3e0e5d8c47c4 100644
--- a/lldb/include/lldb/Target/LanguageRuntime.h
+++ b/lldb/include/lldb/Target/LanguageRuntime.h
@@ -108,7 +108,9 @@ class LanguageRuntime : public Runtime, public PluginInterface {
/// This call should return true if it could set the name and/or the type
/// Sets address to the address of the dynamic type if value_type is set to
/// a file or load address. Sets local_buffer to a buffer containing the data
- /// of the dynamic type if value_type is set to a host address.
+ /// of the dynamic type if value_type is set to a host address. Callers should
+ /// copy local_buffer over into their own buffer if they want to keep the data
+ ///alive.
virtual bool GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
>From 854f74e16d5c111b12b396b662e6c0cb87f10ee9 Mon Sep 17 00:00:00 2001
From: Augusto Noronha <anoronha at apple.com>
Date: Tue, 4 Feb 2025 08:26:03 -0800
Subject: [PATCH 5/6] clang format
---
lldb/include/lldb/Target/LanguageRuntime.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h
index 4af3e0e5d8c47c4..f9ae2dc5896329c 100644
--- a/lldb/include/lldb/Target/LanguageRuntime.h
+++ b/lldb/include/lldb/Target/LanguageRuntime.h
@@ -108,9 +108,9 @@ class LanguageRuntime : public Runtime, public PluginInterface {
/// This call should return true if it could set the name and/or the type
/// Sets address to the address of the dynamic type if value_type is set to
/// a file or load address. Sets local_buffer to a buffer containing the data
- /// of the dynamic type if value_type is set to a host address. Callers should
+ /// of the dynamic type if value_type is set to a host address. Callers should
/// copy local_buffer over into their own buffer if they want to keep the data
- ///alive.
+ /// alive.
virtual bool GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
>From 441192a4ea4d482b7c927285cd68727fef5cdd69 Mon Sep 17 00:00:00 2001
From: Augusto Noronha <anoronha at apple.com>
Date: Wed, 5 Feb 2025 17:52:21 -0800
Subject: [PATCH 6/6] add test
---
.../ValueObject/ValueObjectDynamicValue.cpp | 13 +-
.../TestingSupport/Symbol/ClangTestUtils.h | 22 +-
lldb/unittests/ValueObject/CMakeLists.txt | 1 +
.../ValueObject/ValueObjectLocalBuffer.cpp | 237 ++++++++++++++++++
4 files changed, 260 insertions(+), 13 deletions(-)
create mode 100644 lldb/unittests/ValueObject/ValueObjectLocalBuffer.cpp
diff --git a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
index 3f668b8bd173f62..40e72112cdc92c2 100644
--- a/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
+++ b/lldb/source/ValueObject/ValueObjectDynamicValue.cpp
@@ -244,9 +244,16 @@ bool ValueObjectDynamicValue::UpdateValue() {
// If we found a host address, and the dynamic type fits in the local buffer
// that was found, point to thar buffer. Later on this function will copy
// the buffer over.
- if (value_type == Value::ValueType::HostAddress && !local_buffer.empty() &&
- local_buffer.size() <=
- m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope)) {
+ if (value_type == Value::ValueType::HostAddress) {
+ // If we found a host address but it doesn't fit in the buffer, there's
+ // nothing we can do.
+ if (local_buffer.empty() ||
+ local_buffer.size() <
+ m_dynamic_type_info.GetCompilerType().GetByteSize(exe_scope)) {
+ SetValueIsValid(false);
+ return false;
+ }
+
m_value.GetScalar() = (uint64_t)local_buffer.data();
m_address = LLDB_INVALID_ADDRESS;
} else {
diff --git a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h
index 21525266119b404..63b2ba8c8688a4e 100644
--- a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h
+++ b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h
@@ -21,20 +21,21 @@ inline clang::DeclarationName getDeclarationName(TypeSystemClang &ast,
return ast.getASTContext().DeclarationNames.getIdentifier(&II);
}
-inline CompilerType createRecord(TypeSystemClang &ast, llvm::StringRef name) {
+inline CompilerType
+createRecord(TypeSystemClang &ast, llvm::StringRef name,
+ lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
return ast.CreateRecordType(ast.getASTContext().getTranslationUnitDecl(),
OptionalClangModuleID(),
- lldb::AccessType::eAccessPublic, name, 0,
- lldb::LanguageType::eLanguageTypeC);
+ lldb::AccessType::eAccessPublic, name, 0, lang);
}
/// Create a record with the given name and a field with the given type
/// and name.
-inline CompilerType createRecordWithField(TypeSystemClang &ast,
- llvm::StringRef record_name,
- CompilerType field_type,
- llvm::StringRef field_name) {
- CompilerType t = createRecord(ast, record_name);
+inline CompilerType createRecordWithField(
+ TypeSystemClang &ast, llvm::StringRef record_name, CompilerType field_type,
+ llvm::StringRef field_name,
+ lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
+ CompilerType t = createRecord(ast, record_name, lang);
TypeSystemClang::StartTagDeclarationDefinition(t);
ast.AddFieldToRecordType(t, field_name, field_type,
@@ -63,12 +64,13 @@ struct SourceASTWithRecord {
CompilerType record_type;
clang::RecordDecl *record_decl = nullptr;
clang::FieldDecl *field_decl = nullptr;
- SourceASTWithRecord() {
+ SourceASTWithRecord(
+ lldb::LanguageType lang = lldb::LanguageType::eLanguageTypeC) {
holder = std::make_unique<TypeSystemClangHolder>("test ASTContext");
ast = holder->GetAST();
record_type = createRecordWithField(
*ast, "Source", ast->GetBasicType(lldb::BasicType::eBasicTypeChar),
- "a_field");
+ "a_field", lang);
record_decl =
llvm::cast<clang::RecordDecl>(ClangUtil::GetAsTagDecl(record_type));
field_decl = *record_decl->fields().begin();
diff --git a/lldb/unittests/ValueObject/CMakeLists.txt b/lldb/unittests/ValueObject/CMakeLists.txt
index 14808aa2f213a55..78b234054e8864f 100644
--- a/lldb/unittests/ValueObject/CMakeLists.txt
+++ b/lldb/unittests/ValueObject/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_unittest(LLDBValueObjectTests
DumpValueObjectOptionsTests.cpp
DILLexerTests.cpp
+ ValueObjectLocalBuffer.cpp
LINK_LIBS
lldbValueObject
diff --git a/lldb/unittests/ValueObject/ValueObjectLocalBuffer.cpp b/lldb/unittests/ValueObject/ValueObjectLocalBuffer.cpp
new file mode 100644
index 000000000000000..a6324492e2781d7
--- /dev/null
+++ b/lldb/unittests/ValueObject/ValueObjectLocalBuffer.cpp
@@ -0,0 +1,237 @@
+//===-- DumpValueObjectOptionsTests.cpp -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "TestingSupport/SubsystemRAII.h"
+#include "TestingSupport/Symbol/ClangTestUtils.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/Language.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/ValueObject/ValueObject.h"
+#include "lldb/ValueObject/ValueObjectConstResult.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::clang_utils;
+
+// This entire class is boilerplate.
+struct MockLanguage : public Language {
+
+ llvm::StringRef GetPluginName() override { return "MockLanguage"; }
+ lldb::LanguageType GetLanguageType() const override {
+ return lldb::eLanguageTypeC_plus_plus;
+ };
+
+ static Language *CreateInstance(lldb::LanguageType language) {
+ return new MockLanguage();
+ }
+ static void Initialize() {
+ PluginManager::RegisterPlugin("MockLanguage", "Mock Language",
+ CreateInstance);
+ };
+
+ static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
+ bool IsSourceFile(llvm::StringRef file_path) const override { return true; }
+};
+LLDB_PLUGIN_DEFINE(MockLanguage)
+
+struct MockLanguageRuntime : public LanguageRuntime {
+ // This is the only method in this class that matters for this test.
+ // This will unconditionally succeed and return a type with size 4,
+ // a value_type of HostAddress, and a local buffer that points to the parent's
+ // local buffer.
+ // The tests will set that buffer to be either be larger or smaller than the
+ // type we're returning.
+ bool
+ GetDynamicTypeAndAddress(ValueObject &in_value,
+ lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name, Address &address,
+ Value::ValueType &value_type,
+ llvm::ArrayRef<uint8_t> &local_buffer) override {
+ auto ast = in_value.GetCompilerType()
+ .GetTypeSystem()
+ .dyn_cast_or_null<TypeSystemClang>();
+
+ auto int_type = createRecordWithField(
+ *ast, "TypeWitInt", ast->GetBasicType(lldb::BasicType::eBasicTypeInt),
+ "theIntField", LanguageType::eLanguageTypeC_plus_plus);
+ class_type_or_name.SetCompilerType(int_type);
+ local_buffer = {(uint8_t *)in_value.GetValue().GetScalar().ULongLong(
+ LLDB_INVALID_ADDRESS),
+ in_value.GetLocalBufferSize()};
+ value_type = Value::ValueType::HostAddress;
+
+ return true;
+ }
+
+ // All of this is boilerplate.
+ MockLanguageRuntime(Process *process) : LanguageRuntime(process) {}
+ llvm::StringRef GetPluginName() override { return "MockLanguageRuntime"; }
+ lldb::LanguageType GetLanguageType() const override {
+ return lldb::eLanguageTypeC_plus_plus;
+ }
+
+ llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override {
+ return llvm::Error::success();
+ }
+
+ llvm::Error GetObjectDescription(Stream &str, Value &value,
+ ExecutionContextScope *exe_scope) override {
+ return llvm::Error::success();
+ }
+
+ bool CouldHaveDynamicValue(ValueObject &in_value) override { return true; }
+
+ TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
+ ValueObject &static_value) override {
+ return type_and_or_name;
+ }
+
+ lldb::BreakpointResolverSP
+ CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
+ bool throw_bp) override {
+ return lldb::BreakpointResolverSP();
+ }
+
+ lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+ bool stop_others) override {
+ return {};
+ }
+
+ static LanguageRuntime *CreateInstance(Process *process,
+ LanguageType language) {
+ return new MockLanguageRuntime(process);
+ }
+
+ static void Initialize() {
+ PluginManager::RegisterPlugin(
+ "MockLanguageRuntime", "MockLanguageRuntime", CreateInstance,
+ [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
+ return {};
+ },
+ [](lldb::LanguageType language,
+ bool throw_bp) -> BreakpointPreconditionSP { return {}; });
+ }
+
+ static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
+};
+LLDB_PLUGIN_DEFINE(MockLanguageRuntime)
+
+// This entire class is boilerplate.
+struct MockProcess : Process {
+ MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
+ : Process(target_sp, listener_sp) {}
+
+ llvm::StringRef GetPluginName() override { return "mock process"; }
+
+ bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
+ return false;
+ };
+
+ Status DoDestroy() override { return {}; }
+
+ void RefreshStateAfterStop() override {}
+
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override {
+ return false;
+ };
+
+ size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Status &error) override {
+ // No need to read memory in these tests.
+ return size;
+ }
+};
+
+class ValueObjectLocalBufferTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ ArchSpec arch("i386-pc-linux");
+ Platform::SetHostPlatform(
+ platform_linux::PlatformLinux::CreateInstance(true, &arch));
+ // std::call_once(TestUtilities::g_debugger_initialize_flag,
+ // []() { Debugger::Initialize(nullptr); });
+ m_debugger_sp = Debugger::CreateInstance();
+ ASSERT_TRUE(m_debugger_sp);
+ m_debugger_sp->GetTargetList().CreateTarget(*m_debugger_sp, "", arch,
+ eLoadDependentsNo,
+ m_platform_sp, m_target_sp);
+ ASSERT_TRUE(m_target_sp);
+ ASSERT_TRUE(m_target_sp->GetArchitecture().IsValid());
+ ASSERT_TRUE(m_platform_sp);
+ m_listener_sp = Listener::MakeListener("dummy");
+ m_process_sp = std::make_shared<MockProcess>(m_target_sp, m_listener_sp);
+ ASSERT_TRUE(m_process_sp);
+ m_exe_ctx = ExecutionContext(m_process_sp);
+
+ m_holder = std::make_unique<clang_utils::TypeSystemClangHolder>("test");
+ m_type_system = m_holder->GetAST();
+ LLDB_PLUGIN_INITIALIZE(MockLanguage);
+ LLDB_PLUGIN_INITIALIZE(MockLanguageRuntime);
+ }
+ void TearDown() override {
+ LLDB_PLUGIN_TERMINATE(MockLanguage);
+ LLDB_PLUGIN_TERMINATE(MockLanguageRuntime);
+ }
+
+ void TestValueObjectWithLocalBuffer(DataExtractor &data_extractor,
+ bool should_succeed) {
+ std::unique_ptr<TypeSystemClangHolder> holder =
+ std::make_unique<TypeSystemClangHolder>("test ASTContext");
+ TypeSystemClang *ast = holder->GetAST();
+ auto char_type = createRecordWithField(
+ *ast, "TypeWithChar",
+ ast->GetBasicType(lldb::BasicType::eBasicTypeChar), "theField");
+
+ ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
+ ConstString var_name("test_var");
+ auto valobj_sp = ValueObjectConstResult::Create(exe_scope, char_type,
+ var_name, data_extractor);
+ auto dyn_valobj = valobj_sp->GetDynamicValue(lldb::eDynamicCanRunTarget);
+ ASSERT_TRUE(dyn_valobj->GetValueIsValid() == should_succeed);
+ }
+
+ SubsystemRAII<FileSystem, HostInfo, platform_linux::PlatformLinux,
+ ScriptInterpreterNone>
+ m_subsystems;
+ std::unique_ptr<clang_utils::TypeSystemClangHolder> m_holder;
+ lldb::DebuggerSP m_debugger_sp;
+ lldb::TargetSP m_target_sp;
+ lldb::PlatformSP m_platform_sp;
+ lldb::ListenerSP m_listener_sp;
+ lldb::ProcessSP m_process_sp;
+ ExecutionContext m_exe_ctx;
+ TypeSystemClang *m_type_system;
+};
+
+TEST_F(ValueObjectLocalBufferTest, BufferTooSmall) {
+ u_int8_t value = 1;
+ ByteOrder endian = endian::InlHostByteOrder();
+ DataExtractor data_extractor{&value, sizeof(value), endian, 4};
+ TestValueObjectWithLocalBuffer(data_extractor, false);
+}
+
+TEST_F(ValueObjectLocalBufferTest, BufferTooBig) {
+ uint64_t value = 1;
+ ByteOrder endian = endian::InlHostByteOrder();
+ DataExtractor data_extractor{&value, sizeof(value), endian, 4};
+ TestValueObjectWithLocalBuffer(data_extractor, true);
+}
+
+TEST_F(ValueObjectLocalBufferTest, BufferExactlyRight) {
+ uint32_t value = 1;
+ ByteOrder endian = endian::InlHostByteOrder();
+ DataExtractor data_extractor{&value, sizeof(value), endian, 4};
+ TestValueObjectWithLocalBuffer(data_extractor, true);
+}
More information about the lldb-commits
mailing list