forked from OSchip/llvm-project
[Support] Add LEB128 support to BinaryStreamReader/Writer.
Summary: This patch adds support for ULEB128 and SLEB128 encoding and decoding to BinaryStreamWriter and BinaryStreamReader respectively. Support for ULEB128/SLEB128 will be used for eh-frame parsing in the JITLink library currently under development (see https://reviews.llvm.org/D58704). Reviewers: zturner, dblaikie Subscribers: kristina, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D60810 llvm-svn: 358584
This commit is contained in:
parent
258a425c69
commit
c1106c9b11
|
@ -96,6 +96,18 @@ public:
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
/// Read an unsigned LEB128 encoded value.
|
||||
///
|
||||
/// \returns a success error code if the data was successfully read, otherwise
|
||||
/// returns an appropriate error code.
|
||||
Error readULEB128(uint64_t &Dest);
|
||||
|
||||
/// Read a signed LEB128 encoded value.
|
||||
///
|
||||
/// \returns a success error code if the data was successfully read, otherwise
|
||||
/// returns an appropriate error code.
|
||||
Error readSLEB128(int64_t &Dest);
|
||||
|
||||
/// Read a null terminated string from \p Dest. Whether a copy occurs depends
|
||||
/// on the implementation of the underlying stream. Updates the stream's
|
||||
/// offset to point after the newly read data.
|
||||
|
|
|
@ -79,6 +79,20 @@ public:
|
|||
return writeInteger<U>(static_cast<U>(Num));
|
||||
}
|
||||
|
||||
/// Write the unsigned integer Value to the underlying stream using ULEB128
|
||||
/// encoding.
|
||||
///
|
||||
/// \returns a success error code if the data was successfully written,
|
||||
/// otherwise returns an appropriate error code.
|
||||
Error writeULEB128(uint64_t Value);
|
||||
|
||||
/// Write the unsigned integer Value to the underlying stream using ULEB128
|
||||
/// encoding.
|
||||
///
|
||||
/// \returns a success error code if the data was successfully written,
|
||||
/// otherwise returns an appropriate error code.
|
||||
Error writeSLEB128(int64_t Value);
|
||||
|
||||
/// Write the string \p Str to the underlying stream followed by a null
|
||||
/// terminator. On success, updates the offset so that subsequent writes
|
||||
/// occur at the next unwritten position. \p Str need not be null terminated
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "llvm/Support/BinaryStreamError.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
|
||||
using namespace llvm;
|
||||
using endianness = llvm::support::endianness;
|
||||
|
@ -40,6 +41,36 @@ Error BinaryStreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error BinaryStreamReader::readULEB128(uint64_t &Dest) {
|
||||
SmallVector<uint8_t, 10> EncodedBytes;
|
||||
ArrayRef<uint8_t> NextByte;
|
||||
|
||||
// Copy the encoded ULEB into the buffer.
|
||||
do {
|
||||
if (auto Err = readBytes(NextByte, 1))
|
||||
return Err;
|
||||
EncodedBytes.push_back(NextByte[0]);
|
||||
} while (NextByte[0] & 0x80);
|
||||
|
||||
Dest = decodeULEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error BinaryStreamReader::readSLEB128(int64_t &Dest) {
|
||||
SmallVector<uint8_t, 10> EncodedBytes;
|
||||
ArrayRef<uint8_t> NextByte;
|
||||
|
||||
// Copy the encoded ULEB into the buffer.
|
||||
do {
|
||||
if (auto Err = readBytes(NextByte, 1))
|
||||
return Err;
|
||||
EncodedBytes.push_back(NextByte[0]);
|
||||
} while (NextByte[0] & 0x80);
|
||||
|
||||
Dest = decodeSLEB128(EncodedBytes.begin(), nullptr, EncodedBytes.end());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error BinaryStreamReader::readCString(StringRef &Dest) {
|
||||
uint32_t OriginalOffset = getOffset();
|
||||
uint32_t FoundOffset = 0;
|
||||
|
@ -145,4 +176,4 @@ BinaryStreamReader::split(uint32_t Off) const {
|
|||
BinaryStreamReader W1{First};
|
||||
BinaryStreamReader W2{Second};
|
||||
return std::make_pair(W1, W2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "llvm/Support/BinaryStreamError.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
@ -31,6 +32,18 @@ Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error BinaryStreamWriter::writeULEB128(uint64_t Value) {
|
||||
uint8_t EncodedBytes[10] = {0};
|
||||
unsigned Size = encodeULEB128(Value, &EncodedBytes[0]);
|
||||
return writeBytes({EncodedBytes, Size});
|
||||
}
|
||||
|
||||
Error BinaryStreamWriter::writeSLEB128(int64_t Value) {
|
||||
uint8_t EncodedBytes[10] = {0};
|
||||
unsigned Size = encodeSLEB128(Value, &EncodedBytes[0]);
|
||||
return writeBytes({EncodedBytes, Size});
|
||||
}
|
||||
|
||||
Error BinaryStreamWriter::writeCString(StringRef Str) {
|
||||
if (auto EC = writeFixedString(Str))
|
||||
return EC;
|
||||
|
|
|
@ -610,6 +610,77 @@ TEST_F(BinaryStreamTest, StreamReaderEnum) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderULEB128) {
|
||||
std::vector<uint64_t> TestValues = {
|
||||
0, // Zero
|
||||
0x7F, // One byte
|
||||
0xFF, // One byte, all-ones
|
||||
0xAAAA, // Two bytes
|
||||
0xAAAAAAAA, // Four bytes
|
||||
0xAAAAAAAAAAAAAAAA, // Eight bytes
|
||||
0xffffffffffffffff // Eight bytess, all-ones
|
||||
};
|
||||
|
||||
// Conservatively assume a 10-byte encoding for each of our LEB128s, with no
|
||||
// alignment requirement.
|
||||
initializeOutput(10 * TestValues.size(), 1);
|
||||
initializeInputFromOutput(1);
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
// Write fields.
|
||||
BinaryStreamWriter Writer(*Stream.Output);
|
||||
for (const auto &Value : TestValues)
|
||||
ASSERT_THAT_ERROR(Writer.writeULEB128(Value), Succeeded());
|
||||
|
||||
// Read fields.
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
std::vector<uint64_t> Results;
|
||||
Results.resize(TestValues.size());
|
||||
for (unsigned I = 0; I != TestValues.size(); ++I)
|
||||
ASSERT_THAT_ERROR(Reader.readULEB128(Results[I]), Succeeded());
|
||||
|
||||
for (unsigned I = 0; I != TestValues.size(); ++I)
|
||||
EXPECT_EQ(TestValues[I], Results[I]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderSLEB128) {
|
||||
std::vector<int64_t> TestValues = {
|
||||
0, // Zero
|
||||
0x7F, // One byte
|
||||
-0x7F, // One byte, negative
|
||||
0xFF, // One byte, all-ones
|
||||
0xAAAA, // Two bytes
|
||||
-0xAAAA, // Two bytes, negative
|
||||
0xAAAAAAAA, // Four bytes
|
||||
-0xAAAAAAAA, // Four bytes, negative
|
||||
0x2AAAAAAAAAAAAAAA, // Eight bytes
|
||||
-0x7ffffffffffffff // Eight bytess, negative
|
||||
};
|
||||
|
||||
// Conservatively assume a 10-byte encoding for each of our LEB128s, with no
|
||||
// alignment requirement.
|
||||
initializeOutput(10 * TestValues.size(), 1);
|
||||
initializeInputFromOutput(1);
|
||||
|
||||
for (auto &Stream : Streams) {
|
||||
// Write fields.
|
||||
BinaryStreamWriter Writer(*Stream.Output);
|
||||
for (const auto &Value : TestValues)
|
||||
ASSERT_THAT_ERROR(Writer.writeSLEB128(Value), Succeeded());
|
||||
|
||||
// Read fields.
|
||||
BinaryStreamReader Reader(*Stream.Input);
|
||||
std::vector<int64_t> Results;
|
||||
Results.resize(TestValues.size());
|
||||
for (unsigned I = 0; I != TestValues.size(); ++I)
|
||||
ASSERT_THAT_ERROR(Reader.readSLEB128(Results[I]), Succeeded());
|
||||
|
||||
for (unsigned I = 0; I != TestValues.size(); ++I)
|
||||
EXPECT_EQ(TestValues[I], Results[I]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryStreamTest, StreamReaderObject) {
|
||||
struct Foo {
|
||||
int X;
|
||||
|
|
Loading…
Reference in New Issue