|
@@ -11,6 +11,7 @@
|
|
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
#include "llvm/Support/DataTypes.h"
|
|
|
+#include "llvm/Support/Error.h"
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
@@ -42,6 +43,38 @@ class DataExtractor {
|
|
|
uint8_t IsLittleEndian;
|
|
|
uint8_t AddressSize;
|
|
|
public:
|
|
|
+ /// A class representing a position in a DataExtractor, as well as any error
|
|
|
+ /// encountered during extraction. It enables one to extract a sequence of
|
|
|
+ /// values without error-checking and then checking for errors in bulk at the
|
|
|
+ /// end. The class holds an Error object, so failing to check the result of
|
|
|
+ /// the parse will result in a runtime error. The error flag is sticky and
|
|
|
+ /// will cause all subsequent extraction functions to fail without even
|
|
|
+ /// attempting to parse and without updating the Cursor offset. After clearing
|
|
|
+ /// the error flag, one can again use the Cursor object for parsing.
|
|
|
+ class Cursor {
|
|
|
+ uint64_t Offset;
|
|
|
+ Error Err;
|
|
|
+
|
|
|
+ friend class DataExtractor;
|
|
|
+
|
|
|
+ public:
|
|
|
+ /// Construct a cursor for extraction from the given offset.
|
|
|
+ explicit Cursor(uint64_t Offset) : Offset(Offset), Err(Error::success()) {}
|
|
|
+
|
|
|
+ /// Checks whether the cursor is valid (i.e. no errors were encountered). In
|
|
|
+ /// case of errors, this does not clear the error flag -- one must call
|
|
|
+ /// takeError() instead.
|
|
|
+ explicit operator bool() { return !Err; }
|
|
|
+
|
|
|
+ /// Return the current position of this Cursor. In the error state this is
|
|
|
+ /// the position of the Cursor before the first error was encountered.
|
|
|
+ uint64_t tell() const { return Offset; }
|
|
|
+
|
|
|
+ /// Return error contained inside this Cursor, if any. Clears the internal
|
|
|
+ /// Cursor state.
|
|
|
+ Error takeError() { return std::move(Err); }
|
|
|
+ };
|
|
|
+
|
|
|
/// Construct with a buffer that is owned by the caller.
|
|
|
///
|
|
|
/// This constructor allows us to use data that is owned by the
|
|
@@ -124,10 +157,24 @@ public:
|
|
|
/// @param[in] byte_size
|
|
|
/// The size in byte of the integer to extract.
|
|
|
///
|
|
|
+ /// @param[in,out] Err
|
|
|
+ /// A pointer to an Error object. Upon return the Error object is set to
|
|
|
+ /// indicate the result (success/failure) of the function. If the Error
|
|
|
+ /// object is already set when calling this function, no extraction is
|
|
|
+ /// performed.
|
|
|
+ ///
|
|
|
/// @return
|
|
|
/// The unsigned integer value that was extracted, or zero on
|
|
|
/// failure.
|
|
|
- uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size) const;
|
|
|
+ uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
|
|
|
+ Error *Err = nullptr) const;
|
|
|
+
|
|
|
+ /// Extract an unsigned integer of the given size from the location given by
|
|
|
+ /// the cursor. In case of an extraction error, or if the cursor is already in
|
|
|
+ /// an error state, zero is returned.
|
|
|
+ uint64_t getUnsigned(Cursor &C, uint32_t Size) const {
|
|
|
+ return getUnsigned(&C.Offset, Size, &C.Err);
|
|
|
+ }
|
|
|
|
|
|
/// Extract an signed integer of size \a byte_size from \a *offset_ptr.
|
|
|
///
|
|
@@ -175,6 +222,11 @@ public:
|
|
|
return getUnsigned(offset_ptr, AddressSize);
|
|
|
}
|
|
|
|
|
|
+ /// Extract a pointer-sized unsigned integer from the location given by the
|
|
|
+ /// cursor. In case of an extraction error, or if the cursor is already in
|
|
|
+ /// an error state, zero is returned.
|
|
|
+ uint64_t getAddress(Cursor &C) const { return getUnsigned(C, AddressSize); }
|
|
|
+
|
|
|
/// Extract a uint8_t value from \a *offset_ptr.
|
|
|
///
|
|
|
/// Extract a single uint8_t from the binary data at the offset
|
|
@@ -187,9 +239,20 @@ public:
|
|
|
/// enough bytes to extract this value, the offset will be left
|
|
|
/// unmodified.
|
|
|
///
|
|
|
+ /// @param[in,out] Err
|
|
|
+ /// A pointer to an Error object. Upon return the Error object is set to
|
|
|
+ /// indicate the result (success/failure) of the function. If the Error
|
|
|
+ /// object is already set when calling this function, no extraction is
|
|
|
+ /// performed.
|
|
|
+ ///
|
|
|
/// @return
|
|
|
/// The extracted uint8_t value.
|
|
|
- uint8_t getU8(uint64_t *offset_ptr) const;
|
|
|
+ uint8_t getU8(uint64_t *offset_ptr, Error *Err = nullptr) const;
|
|
|
+
|
|
|
+ /// Extract a single uint8_t value from the location given by the cursor. In
|
|
|
+ /// case of an extraction error, or if the cursor is already in an error
|
|
|
+ /// state, zero is returned.
|
|
|
+ uint8_t getU8(Cursor &C) const { return getU8(&C.Offset, &C.Err); }
|
|
|
|
|
|
/// Extract \a count uint8_t values from \a *offset_ptr.
|
|
|
///
|
|
@@ -216,6 +279,26 @@ public:
|
|
|
/// NULL otherise.
|
|
|
uint8_t *getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const;
|
|
|
|
|
|
+ /// Extract \a Count uint8_t values from the location given by the cursor and
|
|
|
+ /// store them into the destination buffer. In case of an extraction error, or
|
|
|
+ /// if the cursor is already in an error state, a nullptr is returned and the
|
|
|
+ /// destination buffer is left unchanged.
|
|
|
+ uint8_t *getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const;
|
|
|
+
|
|
|
+ /// Extract \a Count uint8_t values from the location given by the cursor and
|
|
|
+ /// store them into the destination vector. The vector is resized to fit the
|
|
|
+ /// extracted data. In case of an extraction error, or if the cursor is
|
|
|
+ /// already in an error state, the destination vector is left unchanged and
|
|
|
+ /// cursor is placed into an error state.
|
|
|
+ void getU8(Cursor &C, SmallVectorImpl<uint8_t> &Dst, uint32_t Count) const {
|
|
|
+ if (isValidOffsetForDataOfSize(C.Offset, Count))
|
|
|
+ Dst.resize(Count);
|
|
|
+
|
|
|
+ // This relies on the fact that getU8 will not attempt to write to the
|
|
|
+ // buffer if isValidOffsetForDataOfSize(C.Offset, Count) is false.
|
|
|
+ getU8(C, Dst.data(), Count);
|
|
|
+ }
|
|
|
+
|
|
|
//------------------------------------------------------------------
|
|
|
/// Extract a uint16_t value from \a *offset_ptr.
|
|
|
///
|
|
@@ -229,10 +312,21 @@ public:
|
|
|
/// enough bytes to extract this value, the offset will be left
|
|
|
/// unmodified.
|
|
|
///
|
|
|
+ /// @param[in,out] Err
|
|
|
+ /// A pointer to an Error object. Upon return the Error object is set to
|
|
|
+ /// indicate the result (success/failure) of the function. If the Error
|
|
|
+ /// object is already set when calling this function, no extraction is
|
|
|
+ /// performed.
|
|
|
+ ///
|
|
|
/// @return
|
|
|
/// The extracted uint16_t value.
|
|
|
//------------------------------------------------------------------
|
|
|
- uint16_t getU16(uint64_t *offset_ptr) const;
|
|
|
+ uint16_t getU16(uint64_t *offset_ptr, Error *Err = nullptr) const;
|
|
|
+
|
|
|
+ /// Extract a single uint16_t value from the location given by the cursor. In
|
|
|
+ /// case of an extraction error, or if the cursor is already in an error
|
|
|
+ /// state, zero is returned.
|
|
|
+ uint16_t getU16(Cursor &C) const { return getU16(&C.Offset, &C.Err); }
|
|
|
|
|
|
/// Extract \a count uint16_t values from \a *offset_ptr.
|
|
|
///
|
|
@@ -288,9 +382,20 @@ public:
|
|
|
/// enough bytes to extract this value, the offset will be left
|
|
|
/// unmodified.
|
|
|
///
|
|
|
+ /// @param[in,out] Err
|
|
|
+ /// A pointer to an Error object. Upon return the Error object is set to
|
|
|
+ /// indicate the result (success/failure) of the function. If the Error
|
|
|
+ /// object is already set when calling this function, no extraction is
|
|
|
+ /// performed.
|
|
|
+ ///
|
|
|
/// @return
|
|
|
/// The extracted uint32_t value.
|
|
|
- uint32_t getU32(uint64_t *offset_ptr) const;
|
|
|
+ uint32_t getU32(uint64_t *offset_ptr, Error *Err = nullptr) const;
|
|
|
+
|
|
|
+ /// Extract a single uint32_t value from the location given by the cursor. In
|
|
|
+ /// case of an extraction error, or if the cursor is already in an error
|
|
|
+ /// state, zero is returned.
|
|
|
+ uint32_t getU32(Cursor &C) const { return getU32(&C.Offset, &C.Err); }
|
|
|
|
|
|
/// Extract \a count uint32_t values from \a *offset_ptr.
|
|
|
///
|
|
@@ -329,9 +434,20 @@ public:
|
|
|
/// enough bytes to extract this value, the offset will be left
|
|
|
/// unmodified.
|
|
|
///
|
|
|
+ /// @param[in,out] Err
|
|
|
+ /// A pointer to an Error object. Upon return the Error object is set to
|
|
|
+ /// indicate the result (success/failure) of the function. If the Error
|
|
|
+ /// object is already set when calling this function, no extraction is
|
|
|
+ /// performed.
|
|
|
+ ///
|
|
|
/// @return
|
|
|
/// The extracted uint64_t value.
|
|
|
- uint64_t getU64(uint64_t *offset_ptr) const;
|
|
|
+ uint64_t getU64(uint64_t *offset_ptr, Error *Err = nullptr) const;
|
|
|
+
|
|
|
+ /// Extract a single uint64_t value from the location given by the cursor. In
|
|
|
+ /// case of an extraction error, or if the cursor is already in an error
|
|
|
+ /// state, zero is returned.
|
|
|
+ uint64_t getU64(Cursor &C) const { return getU64(&C.Offset, &C.Err); }
|
|
|
|
|
|
/// Extract \a count uint64_t values from \a *offset_ptr.
|
|
|
///
|
|
@@ -390,9 +506,30 @@ public:
|
|
|
/// enough bytes to extract this value, the offset will be left
|
|
|
/// unmodified.
|
|
|
///
|
|
|
+ /// @param[in,out] Err
|
|
|
+ /// A pointer to an Error object. Upon return the Error object is set to
|
|
|
+ /// indicate the result (success/failure) of the function. If the Error
|
|
|
+ /// object is already set when calling this function, no extraction is
|
|
|
+ /// performed.
|
|
|
+ ///
|
|
|
/// @return
|
|
|
/// The extracted unsigned integer value.
|
|
|
- uint64_t getULEB128(uint64_t *offset_ptr) const;
|
|
|
+ uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err = nullptr) const;
|
|
|
+
|
|
|
+ /// Extract an unsigned ULEB128 value from the location given by the cursor.
|
|
|
+ /// In case of an extraction error, or if the cursor is already in an error
|
|
|
+ /// state, zero is returned.
|
|
|
+ uint64_t getULEB128(Cursor &C) const { return getULEB128(&C.Offset, &C.Err); }
|
|
|
+
|
|
|
+ /// Advance the Cursor position by the given number of bytes. No-op if the
|
|
|
+ /// cursor is in an error state.
|
|
|
+ void skip(Cursor &C, uint64_t Length) const;
|
|
|
+
|
|
|
+ /// Return true iff the cursor is at the end of the buffer, regardless of the
|
|
|
+ /// error state of the cursor. The only way both eof and error states can be
|
|
|
+ /// true is if one attempts a read while the cursor is at the very end of the
|
|
|
+ /// data buffer.
|
|
|
+ bool eof(const Cursor &C) const { return Data.size() == C.Offset; }
|
|
|
|
|
|
/// Test the validity of \a offset.
|
|
|
///
|
|
@@ -420,6 +557,12 @@ public:
|
|
|
bool isValidOffsetForAddress(uint64_t offset) const {
|
|
|
return isValidOffsetForDataOfSize(offset, AddressSize);
|
|
|
}
|
|
|
+
|
|
|
+protected:
|
|
|
+ // Make it possible for subclasses to access these fields without making them
|
|
|
+ // public.
|
|
|
+ static uint64_t &getOffset(Cursor &C) { return C.Offset; }
|
|
|
+ static Error &getError(Cursor &C) { return C.Err; }
|
|
|
};
|
|
|
|
|
|
} // namespace llvm
|