Fix dumping of characters with non-standard sizes
* 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(), GetMaxS64() and GetMaxU64_unchecked() 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(). llvm-svn: 315444
This commit is contained in:
parent
782f28bf2f
commit
dbd7c338a0
|
@ -513,10 +513,8 @@ public:
|
|||
///
|
||||
/// Extract a single integer value and update the offset pointed to
|
||||
/// by \a offset_ptr. The size of the extracted integer is specified
|
||||
/// by the \a byte_size argument. \a byte_size should have a value
|
||||
/// >= 1 and <= 4 since the return value is only 32 bits wide. Any
|
||||
/// \a byte_size values less than 1 or greater than 4 will result in
|
||||
/// nothing being extracted, and zero being returned.
|
||||
/// by the \a byte_size argument. \a byte_size must have a value
|
||||
/// >= 1 and <= 4 since the return value is only 32 bits wide.
|
||||
///
|
||||
/// @param[in,out] offset_ptr
|
||||
/// A pointer to an offset within the data that will be advanced
|
||||
|
@ -539,11 +537,9 @@ public:
|
|||
///
|
||||
/// Extract a single unsigned integer value and update the offset
|
||||
/// pointed to by \a offset_ptr. The size of the extracted integer
|
||||
/// is specified by the \a byte_size argument. \a byte_size should
|
||||
/// is specified by the \a byte_size argument. \a byte_size must
|
||||
/// have a value greater than or equal to one and less than or equal
|
||||
/// to eight since the return value is 64 bits wide. Any
|
||||
/// \a byte_size values less than 1 or greater than 8 will result in
|
||||
/// nothing being extracted, and zero being returned.
|
||||
/// to eight since the return value is 64 bits wide.
|
||||
///
|
||||
/// @param[in,out] offset_ptr
|
||||
/// A pointer to an offset within the data that will be advanced
|
||||
|
@ -570,10 +566,9 @@ public:
|
|||
/// Extract a single signed integer value (sign extending if required)
|
||||
/// and update the offset pointed to by \a offset_ptr. The size of
|
||||
/// the extracted integer is specified by the \a byte_size argument.
|
||||
/// \a byte_size should have a value greater than or equal to one
|
||||
/// and less than or equal to eight since the return value is 64
|
||||
/// bits wide. Any \a byte_size values less than 1 or greater than
|
||||
/// 8 will result in nothing being extracted, and zero being returned.
|
||||
/// \a byte_size must have a value greater than or equal to one and
|
||||
/// less than or equal to eight since the return value is 64 bits
|
||||
/// wide.
|
||||
///
|
||||
/// @param[in,out] offset_ptr
|
||||
/// A pointer to an offset within the data that will be advanced
|
||||
|
@ -589,7 +584,7 @@ public:
|
|||
/// 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
|
||||
|
@ -598,11 +593,9 @@ public:
|
|||
///
|
||||
/// Extract a single unsigned integer value and update the offset
|
||||
/// pointed to by \a offset_ptr. The size of the extracted integer
|
||||
/// is specified by the \a byte_size argument. \a byte_size should
|
||||
/// is specified by the \a byte_size argument. \a byte_size must
|
||||
/// have a value greater than or equal to one and less than or equal
|
||||
/// to 8 since the return value is 64 bits wide. Any
|
||||
/// \a byte_size values less than 1 or greater than 8 will result in
|
||||
/// nothing being extracted, and zero being returned.
|
||||
/// to 8 since the return value is 64 bits wide.
|
||||
///
|
||||
/// @param[in,out] offset_ptr
|
||||
/// A pointer to an offset within the data that will be advanced
|
||||
|
@ -641,10 +634,9 @@ public:
|
|||
/// Extract a single signed integer value (sign extending if required)
|
||||
/// and update the offset pointed to by \a offset_ptr. The size of
|
||||
/// the extracted integer is specified by the \a byte_size argument.
|
||||
/// \a byte_size should have a value greater than or equal to one
|
||||
/// and less than or equal to eight since the return value is 64
|
||||
/// bits wide. Any \a byte_size values less than 1 or greater than
|
||||
/// 8 will result in nothing being extracted, and zero being returned.
|
||||
/// \a byte_size must have a value greater than or equal to one and
|
||||
/// less than or equal to eight since the return value is 64 bits
|
||||
/// wide.
|
||||
///
|
||||
/// @param[in,out] offset_ptr
|
||||
/// A pointer to an offset within the data that will be advanced
|
||||
|
|
|
@ -272,6 +272,13 @@ lldb::offset_t lldb_private::DumpDataExtractor(
|
|||
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)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "lldb/Utility/DataBuffer.h"
|
||||
#include "lldb/Utility/DataBufferHeap.h"
|
||||
#include "lldb/Utility/Endian.h"
|
||||
#include "lldb/Utility/LLDBAssert.h"
|
||||
#include "lldb/Utility/Log.h"
|
||||
#include "lldb/Utility/Stream.h"
|
||||
#include "lldb/Utility/StreamString.h"
|
||||
|
@ -105,6 +106,20 @@ static inline uint64_t ReadSwapInt64(const void *ptr) {
|
|||
return llvm::ByteSwap_64(value);
|
||||
}
|
||||
|
||||
static inline uint64_t ReadMaxInt64(const uint8_t *data, size_t byte_size,
|
||||
ByteOrder byte_order) {
|
||||
uint64_t res = 0;
|
||||
if (byte_order == eByteOrderBig)
|
||||
for (size_t i = 0; i < byte_size; ++i)
|
||||
res = (res << 8) | data[i];
|
||||
else {
|
||||
assert(byte_order == eByteOrderLittle);
|
||||
for (size_t i = 0; i < byte_size; ++i)
|
||||
res = (res << 8) | data[byte_size - 1 - i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
DataExtractor::DataExtractor()
|
||||
: m_start(nullptr), m_end(nullptr),
|
||||
m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)),
|
||||
|
@ -551,107 +566,59 @@ void *DataExtractor::GetU64(offset_t *offset_ptr, void *void_dst,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Extract a single integer value from the data and update the offset
|
||||
// pointed to by "offset_ptr". The size of the extracted integer
|
||||
// is specified by the "byte_size" argument. "byte_size" should have
|
||||
// a value between 1 and 4 since the return value is only 32 bits
|
||||
// wide. Any "byte_size" values less than 1 or greater than 4 will
|
||||
// result in nothing being extracted, and zero being returned.
|
||||
//
|
||||
// RETURNS the integer value that was extracted, or zero on failure.
|
||||
//----------------------------------------------------------------------
|
||||
uint32_t DataExtractor::GetMaxU32(offset_t *offset_ptr,
|
||||
size_t byte_size) const {
|
||||
lldbassert(byte_size > 0 && byte_size <= 4 && "GetMaxU32 invalid byte_size!");
|
||||
return GetMaxU64(offset_ptr, byte_size);
|
||||
}
|
||||
|
||||
uint64_t DataExtractor::GetMaxU64(offset_t *offset_ptr,
|
||||
size_t byte_size) const {
|
||||
lldbassert(byte_size > 0 && byte_size <= 8 && "GetMaxU64 invalid byte_size!");
|
||||
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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Extract a single integer value from the data and update the offset
|
||||
// pointed to by "offset_ptr". The size of the extracted integer
|
||||
// is specified by the "byte_size" argument. "byte_size" should have
|
||||
// a value >= 1 and <= 8 since the return value is only 64 bits
|
||||
// wide. Any "byte_size" values less than 1 or greater than 8 will
|
||||
// result in nothing being extracted, and zero being returned.
|
||||
//
|
||||
// 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) {
|
||||
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;
|
||||
return ReadMaxInt64(data, byte_size, m_byte_order);
|
||||
}
|
||||
}
|
||||
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;
|
||||
default: {
|
||||
uint64_t res = ReadMaxInt64(&m_start[*offset_ptr], byte_size, m_byte_order);
|
||||
*offset_ptr += byte_size;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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,
|
||||
|
|
|
@ -49,3 +49,120 @@ TEST(DataExtractorTest, PeekData) {
|
|||
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 with the minimum allowed byte size.
|
||||
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 with the minimum allowed byte size.
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x01, LE.GetMaxS64(&offset, 1));
|
||||
EXPECT_EQ(1U, offset);
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x01, BE.GetMaxS64(&offset, 1));
|
||||
EXPECT_EQ(1U, 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);
|
||||
}
|
||||
|
||||
TEST(DataExtractorTest, GetMaxU64_unchecked) {
|
||||
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 with the minimum allowed byte size.
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x01U, LE.GetMaxU64_unchecked(&offset, 1));
|
||||
EXPECT_EQ(1U, offset);
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x01U, BE.GetMaxU64_unchecked(&offset, 1));
|
||||
EXPECT_EQ(1U, offset);
|
||||
|
||||
// Check with a non-zero offset.
|
||||
offset = 1;
|
||||
EXPECT_EQ(0x0302U, LE.GetMaxU64_unchecked(&offset, 2));
|
||||
EXPECT_EQ(3U, offset);
|
||||
offset = 1;
|
||||
EXPECT_EQ(0x0203U, BE.GetMaxU64_unchecked(&offset, 2));
|
||||
EXPECT_EQ(3U, offset);
|
||||
|
||||
// Check with the byte size not being a multiple of 2.
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x07060504030201U, LE.GetMaxU64_unchecked(&offset, 7));
|
||||
EXPECT_EQ(7U, offset);
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x01020304050607U, BE.GetMaxU64_unchecked(&offset, 7));
|
||||
EXPECT_EQ(7U, offset);
|
||||
|
||||
// Check with the maximum allowed byte size.
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x0807060504030201U, LE.GetMaxU64_unchecked(&offset, 8));
|
||||
EXPECT_EQ(8U, offset);
|
||||
offset = 0;
|
||||
EXPECT_EQ(0x0102030405060708U, BE.GetMaxU64_unchecked(&offset, 8));
|
||||
EXPECT_EQ(8U, offset);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue