Author: Ilia Kuklin Date: 2025-08-06T14:32:19+05:00 New Revision: dace67e941f309318b5ce200c1f4e180a4471d20
URL: https://github.com/llvm/llvm-project/commit/dace67e941f309318b5ce200c1f4e180a4471d20 DIFF: https://github.com/llvm/llvm-project/commit/dace67e941f309318b5ce200c1f4e180a4471d20.diff LOG: [lldb] Add `ValueObject::CreateValueObjectFromScalar` and fix `Scalar::GetData` (#151350) Add `ValueObject::CreateValueObjectFromScalar` function and adjust `Scalar::GetData` to be able to both extend and truncate the data bytes in Scalar to the specified size. Added: Modified: lldb/include/lldb/Utility/Scalar.h lldb/include/lldb/ValueObject/ValueObject.h lldb/include/lldb/ValueObject/ValueObjectConstResult.h lldb/source/Core/Value.cpp lldb/source/Utility/Scalar.cpp lldb/source/ValueObject/ValueObject.cpp lldb/source/ValueObject/ValueObjectConstResult.cpp lldb/unittests/Utility/ScalarTest.cpp Removed: ################################################################################ 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 38784426b8024..38b9f77e6ddda 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -3590,6 +3590,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..10a62970edcbb 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(eAddressTypeLoad); +} + ValueObjectConstResult::~ValueObjectConstResult() = default; CompilerType ValueObjectConstResult::GetCompilerTypeImpl() { diff --git a/lldb/unittests/Utility/ScalarTest.cpp b/lldb/unittests/Utility/ScalarTest.cpp index 65b9783b9416f..256d456783583 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) { _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits