Index: include/llvm/Support/DataExtractor.h =================================================================== --- include/llvm/Support/DataExtractor.h +++ include/llvm/Support/DataExtractor.h @@ -79,6 +79,9 @@ /// pointed to by \a offset_ptr is out of bounds, or if the /// offset plus the length of the C string is out of bounds, /// NULL will be returned. + const char *getCStr(uint64_t *offset_ptr) const; + + /// \overload const char *getCStr(uint32_t *offset_ptr) const const char *getCStr(uint32_t *offset_ptr) const; /// Extract a C string from \a *OffsetPtr. @@ -101,6 +104,9 @@ /// pointed to by \a OffsetPtr is out of bounds, or if the /// offset plus the length of the C string is out of bounds, /// a default-initialized StringRef will be returned. + StringRef getCStrRef(uint64_t *OffsetPtr) const; + + /// \overload StringRef getCStrRef(uint32_t *OffsetPtr) const StringRef getCStrRef(uint32_t *OffsetPtr) const; /// Extract an unsigned integer of size \a byte_size from \a @@ -127,6 +133,9 @@ /// @return /// The unsigned integer value that was extracted, or zero on /// failure. + uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size) const; + + /// \overload uint64_t getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const uint64_t getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const; /// Extract an signed integer of size \a byte_size from \a *offset_ptr. @@ -152,6 +161,9 @@ /// @return /// The sign extended signed integer value that was extracted, /// or zero on failure. + int64_t getSigned(uint64_t *offset_ptr, uint32_t size) const; + + /// \overload int64_t getSigned(uint32_t *offset_ptr, uint32_t size) const int64_t getSigned(uint32_t *offset_ptr, uint32_t size) const; //------------------------------------------------------------------ @@ -171,6 +183,11 @@ /// /// @return /// The extracted pointer value as a 64 integer. + uint64_t getAddress(uint64_t *offset_ptr) const { + return getUnsigned(offset_ptr, AddressSize); + } + + /// \overload uint64_t getAddress(uint32_t *offset_ptr) const uint64_t getAddress(uint32_t *offset_ptr) const { return getUnsigned(offset_ptr, AddressSize); } @@ -189,6 +206,9 @@ /// /// @return /// The extracted uint8_t value. + uint8_t getU8(uint64_t *offset_ptr) const; + + /// \overload uint8_t getU8(uint32_t *offset_ptr) const uint8_t getU8(uint32_t *offset_ptr) const; /// Extract \a count uint8_t values from \a *offset_ptr. @@ -214,6 +234,9 @@ /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. + uint8_t *getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const; + + /// \overload uint8_t *getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const uint8_t *getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const; //------------------------------------------------------------------ @@ -232,6 +255,9 @@ /// @return /// The extracted uint16_t value. //------------------------------------------------------------------ + uint16_t getU16(uint64_t *offset_ptr) const; + + /// \overload uint16_t getU16(uint32_t *offset_ptr) const uint16_t getU16(uint32_t *offset_ptr) const; /// Extract \a count uint16_t values from \a *offset_ptr. @@ -257,6 +283,9 @@ /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. + uint16_t *getU16(uint64_t *offset_ptr, uint16_t *dst, uint32_t count) const; + + /// \overload uint16_t *getU16(uint32_t *offset_ptr, uint16_t *dst, uint32_t count) const uint16_t *getU16(uint32_t *offset_ptr, uint16_t *dst, uint32_t count) const; /// Extract a 24-bit unsigned value from \a *offset_ptr and return it @@ -274,6 +303,9 @@ /// /// @return /// The extracted 24-bit value represented in a uint32_t. + uint32_t getU24(uint64_t *offset_ptr) const; + + /// \overload uint32_t getU24(uint32_t *offset_ptr) const uint32_t getU24(uint32_t *offset_ptr) const; /// Extract a uint32_t value from \a *offset_ptr. @@ -290,6 +322,9 @@ /// /// @return /// The extracted uint32_t value. + uint32_t getU32(uint64_t *offset_ptr) const; + + /// \overload uint32_t getU32(uint32_t *offset_ptr) const uint32_t getU32(uint32_t *offset_ptr) const; /// Extract \a count uint32_t values from \a *offset_ptr. @@ -315,6 +350,9 @@ /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. + uint32_t *getU32(uint64_t *offset_ptr, uint32_t *dst, uint32_t count) const; + + /// \overload uint32_t *getU32(uint32_t *offset_ptr, uint32_t *dst, uint32_t count) const uint32_t *getU32(uint32_t *offset_ptr, uint32_t *dst, uint32_t count) const; /// Extract a uint64_t value from \a *offset_ptr. @@ -331,6 +369,9 @@ /// /// @return /// The extracted uint64_t value. + uint64_t getU64(uint64_t *offset_ptr) const; + + /// \overload uint64_t getU64(uint32_t *offset_ptr) const uint64_t getU64(uint32_t *offset_ptr) const; /// Extract \a count uint64_t values from \a *offset_ptr. @@ -356,6 +397,9 @@ /// @return /// \a dst if all values were properly extracted and copied, /// NULL otherise. + uint64_t *getU64(uint64_t *offset_ptr, uint64_t *dst, uint32_t count) const; + + /// \overload uint64_t *getU64(uint32_t *offset_ptr, uint64_t *dst, uint32_t count) const uint64_t *getU64(uint32_t *offset_ptr, uint64_t *dst, uint32_t count) const; /// Extract a signed LEB128 value from \a *offset_ptr. @@ -374,6 +418,9 @@ /// /// @return /// The extracted signed integer value. + int64_t getSLEB128(uint64_t *offset_ptr) const; + + /// \overload int64_t getSLEB128(uint32_t *offset_ptr) const int64_t getSLEB128(uint32_t *offset_ptr) const; /// Extract a unsigned LEB128 value from \a *offset_ptr. @@ -392,6 +439,9 @@ /// /// @return /// The extracted unsigned integer value. + uint64_t getULEB128(uint64_t *offset_ptr) const; + + /// \overload uint64_t getULEB128(uint32_t *offset_ptr) const uint64_t getULEB128(uint32_t *offset_ptr) const; /// Test the validity of \a offset. @@ -399,14 +449,14 @@ /// @return /// \b true if \a offset is a valid offset into the data in this /// object, \b false otherwise. - bool isValidOffset(uint32_t offset) const { return Data.size() > offset; } + bool isValidOffset(uint64_t offset) const { return Data.size() > offset; } /// Test the availability of \a length bytes of data from \a offset. /// /// @return /// \b true if \a offset is a valid offset and there are \a /// length bytes available at that offset, \b false otherwise. - bool isValidOffsetForDataOfSize(uint32_t offset, uint32_t length) const { + bool isValidOffsetForDataOfSize(uint64_t offset, uint64_t length) const { return offset + length >= offset && isValidOffset(offset + length - 1); } @@ -417,7 +467,7 @@ /// \b true if \a offset is a valid offset and there are enough /// bytes for a pointer available at that offset, \b false /// otherwise. - bool isValidOffsetForAddress(uint32_t offset) const { + bool isValidOffsetForAddress(uint64_t offset) const { return isValidOffsetForDataOfSize(offset, AddressSize); } }; Index: lib/Support/DataExtractor.cpp =================================================================== --- lib/Support/DataExtractor.cpp +++ lib/Support/DataExtractor.cpp @@ -13,11 +13,11 @@ #include "llvm/Support/LEB128.h" using namespace llvm; -template -static T getU(uint32_t *offset_ptr, const DataExtractor *de, +template +static T getU(TOff *offset_ptr, const DataExtractor *de, bool isLittleEndian, const char *Data) { T val = 0; - uint32_t offset = *offset_ptr; + TOff offset = *offset_ptr; if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) { std::memcpy(&val, &Data[offset], sizeof(val)); if (sys::IsLittleEndianHost != isLittleEndian) @@ -29,10 +29,10 @@ return val; } -template -static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count, +template +static T *getUs(TOff *offset_ptr, T *dst, uint32_t count, const DataExtractor *de, bool isLittleEndian, const char *Data){ - uint32_t offset = *offset_ptr; + TOff offset = *offset_ptr; if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) { for (T *value_ptr = dst, *end = dst + count; value_ptr != end; @@ -47,27 +47,53 @@ return nullptr; } +uint8_t DataExtractor::getU8(uint64_t *offset_ptr) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data()); +} + uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const { return getU(offset_ptr, this, IsLittleEndian, Data.data()); } +uint8_t * +DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const { + return getUs(offset_ptr, dst, count, this, IsLittleEndian, + Data.data()); +} + uint8_t * DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, Data.data()); } +uint16_t DataExtractor::getU16(uint64_t *offset_ptr) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data()); +} uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const { return getU(offset_ptr, this, IsLittleEndian, Data.data()); } +uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst, + uint32_t count) const { + return getUs(offset_ptr, dst, count, this, IsLittleEndian, + Data.data()); +} + uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, Data.data()); } +uint32_t DataExtractor::getU24(uint64_t *offset_ptr) const { + uint24_t ExtractedVal = + getU(offset_ptr, this, IsLittleEndian, Data.data()); + // The 3 bytes are in the correct byte order for the host. + return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); +} + uint32_t DataExtractor::getU24(uint32_t *offset_ptr) const { uint24_t ExtractedVal = getU(offset_ptr, this, IsLittleEndian, Data.data()); @@ -75,58 +101,101 @@ return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); } +uint32_t DataExtractor::getU32(uint64_t *offset_ptr) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data()); +} + uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { return getU(offset_ptr, this, IsLittleEndian, Data.data()); } +uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst, + uint32_t count) const { + return getUs(offset_ptr, dst, count, this, IsLittleEndian, + Data.data()); +} + uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, Data.data()); } +uint64_t DataExtractor::getU64(uint64_t *offset_ptr) const { + return getU(offset_ptr, this, IsLittleEndian, Data.data()); +} + uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const { return getU(offset_ptr, this, IsLittleEndian, Data.data()); } +uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst, + uint32_t count) const { + return getUs(offset_ptr, dst, count, this, IsLittleEndian, + Data.data()); +} + uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst, uint32_t count) const { return getUs(offset_ptr, dst, count, this, IsLittleEndian, Data.data()); } -uint64_t -DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const { +template +static uint64_t getUnsigned(TOff *offset_ptr, uint32_t byte_size, + const DataExtractor *de) { switch (byte_size) { case 1: - return getU8(offset_ptr); + return de->getU8(offset_ptr); case 2: - return getU16(offset_ptr); + return de->getU16(offset_ptr); case 4: - return getU32(offset_ptr); + return de->getU32(offset_ptr); case 8: - return getU64(offset_ptr); + return de->getU64(offset_ptr); } llvm_unreachable("getUnsigned unhandled case!"); } -int64_t -DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const { +uint64_t +DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size) const { + return ::getUnsigned(offset_ptr, byte_size, this); +} + +uint64_t +DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const { + return ::getUnsigned(offset_ptr, byte_size, this); +} + +template +static int64_t getSigned(TOff *offset_ptr, uint32_t byte_size, + const DataExtractor *de) { switch (byte_size) { case 1: - return (int8_t)getU8(offset_ptr); + return (int8_t)de->getU8(offset_ptr); case 2: - return (int16_t)getU16(offset_ptr); + return (int16_t)de->getU16(offset_ptr); case 4: - return (int32_t)getU32(offset_ptr); + return (int32_t)de->getU32(offset_ptr); case 8: - return (int64_t)getU64(offset_ptr); + return (int64_t)de->getU64(offset_ptr); } llvm_unreachable("getSigned unhandled case!"); } -const char *DataExtractor::getCStr(uint32_t *offset_ptr) const { - uint32_t offset = *offset_ptr; +int64_t +DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const { + return ::getSigned(offset_ptr, byte_size, this); +} + +int64_t +DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const { + return ::getSigned(offset_ptr, byte_size, this); +} + +template +static const char *getCStr(TOff* offset_ptr, const StringRef &Data) { + TOff offset = *offset_ptr; StringRef::size_type pos = Data.find('\0', offset); if (pos != StringRef::npos) { *offset_ptr = pos + 1; @@ -135,8 +204,17 @@ return nullptr; } -StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const { - uint32_t Start = *OffsetPtr; +const char *DataExtractor::getCStr(uint64_t *offset_ptr) const { + return ::getCStr(offset_ptr, Data); +} + +const char *DataExtractor::getCStr(uint32_t *offset_ptr) const { + return ::getCStr(offset_ptr, Data); +} + +template +static StringRef getCStrRef(TOff *OffsetPtr, const StringRef &Data) { + TOff Start = *OffsetPtr; StringRef::size_type Pos = Data.find('\0', Start); if (Pos != StringRef::npos) { *OffsetPtr = Pos + 1; @@ -145,7 +223,16 @@ return StringRef(); } -uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { +StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr) const { + return ::getCStrRef(OffsetPtr, Data); +} + +StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const { + return ::getCStrRef(OffsetPtr, Data); +} + +template +static uint64_t getULEB128(TOff *offset_ptr, const StringRef &Data) { assert(*offset_ptr <= Data.size()); const char *error; @@ -159,7 +246,16 @@ return result; } -int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const { +uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr) const { + return ::getULEB128(offset_ptr, Data); +} + +uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { + return ::getULEB128(offset_ptr, Data); +} + +template +static int64_t getSLEB128(TOff *offset_ptr, const StringRef &Data) { assert(*offset_ptr <= Data.size()); const char *error; @@ -172,3 +268,11 @@ *offset_ptr += bytes_read; return result; } + +int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr) const { + return ::getSLEB128(offset_ptr, Data); +} + +int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const { + return ::getSLEB128(offset_ptr, Data); +} Index: unittests/Support/DataExtractorTest.cpp =================================================================== --- unittests/Support/DataExtractorTest.cpp +++ unittests/Support/DataExtractorTest.cpp @@ -12,19 +12,27 @@ namespace { +// Test fixture +template +class DataExtractorTest : public ::testing::Test { }; + +// Test DataExtractor with both types which can be used for offsets. +typedef ::testing::Types TestTypes; +TYPED_TEST_CASE(DataExtractorTest, TestTypes); + const char numberData[] = "\x80\x90\xFF\xFF\x80\x00\x00\x00"; const char stringData[] = "hellohello\0hello"; const char leb128data[] = "\xA6\x49"; const char bigleb128data[] = "\xAA\xA9\xFF\xAA\xFF\xAA\xFF\x4A"; -TEST(DataExtractorTest, OffsetOverflow) { +TYPED_TEST(DataExtractorTest, OffsetOverflow) { DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8); EXPECT_FALSE(DE.isValidOffsetForDataOfSize(-2U, 5)); } -TEST(DataExtractorTest, UnsignedNumbers) { +TYPED_TEST(DataExtractorTest, UnsignedNumbers) { DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8); - uint32_t offset = 0; + TypeParam offset = 0; EXPECT_EQ(0x80U, DE.getU8(&offset)); EXPECT_EQ(1U, offset); @@ -70,9 +78,9 @@ EXPECT_EQ(8U, offset); } -TEST(DataExtractorTest, SignedNumbers) { +TYPED_TEST(DataExtractorTest, SignedNumbers) { DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8); - uint32_t offset = 0; + TypeParam offset = 0; EXPECT_EQ(-128, DE.getSigned(&offset, 1)); EXPECT_EQ(1U, offset); @@ -87,9 +95,9 @@ EXPECT_EQ(8U, offset); } -TEST(DataExtractorTest, Strings) { +TYPED_TEST(DataExtractorTest, Strings) { DataExtractor DE(StringRef(stringData, sizeof(stringData)-1), false, 8); - uint32_t offset = 0; + TypeParam offset = 0; EXPECT_EQ(stringData, DE.getCStr(&offset)); EXPECT_EQ(11U, offset); @@ -97,9 +105,9 @@ EXPECT_EQ(11U, offset); } -TEST(DataExtractorTest, LEB128) { +TYPED_TEST(DataExtractorTest, LEB128) { DataExtractor DE(StringRef(leb128data, sizeof(leb128data)-1), false, 8); - uint32_t offset = 0; + TypeParam offset = 0; EXPECT_EQ(9382ULL, DE.getULEB128(&offset)); EXPECT_EQ(2U, offset); @@ -116,9 +124,9 @@ EXPECT_EQ(8U, offset); } -TEST(DataExtractorTest, LEB128_error) { +TYPED_TEST(DataExtractorTest, LEB128_error) { DataExtractor DE(StringRef("\x81"), false, 8); - uint32_t Offset = 0; + TypeParam Offset = 0; EXPECT_EQ(0U, DE.getULEB128(&Offset)); EXPECT_EQ(0U, Offset);