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

Reply via email to