petpav01 created this revision.
Herald added subscribers: kristof.beyls, aemerson.
- Prevent dumping of characters in `DumpDataExtractor()` with `item_byte_size`
bigger than 8 bytes. This case is not supported by the code and results in a
crash because the code calls `DataExtractor::GetMaxU64Bitfield()` ->
`GetMaxU64()` that asserts for byte size > 8 bytes.
- Teach `DataExtractor::GetMaxU64()`, `GetMaxU32()` and `GetMaxS64()` how to
handle byte sizes that are not a multiple of 2. This allows
`DumpDataExtractor()` to dump characters and booleans with `item_byte_size` in
the interval of [1, 8] bytes. Values that are not a multiple of 2 would
previously result in a crash because they were not handled by `GetMaxU64()`.
Examples of two commands that previously resulted in a crash when debugging an
AArch64 target, and their new behaviour:
(lldb) register read --format character v0
v0 = error: unsupported byte size (16) for char format
(lldb) memory read --format boolean --size 7 $sp
0x7ffffffd70: false
0x7ffffffd77: false
[...]
https://reviews.llvm.org/D38394
Files:
include/lldb/Utility/DataExtractor.h
source/Core/DumpDataExtractor.cpp
source/Utility/DataExtractor.cpp
unittests/Core/DataExtractorTest.cpp
Index: unittests/Core/DataExtractorTest.cpp
===================================================================
--- unittests/Core/DataExtractorTest.cpp
+++ unittests/Core/DataExtractorTest.cpp
@@ -49,3 +49,86 @@
EXPECT_EQ(buffer + 4, E.PeekData(4, 0));
EXPECT_EQ(nullptr, E.PeekData(4, 1));
}
+
+TEST(DataExtractorTest, GetMaxU64) {
+ uint8_t buffer[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+ DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
+ sizeof(void *));
+ DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
+
+ lldb::offset_t offset;
+
+ // Check cases at the lower end with the byte size equal to 0 and 1.
+ offset = 0;
+ EXPECT_EQ(0U, LE.GetMaxU64(&offset, 0));
+ EXPECT_EQ(0U, offset);
+ offset = 0;
+ EXPECT_EQ(0U, BE.GetMaxU64(&offset, 0));
+ EXPECT_EQ(0U, offset);
+
+ offset = 0;
+ EXPECT_EQ(0x01U, LE.GetMaxU64(&offset, 1));
+ EXPECT_EQ(1U, offset);
+ offset = 0;
+ EXPECT_EQ(0x01U, BE.GetMaxU64(&offset, 1));
+ EXPECT_EQ(1U, offset);
+
+ // Check with a non-zero offset.
+ offset = 1;
+ EXPECT_EQ(0x0302U, LE.GetMaxU64(&offset, 2));
+ EXPECT_EQ(3U, offset);
+ offset = 1;
+ EXPECT_EQ(0x0203U, BE.GetMaxU64(&offset, 2));
+ EXPECT_EQ(3U, offset);
+
+ // Check with the byte size not being a multiple of 2.
+ offset = 0;
+ EXPECT_EQ(0x07060504030201U, LE.GetMaxU64(&offset, 7));
+ EXPECT_EQ(7U, offset);
+ offset = 0;
+ EXPECT_EQ(0x01020304050607U, BE.GetMaxU64(&offset, 7));
+ EXPECT_EQ(7U, offset);
+
+ // Check with the maximum allowed byte size.
+ offset = 0;
+ EXPECT_EQ(0x0807060504030201U, LE.GetMaxU64(&offset, 8));
+ EXPECT_EQ(8U, offset);
+ offset = 0;
+ EXPECT_EQ(0x0102030405060708U, BE.GetMaxU64(&offset, 8));
+ EXPECT_EQ(8U, offset);
+}
+
+TEST(DataExtractorTest, GetMaxS64) {
+ uint8_t buffer[] = {0x01, 0x02, 0x83, 0x04, 0x05, 0x06, 0x07, 0x08};
+ DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle,
+ sizeof(void *));
+ DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, sizeof(void *));
+
+ lldb::offset_t offset;
+
+ // Check a trivial case with the byte size equal to 0.
+ offset = 0;
+ EXPECT_EQ(0, LE.GetMaxS64(&offset, 0));
+ EXPECT_EQ(0U, offset);
+ offset = 0;
+ EXPECT_EQ(0, BE.GetMaxS64(&offset, 0));
+ EXPECT_EQ(0U, offset);
+
+ // Check that sign extension works correctly.
+ offset = 0;
+ int64_t value = LE.GetMaxS64(&offset, 3);
+ EXPECT_EQ(0xffffffffff830201U, *reinterpret_cast<uint64_t *>(&value));
+ EXPECT_EQ(3U, offset);
+ offset = 2;
+ value = BE.GetMaxS64(&offset, 3);
+ EXPECT_EQ(0xffffffffff830405U, *reinterpret_cast<uint64_t *>(&value));
+ EXPECT_EQ(5U, offset);
+
+ // Check with the maximum allowed byte size.
+ offset = 0;
+ EXPECT_EQ(0x0807060504830201, LE.GetMaxS64(&offset, 8));
+ EXPECT_EQ(8U, offset);
+ offset = 0;
+ EXPECT_EQ(0x0102830405060708, BE.GetMaxS64(&offset, 8));
+ EXPECT_EQ(8U, offset);
+}
Index: source/Utility/DataExtractor.cpp
===================================================================
--- source/Utility/DataExtractor.cpp
+++ source/Utility/DataExtractor.cpp
@@ -563,21 +563,8 @@
//----------------------------------------------------------------------
uint32_t DataExtractor::GetMaxU32(offset_t *offset_ptr,
size_t byte_size) const {
- switch (byte_size) {
- case 1:
- return GetU8(offset_ptr);
- break;
- case 2:
- return GetU16(offset_ptr);
- break;
- case 4:
- return GetU32(offset_ptr);
- break;
- default:
- assert(false && "GetMaxU32 unhandled case!");
- break;
- }
- return 0;
+ assert(byte_size <= 4 && "GetMaxU32 unhandled case!");
+ return GetMaxU64(offset_ptr, byte_size);
}
//----------------------------------------------------------------------
@@ -590,68 +577,63 @@
//
// RETURNS the integer value that was extracted, or zero on failure.
//----------------------------------------------------------------------
-uint64_t DataExtractor::GetMaxU64(offset_t *offset_ptr, size_t size) const {
- switch (size) {
+uint64_t DataExtractor::GetMaxU64(offset_t *offset_ptr,
+ size_t byte_size) const {
+ assert(byte_size <= 8 && "GetMax64 unhandled case!");
+ switch (byte_size) {
case 1:
return GetU8(offset_ptr);
- break;
case 2:
return GetU16(offset_ptr);
- break;
case 4:
return GetU32(offset_ptr);
- break;
case 8:
return GetU64(offset_ptr);
- break;
- default:
- assert(false && "GetMax64 unhandled case!");
- break;
+ default: {
+ // General case.
+ const uint8_t *data =
+ static_cast<const uint8_t *>(GetData(offset_ptr, byte_size));
+ if (data == nullptr)
+ return 0;
+
+ uint64_t res = 0;
+ if (m_byte_order == eByteOrderBig)
+ for (size_t i = 0; i < byte_size; ++i)
+ res = (res << 8) | data[i];
+ else {
+ assert(m_byte_order == eByteOrderLittle);
+ for (size_t i = 0; i < byte_size; ++i)
+ res = (res << 8) | data[byte_size - 1 - i];
+ }
+ return res;
+ }
}
return 0;
}
uint64_t DataExtractor::GetMaxU64_unchecked(offset_t *offset_ptr,
- size_t size) const {
- switch (size) {
+ size_t byte_size) const {
+ switch (byte_size) {
case 1:
return GetU8_unchecked(offset_ptr);
- break;
case 2:
return GetU16_unchecked(offset_ptr);
- break;
case 4:
return GetU32_unchecked(offset_ptr);
- break;
case 8:
return GetU64_unchecked(offset_ptr);
- break;
default:
- assert(false && "GetMax64 unhandled case!");
- break;
+ llvm_unreachable("GetMax64_unchecked unhandled case!");
}
return 0;
}
-int64_t DataExtractor::GetMaxS64(offset_t *offset_ptr, size_t size) const {
- switch (size) {
- case 1:
- return (int8_t)GetU8(offset_ptr);
- break;
- case 2:
- return (int16_t)GetU16(offset_ptr);
- break;
- case 4:
- return (int32_t)GetU32(offset_ptr);
- break;
- case 8:
- return (int64_t)GetU64(offset_ptr);
- break;
- default:
- assert(false && "GetMax64 unhandled case!");
- break;
- }
- return 0;
+int64_t DataExtractor::GetMaxS64(offset_t *offset_ptr, size_t byte_size) const {
+ if (byte_size == 0)
+ return 0;
+
+ uint64_t u64 = GetMaxU64(offset_ptr, byte_size);
+ return llvm::SignExtend64(u64, 8 * byte_size);
}
uint64_t DataExtractor::GetMaxU64Bitfield(offset_t *offset_ptr, size_t size,
Index: source/Core/DumpDataExtractor.cpp
===================================================================
--- source/Core/DumpDataExtractor.cpp
+++ source/Core/DumpDataExtractor.cpp
@@ -272,6 +272,13 @@
case eFormatChar:
case eFormatCharPrintable:
case eFormatCharArray: {
+ // Reject invalid item_byte_size.
+ if (item_byte_size > 8) {
+ s->Printf("error: unsupported byte size (%" PRIu64 ") for char format",
+ (uint64_t)item_byte_size);
+ return offset;
+ }
+
// If we are only printing one character surround it with single
// quotes
if (item_count == 1 && item_format == eFormatChar)
Index: include/lldb/Utility/DataExtractor.h
===================================================================
--- include/lldb/Utility/DataExtractor.h
+++ include/lldb/Utility/DataExtractor.h
@@ -589,7 +589,7 @@
/// The sign extended signed integer value that was extracted,
/// or zero on failure.
//------------------------------------------------------------------
- int64_t GetMaxS64(lldb::offset_t *offset_ptr, size_t size) const;
+ int64_t GetMaxS64(lldb::offset_t *offset_ptr, size_t byte_size) const;
//------------------------------------------------------------------
/// Extract an unsigned integer of size \a byte_size from \a
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits