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 <anoro...@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 <anoro...@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 <anoro...@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 <anoro...@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 <anoro...@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 <anoro...@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); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits