Author: Matej Košík Date: 2025-10-20T12:48:00+01:00 New Revision: b2ad90b8dcafdf3baea10457c4cac73bb34d06ef
URL: https://github.com/llvm/llvm-project/commit/b2ad90b8dcafdf3baea10457c4cac73bb34d06ef DIFF: https://github.com/llvm/llvm-project/commit/b2ad90b8dcafdf3baea10457c4cac73bb34d06ef.diff LOG: [lldb] Fix the "RegisterValue::SetValueFromData" method for 128-bit integer registers (#163646) Fix the `RegisterValue::SetValueFromData` method so that it works also for 128-bit registers that contain integers. Without this change, the `RegisterValue::SetValueFromData` method does not work correctly for 128-bit registers that contain (signed or unsigned) integers. --- Steps to reproduce the problem: (1) Create a program that writes a 128-bit number to a 128-bit registers `xmm0`. E.g.: ``` #include <stdint.h> int main() { __asm__ volatile ( "pinsrq $0, %[lo], %%xmm0\n\t" // insert low 64 bits "pinsrq $1, %[hi], %%xmm0" // insert high 64 bits : : [lo]"r"(0x7766554433221100), [hi]"r"(0xffeeddccbbaa9988) ); return 0; } ``` (2) Compile this program with LLVM compiler: ``` $ $YOUR/clang -g -o main main.c ``` (3) Modify LLDB so that when it will be reading value from the `xmm0` register, instead of assuming that it is vector register, it will treat it as if it contain an integer. This can be achieved e.g. this way: ``` diff --git a/lldb/source/Utility/RegisterValue.cpp b/lldb/source/Utility/RegisterValue.cpp index 0e99451c3b70..a4b51db3e56d 100644 --- a/lldb/source/Utility/RegisterValue.cpp +++ b/lldb/source/Utility/RegisterValue.cpp @@ -188,6 +188,7 @@ Status RegisterValue::SetValueFromData(const RegisterInfo ®_info, break; case eEncodingUint: case eEncodingSint: + case eEncodingVector: if (reg_info.byte_size == 1) SetUInt8(src.GetMaxU32(&src_offset, src_len)); else if (reg_info.byte_size <= 2) @@ -217,23 +218,6 @@ Status RegisterValue::SetValueFromData(const RegisterInfo ®_info, else if (reg_info.byte_size == sizeof(long double)) SetLongDouble(src.GetLongDouble(&src_offset)); break; - case eEncodingVector: { - m_type = eTypeBytes; - assert(reg_info.byte_size <= kMaxRegisterByteSize); - buffer.bytes.resize(reg_info.byte_size); - buffer.byte_order = src.GetByteOrder(); - if (src.CopyByteOrderedData( - src_offset, // offset within "src" to start extracting data - src_len, // src length - buffer.bytes.data(), // dst buffer - buffer.bytes.size(), // dst length - buffer.byte_order) == 0) // dst byte order - { - error = Status::FromErrorStringWithFormat( - "failed to copy data for register write of %s", reg_info.name); - return error; - } - } } if (m_type == eTypeInvalid) ``` (4) Rebuild the LLDB. (5) Observe what happens how LLDB will print the content of this register after it was initialized with 128-bit value. ``` $YOUR/lldb --source ./main (lldb) target create main Current executable set to '.../main' (x86_64). (lldb) breakpoint set --file main.c --line 11 Breakpoint 1: where = main`main + 45 at main.c:11:3, address = 0x000000000000164d (lldb) settings set stop-line-count-before 20 (lldb) process launch Process 2568735 launched: '.../main' (x86_64) Process 2568735 stopped * thread #1, name = 'main', stop reason = breakpoint 1.1 frame #0: 0x000055555555564d main`main at main.c:11:3 1 #include <stdint.h> 2 3 int main() { 4 __asm__ volatile ( 5 "pinsrq $0, %[lo], %%xmm0\n\t" // insert low 64 bits 6 "pinsrq $1, %[hi], %%xmm0" // insert high 64 bits 7 : 8 : [lo]"r"(0x7766554433221100), 9 [hi]"r"(0xffeeddccbbaa9988) 10 ); -> 11 return 0; 12 } (lldb) register read --format hex xmm0 xmm0 = 0x7766554433221100ffeeddccbbaa9988 ``` You can see that the upper and lower 64-bit wide halves are swapped. --------- Co-authored-by: Matej Košík <[email protected]> Added: Modified: lldb/source/Utility/RegisterValue.cpp lldb/unittests/Utility/RegisterValueTest.cpp Removed: ################################################################################ diff --git a/lldb/source/Utility/RegisterValue.cpp b/lldb/source/Utility/RegisterValue.cpp index 0e99451c3b700..12c349a143c0f 100644 --- a/lldb/source/Utility/RegisterValue.cpp +++ b/lldb/source/Utility/RegisterValue.cpp @@ -199,7 +199,7 @@ Status RegisterValue::SetValueFromData(const RegisterInfo ®_info, else if (reg_info.byte_size <= 16) { uint64_t data1 = src.GetU64(&src_offset); uint64_t data2 = src.GetU64(&src_offset); - if (src.GetByteOrder() == eByteOrderBig) { + if (src.GetByteOrder() == eByteOrderLittle) { int128.x[0] = data1; int128.x[1] = data2; } else { diff --git a/lldb/unittests/Utility/RegisterValueTest.cpp b/lldb/unittests/Utility/RegisterValueTest.cpp index e0863a41605e6..6239dbe21634a 100644 --- a/lldb/unittests/Utility/RegisterValueTest.cpp +++ b/lldb/unittests/Utility/RegisterValueTest.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/lldb-private-types.h" #include "gtest/gtest.h" #include <optional> @@ -54,3 +56,41 @@ TEST(RegisterValueTest, GetScalarValue) { Scalar((APInt(128, 0xffeeddccbbaa9988ull) << 64) | APInt(128, 0x7766554433221100))); } + +static const Scalar etalon128(APInt(128, 0xffeeddccbbaa9988ull) << 64 | + APInt(128, 0x7766554433221100ull)); + +void TestSetValueFromData128(void *src, const lldb::ByteOrder endianness) { + RegisterInfo ri{"uint128_register", + nullptr, + 16, + 0, + lldb::Encoding::eEncodingUint, + lldb::Format::eFormatDefault, + {0, 0, 0, LLDB_INVALID_REGNUM, 0}, + nullptr, + nullptr, + nullptr}; + DataExtractor src_extractor(src, 16, endianness, 8); + RegisterValue rv; + EXPECT_TRUE(rv.SetValueFromData(ri, src_extractor, 0, false).Success()); + Scalar s; + EXPECT_TRUE(rv.GetScalarValue(s)); + EXPECT_EQ(s, etalon128); +} + +// Test that the "RegisterValue::SetValueFromData" method works correctly +// with 128-bit little-endian data that represents an integer. +TEST(RegisterValueTest, SetValueFromData_128_le) { + uint8_t src[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; + TestSetValueFromData128(src, lldb::ByteOrder::eByteOrderLittle); +} + +// Test that the "RegisterValue::SetValueFromData" method works correctly +// with 128-bit big-endian data that represents an integer. +TEST(RegisterValueTest, SetValueFromData_128_be) { + uint8_t src[] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, + 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}; + TestSetValueFromData128(src, lldb::ByteOrder::eByteOrderBig); +} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
