[Lldb-commits] [lldb] [lldb] Add `ValueObject::CreateValueObjectFromScalar` and fix `Scalar::GetData` (PR #151350)
Ilia Kuklin via lldb-commits
lldb-commits at lists.llvm.org
Thu Jul 31 05:36:45 PDT 2025
https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/151350
>From ff14392e82fb5658c87b4376551a0dc366b33e8c Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Wed, 30 Jul 2025 17:39:43 +0500
Subject: [PATCH 1/2] [lldb] Add `ValueObject::CreateValueObjectFromScalar`
---
lldb/include/lldb/Utility/Scalar.h | 6 +-
lldb/include/lldb/ValueObject/ValueObject.h | 6 ++
.../lldb/ValueObject/ValueObjectConstResult.h | 11 ++++
lldb/source/Core/Value.cpp | 12 +---
lldb/source/Utility/Scalar.cpp | 60 ++++++++++++++-----
lldb/source/ValueObject/ValueObject.cpp | 7 +++
.../ValueObject/ValueObjectConstResult.cpp | 27 +++++++++
lldb/unittests/Utility/ScalarTest.cpp | 18 ++++++
8 files changed, 122 insertions(+), 25 deletions(-)
diff --git a/lldb/include/lldb/Utility/Scalar.h b/lldb/include/lldb/Utility/Scalar.h
index b4b9c7e189582..dbb260962f1d6 100644
--- a/lldb/include/lldb/Utility/Scalar.h
+++ b/lldb/include/lldb/Utility/Scalar.h
@@ -84,11 +84,15 @@ class Scalar {
/// Store the binary representation of this value into the given storage.
/// Exactly GetByteSize() bytes will be stored, and the buffer must be large
/// enough to hold this data.
+ void GetBytes(uint8_t *storage, size_t length) const;
void GetBytes(llvm::MutableArrayRef<uint8_t> storage) const;
size_t GetByteSize() const;
- bool GetData(DataExtractor &data, size_t limit_byte_size = UINT32_MAX) const;
+ /// Get data with a byte size of GetByteSize().
+ bool GetData(DataExtractor &data) const;
+ /// Get data with a byte size forced to \p result_byte_size.
+ bool GetData(DataExtractor &data, size_t result_byte_size) const;
size_t GetAsMemoryData(void *dst, size_t dst_len,
lldb::ByteOrder dst_byte_order, Status &error) const;
diff --git a/lldb/include/lldb/ValueObject/ValueObject.h b/lldb/include/lldb/ValueObject/ValueObject.h
index 3c62f3c17619e..3f9f2b5de8dbe 100644
--- a/lldb/include/lldb/ValueObject/ValueObject.h
+++ b/lldb/include/lldb/ValueObject/ValueObject.h
@@ -737,6 +737,12 @@ class ValueObject {
CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v,
CompilerType type, llvm::StringRef name);
+ /// Create a value object containing the given Scalar value.
+ static lldb::ValueObjectSP CreateValueObjectFromScalar(lldb::TargetSP target,
+ Scalar &s,
+ CompilerType type,
+ llvm::StringRef name);
+
/// Create a value object containing the given boolean value.
static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target,
bool value,
diff --git a/lldb/include/lldb/ValueObject/ValueObjectConstResult.h b/lldb/include/lldb/ValueObject/ValueObjectConstResult.h
index 1e4b81c4dc7f1..6fbb15328ee5c 100644
--- a/lldb/include/lldb/ValueObject/ValueObjectConstResult.h
+++ b/lldb/include/lldb/ValueObject/ValueObjectConstResult.h
@@ -60,6 +60,11 @@ class ValueObjectConstResult : public ValueObject {
Value &value, ConstString name,
Module *module = nullptr);
+ static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
+ const CompilerType &compiler_type,
+ Scalar &scalar, ConstString name,
+ Module *module = nullptr);
+
// When an expression fails to evaluate, we return an error
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope,
Status &&error);
@@ -145,6 +150,12 @@ class ValueObjectConstResult : public ValueObject {
ValueObjectManager &manager, const Value &value,
ConstString name, Module *module = nullptr);
+ ValueObjectConstResult(ExecutionContextScope *exe_scope,
+ ValueObjectManager &manager,
+ const CompilerType &compiler_type,
+ const Scalar &scalar, ConstString name,
+ Module *module = nullptr);
+
ValueObjectConstResult(ExecutionContextScope *exe_scope,
ValueObjectManager &manager, Status &&error);
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index c91b3f852f986..028f0587c5790 100644
--- a/lldb/source/Core/Value.cpp
+++ b/lldb/source/Core/Value.cpp
@@ -347,15 +347,9 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
else
data.SetAddressByteSize(sizeof(void *));
- uint32_t limit_byte_size = UINT32_MAX;
-
- if (type_size)
- limit_byte_size = *type_size;
-
- if (limit_byte_size <= m_value.GetByteSize()) {
- if (m_value.GetData(data, limit_byte_size))
- return error; // Success;
- }
+ uint32_t result_byte_size = *type_size;
+ if (m_value.GetData(data, result_byte_size))
+ return error; // Success;
error = Status::FromErrorString("extracting data from value failed");
break;
diff --git a/lldb/source/Utility/Scalar.cpp b/lldb/source/Utility/Scalar.cpp
index f07a9f3bed00c..7fbe46d46194f 100644
--- a/lldb/source/Utility/Scalar.cpp
+++ b/lldb/source/Utility/Scalar.cpp
@@ -82,7 +82,7 @@ Scalar::Type Scalar::PromoteToMaxType(Scalar &lhs, Scalar &rhs) {
return Scalar::e_void;
}
-bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const {
+bool Scalar::GetData(DataExtractor &data) const {
size_t byte_size = GetByteSize();
if (byte_size == 0) {
data.Clear();
@@ -90,27 +90,57 @@ bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const {
}
auto buffer_up = std::make_unique<DataBufferHeap>(byte_size, 0);
GetBytes(buffer_up->GetData());
- lldb::offset_t offset = 0;
-
- if (limit_byte_size < byte_size) {
- if (endian::InlHostByteOrder() == eByteOrderLittle) {
- // On little endian systems if we want fewer bytes from the current
- // type we just specify fewer bytes since the LSByte is first...
- byte_size = limit_byte_size;
- } else if (endian::InlHostByteOrder() == eByteOrderBig) {
- // On big endian systems if we want fewer bytes from the current type
- // have to advance our initial byte pointer and trim down the number of
- // bytes since the MSByte is first
- offset = byte_size - limit_byte_size;
- byte_size = limit_byte_size;
+ data.SetData(std::move(buffer_up), 0, byte_size);
+ data.SetByteOrder(endian::InlHostByteOrder());
+ return true;
+}
+
+bool Scalar::GetData(DataExtractor &data, size_t result_byte_size) const {
+ size_t byte_size = GetByteSize();
+ if (byte_size == 0 || result_byte_size == 0) {
+ data.Clear();
+ return false;
+ }
+
+ if (endian::InlHostByteOrder() == lldb::eByteOrderBig) {
+ // On big endian systems if we want fewer bytes from the current type
+ // we have to advance our initial byte pointer since the MSByte is
+ // first.
+ if (result_byte_size <= byte_size) {
+ auto buffer_up = std::make_unique<DataBufferHeap>(byte_size, 0);
+ GetBytes(buffer_up->GetData());
+ auto offset = byte_size - result_byte_size;
+ data.SetData(std::move(buffer_up), offset, result_byte_size);
+ data.SetByteOrder(endian::InlHostByteOrder());
+ } else {
+ // Extend created buffer size and insert the data bytes with an offset
+ auto buffer_up = std::make_unique<DataBufferHeap>(result_byte_size, 0);
+ auto offset = result_byte_size - byte_size;
+ GetBytes(buffer_up->GetBytes() + offset, byte_size);
+ data.SetData(std::move(buffer_up), 0, result_byte_size);
+ data.SetByteOrder(endian::InlHostByteOrder());
}
+ return true;
}
- data.SetData(std::move(buffer_up), offset, byte_size);
+ // On little endian systems MSBytes get trimmed or extended automatically by
+ // size.
+ if (byte_size < result_byte_size)
+ byte_size = result_byte_size;
+ auto buffer_up = std::make_unique<DataBufferHeap>(byte_size, 0);
+ GetBytes(buffer_up->GetData());
+ data.SetData(std::move(buffer_up), 0, result_byte_size);
data.SetByteOrder(endian::InlHostByteOrder());
+
return true;
}
+void Scalar::GetBytes(uint8_t *storage, size_t size) const {
+ assert(size >= GetByteSize());
+ llvm::MutableArrayRef<uint8_t> storage_ref(storage, size);
+ GetBytes(storage_ref);
+}
+
void Scalar::GetBytes(llvm::MutableArrayRef<uint8_t> storage) const {
assert(storage.size() >= GetByteSize());
diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp
index 84ad130299221..4bfd778028f3d 100644
--- a/lldb/source/ValueObject/ValueObject.cpp
+++ b/lldb/source/ValueObject/ValueObject.cpp
@@ -3589,6 +3589,13 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat(
return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type, name);
}
+lldb::ValueObjectSP ValueObject::CreateValueObjectFromScalar(
+ lldb::TargetSP target, Scalar &s, CompilerType type, llvm::StringRef name) {
+ ExecutionContext exe_ctx(target.get(), false);
+ return ValueObjectConstResult::Create(exe_ctx.GetBestExecutionContextScope(),
+ type, s, ConstString(name));
+}
+
lldb::ValueObjectSP
ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value,
llvm::StringRef name) {
diff --git a/lldb/source/ValueObject/ValueObjectConstResult.cpp b/lldb/source/ValueObject/ValueObjectConstResult.cpp
index 774749620e0d0..7bedb2d65e7eb 100644
--- a/lldb/source/ValueObject/ValueObjectConstResult.cpp
+++ b/lldb/source/ValueObject/ValueObjectConstResult.cpp
@@ -105,6 +105,16 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
->GetSP();
}
+ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope,
+ const CompilerType &compiler_type,
+ Scalar &scalar, ConstString name,
+ Module *module) {
+ auto manager_sp = ValueObjectManager::Create();
+ return (new ValueObjectConstResult(exe_scope, *manager_sp, compiler_type,
+ scalar, name, module))
+ ->GetSP();
+}
+
ValueObjectConstResult::ValueObjectConstResult(
ExecutionContextScope *exe_scope, ValueObjectManager &manager,
const CompilerType &compiler_type, ConstString name,
@@ -193,6 +203,23 @@ ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope,
m_error = m_value.GetValueAsData(&exe_ctx, m_data, module);
}
+ValueObjectConstResult::ValueObjectConstResult(
+ ExecutionContextScope *exe_scope, ValueObjectManager &manager,
+ const CompilerType &compiler_type, const Scalar &scalar, ConstString name,
+ Module *module)
+ : ValueObject(exe_scope, manager), m_impl(this) {
+ m_value = Value(scalar);
+ m_value.SetCompilerType(compiler_type);
+ m_value.SetValueType(Value::ValueType::Scalar);
+ m_name = name;
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ m_error = m_value.GetValueAsData(&exe_ctx, m_data, module);
+ SetIsConstant();
+ SetValueIsValid(true);
+ SetAddressTypeOfChildren(eAddressTypeInvalid);
+}
+
ValueObjectConstResult::~ValueObjectConstResult() = default;
CompilerType ValueObjectConstResult::GetCompilerTypeImpl() {
diff --git a/lldb/unittests/Utility/ScalarTest.cpp b/lldb/unittests/Utility/ScalarTest.cpp
index 500cb8bb2286e..d8b6f1c7b6a41 100644
--- a/lldb/unittests/Utility/ScalarTest.cpp
+++ b/lldb/unittests/Utility/ScalarTest.cpp
@@ -191,6 +191,24 @@ TEST(ScalarTest, GetData) {
EXPECT_THAT(
get_data(llvm::APSInt::getMaxValue(/*numBits=*/9, /*Unsigned=*/true)),
vec({0x01, 0xff}));
+
+ auto get_data_with_size = [](llvm::APInt v, size_t size) {
+ DataExtractor data;
+ Scalar(v).GetData(data, size);
+ return data.GetData().vec();
+ };
+
+ EXPECT_THAT(get_data_with_size(llvm::APInt(16, 0x0123), 8),
+ vec({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23}));
+
+ EXPECT_THAT(get_data_with_size(llvm::APInt(32, 0x01234567), 4),
+ vec({0x01, 0x23, 0x45, 0x67}));
+
+ EXPECT_THAT(get_data_with_size(llvm::APInt(48, 0xABCD01234567UL), 4),
+ vec({0x01, 0x23, 0x45, 0x67}));
+
+ EXPECT_THAT(get_data_with_size(llvm::APInt(64, 0xABCDEF0123456789UL), 2),
+ vec({0x67, 0x89}));
}
TEST(ScalarTest, SetValueFromData) {
>From 63fcda37195cab9d36ed54e2f64a62c0b2940281 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Thu, 31 Jul 2025 17:36:01 +0500
Subject: [PATCH 2/2] Change the default children address type to
eAddressTypeLoad
---
lldb/source/ValueObject/ValueObjectConstResult.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/source/ValueObject/ValueObjectConstResult.cpp b/lldb/source/ValueObject/ValueObjectConstResult.cpp
index 7bedb2d65e7eb..10a62970edcbb 100644
--- a/lldb/source/ValueObject/ValueObjectConstResult.cpp
+++ b/lldb/source/ValueObject/ValueObjectConstResult.cpp
@@ -217,7 +217,7 @@ ValueObjectConstResult::ValueObjectConstResult(
m_error = m_value.GetValueAsData(&exe_ctx, m_data, module);
SetIsConstant();
SetValueIsValid(true);
- SetAddressTypeOfChildren(eAddressTypeInvalid);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
}
ValueObjectConstResult::~ValueObjectConstResult() = default;
More information about the lldb-commits
mailing list