2011-09-14 03:42:16 +08:00
|
|
|
//===-- DataExtractor.cpp -------------------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-09-14 03:42:16 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Support/DataExtractor.h"
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
#include "llvm/Support/Errc.h"
|
2011-09-14 03:42:16 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/Host.h"
|
2019-06-25 04:43:36 +08:00
|
|
|
#include "llvm/Support/LEB128.h"
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
#include "llvm/Support/SwapByteOrder.h"
|
|
|
|
|
2011-09-14 03:42:16 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2020-02-27 23:22:12 +08:00
|
|
|
static void unexpectedEndReached(Error *E, uint64_t Offset) {
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
if (E)
|
|
|
|
*E = createStringError(errc::illegal_byte_sequence,
|
2020-02-27 23:22:12 +08:00
|
|
|
"unexpected end of data at offset 0x%" PRIx64,
|
|
|
|
Offset);
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool isError(Error *E) { return E && *E; }
|
|
|
|
|
2011-09-14 03:42:16 +08:00
|
|
|
template <typename T>
|
2019-08-06 18:47:20 +08:00
|
|
|
static T getU(uint64_t *offset_ptr, const DataExtractor *de,
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
bool isLittleEndian, const char *Data, llvm::Error *Err) {
|
|
|
|
ErrorAsOutParameter ErrAsOut(Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
T val = 0;
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
if (isError(Err))
|
|
|
|
return val;
|
2011-09-14 03:42:16 +08:00
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
uint64_t offset = *offset_ptr;
|
|
|
|
if (!de->isValidOffsetForDataOfSize(offset, sizeof(T))) {
|
2020-02-27 23:22:12 +08:00
|
|
|
unexpectedEndReached(Err, offset);
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
return val;
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
std::memcpy(&val, &Data[offset], sizeof(val));
|
|
|
|
if (sys::IsLittleEndianHost != isLittleEndian)
|
|
|
|
sys::swapByteOrder(val);
|
|
|
|
|
|
|
|
// Advance the offset
|
|
|
|
*offset_ptr += sizeof(val);
|
2011-09-14 03:42:16 +08:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2019-08-06 18:47:20 +08:00
|
|
|
static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
const DataExtractor *de, bool isLittleEndian, const char *Data,
|
|
|
|
llvm::Error *Err) {
|
|
|
|
ErrorAsOutParameter ErrAsOut(Err);
|
|
|
|
if (isError(Err))
|
|
|
|
return nullptr;
|
|
|
|
|
2019-08-06 18:47:20 +08:00
|
|
|
uint64_t offset = *offset_ptr;
|
2011-09-14 03:42:16 +08:00
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
if (!de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) {
|
2020-02-27 23:22:12 +08:00
|
|
|
unexpectedEndReached(Err, offset);
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
return nullptr;
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
|
|
|
|
++value_ptr, offset += sizeof(*dst))
|
|
|
|
*value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data, Err);
|
|
|
|
// Advance the offset
|
|
|
|
*offset_ptr = offset;
|
|
|
|
// Return a non-NULL pointer to the converted data as an indicator of
|
|
|
|
// success
|
|
|
|
return dst;
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
|
|
|
|
return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *
|
2019-08-06 18:47:20 +08:00
|
|
|
DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const {
|
2011-09-14 03:42:16 +08:00
|
|
|
return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian,
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
Data.data(), nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
|
|
|
|
return getUs<uint8_t>(&C.Offset, Dst, Count, this, IsLittleEndian,
|
|
|
|
Data.data(), &C.Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
|
|
|
|
return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2019-08-06 18:47:20 +08:00
|
|
|
uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,
|
2011-09-14 03:42:16 +08:00
|
|
|
uint32_t count) const {
|
|
|
|
return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian,
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
Data.data(), nullptr);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2020-03-25 00:49:55 +08:00
|
|
|
uint32_t DataExtractor::getU24(uint64_t *OffsetPtr, Error *Err) const {
|
2017-06-22 03:37:44 +08:00
|
|
|
uint24_t ExtractedVal =
|
2020-03-25 00:49:55 +08:00
|
|
|
getU<uint24_t>(OffsetPtr, this, IsLittleEndian, Data.data(), Err);
|
2017-06-22 03:37:44 +08:00
|
|
|
// The 3 bytes are in the correct byte order for the host.
|
|
|
|
return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
|
|
|
|
}
|
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
|
|
|
|
return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2019-08-06 18:47:20 +08:00
|
|
|
uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,
|
2011-09-14 03:42:16 +08:00
|
|
|
uint32_t count) const {
|
|
|
|
return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian,
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
Data.data(), nullptr);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
|
|
|
|
return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2019-08-06 18:47:20 +08:00
|
|
|
uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,
|
2011-09-14 03:42:16 +08:00
|
|
|
uint32_t count) const {
|
|
|
|
return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian,
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
Data.data(), nullptr);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
|
|
|
|
llvm::Error *Err) const {
|
2011-09-14 03:42:16 +08:00
|
|
|
switch (byte_size) {
|
|
|
|
case 1:
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
return getU8(offset_ptr, Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
case 2:
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
return getU16(offset_ptr, Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
case 4:
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
return getU32(offset_ptr, Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
case 8:
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
return getU64(offset_ptr, Err);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("getUnsigned unhandled case!");
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t
|
2019-08-06 18:47:20 +08:00
|
|
|
DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
|
2011-09-14 03:42:16 +08:00
|
|
|
switch (byte_size) {
|
|
|
|
case 1:
|
|
|
|
return (int8_t)getU8(offset_ptr);
|
|
|
|
case 2:
|
|
|
|
return (int16_t)getU16(offset_ptr);
|
|
|
|
case 4:
|
|
|
|
return (int32_t)getU32(offset_ptr);
|
|
|
|
case 8:
|
|
|
|
return (int64_t)getU64(offset_ptr);
|
|
|
|
}
|
|
|
|
llvm_unreachable("getSigned unhandled case!");
|
|
|
|
}
|
|
|
|
|
2020-03-23 23:15:49 +08:00
|
|
|
StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const {
|
|
|
|
ErrorAsOutParameter ErrAsOut(Err);
|
|
|
|
if (isError(Err))
|
|
|
|
return StringRef();
|
2011-09-14 03:42:16 +08:00
|
|
|
|
2020-03-23 23:15:49 +08:00
|
|
|
uint64_t Start = *OffsetPtr;
|
2017-05-03 01:37:32 +08:00
|
|
|
StringRef::size_type Pos = Data.find('\0', Start);
|
|
|
|
if (Pos != StringRef::npos) {
|
2020-03-23 23:15:49 +08:00
|
|
|
*OffsetPtr = Pos + 1;
|
2017-05-03 01:37:32 +08:00
|
|
|
return StringRef(Data.data() + Start, Pos - Start);
|
|
|
|
}
|
2020-03-23 23:15:49 +08:00
|
|
|
unexpectedEndReached(Err, Start);
|
2017-05-03 01:37:32 +08:00
|
|
|
return StringRef();
|
|
|
|
}
|
|
|
|
|
2020-02-22 07:21:07 +08:00
|
|
|
StringRef DataExtractor::getFixedLengthString(uint64_t *OffsetPtr,
|
|
|
|
uint64_t Length,
|
|
|
|
StringRef TrimChars) const {
|
|
|
|
StringRef Bytes(getBytes(OffsetPtr, Length));
|
|
|
|
return Bytes.trim(TrimChars);
|
|
|
|
}
|
|
|
|
|
2020-03-25 00:49:55 +08:00
|
|
|
StringRef DataExtractor::getBytes(uint64_t *OffsetPtr, uint64_t Length,
|
|
|
|
Error *Err) const {
|
|
|
|
ErrorAsOutParameter ErrAsOut(Err);
|
|
|
|
if (isError(Err))
|
|
|
|
return StringRef();
|
|
|
|
|
|
|
|
if (!isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
|
|
|
|
unexpectedEndReached(Err, *OffsetPtr);
|
2020-02-22 07:21:07 +08:00
|
|
|
return StringRef();
|
2020-03-25 00:49:55 +08:00
|
|
|
}
|
|
|
|
|
2020-02-22 07:21:07 +08:00
|
|
|
StringRef Result = Data.substr(*OffsetPtr, Length);
|
|
|
|
*OffsetPtr += Length;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2020-03-25 00:49:55 +08:00
|
|
|
template <typename T>
|
|
|
|
static T getLEB128(StringRef Data, uint64_t *OffsetPtr, Error *Err,
|
|
|
|
T (&Decoder)(const uint8_t *p, unsigned *n,
|
|
|
|
const uint8_t *end, const char **error)) {
|
|
|
|
ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(Data);
|
|
|
|
assert(*OffsetPtr <= Bytes.size());
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
ErrorAsOutParameter ErrAsOut(Err);
|
|
|
|
if (isError(Err))
|
2020-03-25 00:49:55 +08:00
|
|
|
return T();
|
2019-06-25 04:43:36 +08:00
|
|
|
|
|
|
|
const char *error;
|
|
|
|
unsigned bytes_read;
|
2020-03-25 00:49:55 +08:00
|
|
|
T result =
|
|
|
|
Decoder(Bytes.data() + *OffsetPtr, &bytes_read, Bytes.end(), &error);
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
if (error) {
|
|
|
|
if (Err)
|
|
|
|
*Err = createStringError(errc::illegal_byte_sequence, error);
|
2020-03-25 00:49:55 +08:00
|
|
|
return T();
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
}
|
2020-03-25 00:49:55 +08:00
|
|
|
*OffsetPtr += bytes_read;
|
2019-06-25 04:43:36 +08:00
|
|
|
return result;
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
|
|
|
|
2020-03-25 00:49:55 +08:00
|
|
|
uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const {
|
|
|
|
return getLEB128(Data, offset_ptr, Err, decodeULEB128);
|
|
|
|
}
|
2011-09-14 03:42:16 +08:00
|
|
|
|
2020-03-25 00:49:55 +08:00
|
|
|
int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const {
|
|
|
|
return getLEB128(Data, offset_ptr, Err, decodeSLEB128);
|
2011-09-14 03:42:16 +08:00
|
|
|
}
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
|
|
|
|
void DataExtractor::skip(Cursor &C, uint64_t Length) const {
|
|
|
|
ErrorAsOutParameter ErrAsOut(&C.Err);
|
|
|
|
if (isError(&C.Err))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (isValidOffsetForDataOfSize(C.Offset, Length))
|
|
|
|
C.Offset += Length;
|
|
|
|
else
|
2020-02-27 23:22:12 +08:00
|
|
|
unexpectedEndReached(&C.Err, C.Offset);
|
Add error handling to the DataExtractor class
Summary:
This is motivated by D63591, where we realized that there isn't a really
good way of telling whether a DataExtractor is reading actual data, or
is it just returning default values because it reached the end of the
buffer.
This patch resolves that by providing a new "Cursor" class. A Cursor
object encapsulates two things:
- the current position/offset in the DataExtractor
- an error object
Storing the error object inside the Cursor enables one to use the same
pattern as the std::{io}stream API, where one can blindly perform a
sequence of reads and only check for errors once at the end of the
operation. Similarly to the stream API, as soon as we encounter one
error, all of the subsequent operations are skipped (return default
values) too, even if the would suceed with clear error state. Unlike the
std::stream API (but in line with other llvm APIs), we force the error
state to be checked through usage of llvm::Error.
Reviewers: probinson, dblaikie, JDevlieghere, aprantl, echristo
Subscribers: kristina, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63713
llvm-svn: 370042
2019-08-27 19:24:08 +08:00
|
|
|
}
|