1 //===-- DataExtractor.cpp -------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/DataExtractor.h"
10 #include "llvm/ADT/StringExtras.h"
11 #include "llvm/Support/Errc.h"
12 #include "llvm/Support/ErrorHandling.h"
13 #include "llvm/Support/LEB128.h"
14 #include "llvm/Support/SwapByteOrder.h"
18 bool DataExtractor::prepareRead(uint64_t Offset
, uint64_t Size
,
20 if (isValidOffsetForDataOfSize(Offset
, Size
))
23 if (Offset
<= Data
.size())
24 *E
= createStringError(
25 errc::illegal_byte_sequence
,
26 "unexpected end of data at offset 0x%zx while reading [0x%" PRIx64
28 Data
.size(), Offset
, Offset
+ Size
);
30 *E
= createStringError(errc::invalid_argument
,
32 " is beyond the end of data at 0x%zx",
38 static bool isError(Error
*E
) { return E
&& *E
; }
41 T
DataExtractor::getU(uint64_t *offset_ptr
, Error
*Err
) const {
42 ErrorAsOutParameter
ErrAsOut(Err
);
47 uint64_t offset
= *offset_ptr
;
48 if (!prepareRead(offset
, sizeof(T
), Err
))
50 std::memcpy(&val
, &Data
.data()[offset
], sizeof(val
));
51 if (sys::IsLittleEndianHost
!= IsLittleEndian
)
52 sys::swapByteOrder(val
);
55 *offset_ptr
+= sizeof(val
);
60 T
*DataExtractor::getUs(uint64_t *offset_ptr
, T
*dst
, uint32_t count
,
62 ErrorAsOutParameter
ErrAsOut(Err
);
66 uint64_t offset
= *offset_ptr
;
68 if (!prepareRead(offset
, sizeof(*dst
) * count
, Err
))
70 for (T
*value_ptr
= dst
, *end
= dst
+ count
; value_ptr
!= end
;
71 ++value_ptr
, offset
+= sizeof(*dst
))
72 *value_ptr
= getU
<T
>(offset_ptr
, Err
);
75 // Return a non-NULL pointer to the converted data as an indicator of
80 uint8_t DataExtractor::getU8(uint64_t *offset_ptr
, llvm::Error
*Err
) const {
81 return getU
<uint8_t>(offset_ptr
, Err
);
84 uint8_t *DataExtractor::getU8(uint64_t *offset_ptr
, uint8_t *dst
,
85 uint32_t count
) const {
86 return getUs
<uint8_t>(offset_ptr
, dst
, count
, nullptr);
89 uint8_t *DataExtractor::getU8(Cursor
&C
, uint8_t *Dst
, uint32_t Count
) const {
90 return getUs
<uint8_t>(&C
.Offset
, Dst
, Count
, &C
.Err
);
93 uint16_t DataExtractor::getU16(uint64_t *offset_ptr
, llvm::Error
*Err
) const {
94 return getU
<uint16_t>(offset_ptr
, Err
);
97 uint16_t *DataExtractor::getU16(uint64_t *offset_ptr
, uint16_t *dst
,
98 uint32_t count
) const {
99 return getUs
<uint16_t>(offset_ptr
, dst
, count
, nullptr);
102 uint32_t DataExtractor::getU24(uint64_t *OffsetPtr
, Error
*Err
) const {
103 uint24_t ExtractedVal
= getU
<uint24_t
>(OffsetPtr
, Err
);
104 // The 3 bytes are in the correct byte order for the host.
105 return ExtractedVal
.getAsUint32(sys::IsLittleEndianHost
);
108 uint32_t DataExtractor::getU32(uint64_t *offset_ptr
, llvm::Error
*Err
) const {
109 return getU
<uint32_t>(offset_ptr
, Err
);
112 uint32_t *DataExtractor::getU32(uint64_t *offset_ptr
, uint32_t *dst
,
113 uint32_t count
) const {
114 return getUs
<uint32_t>(offset_ptr
, dst
, count
, nullptr);
117 uint64_t DataExtractor::getU64(uint64_t *offset_ptr
, llvm::Error
*Err
) const {
118 return getU
<uint64_t>(offset_ptr
, Err
);
121 uint64_t *DataExtractor::getU64(uint64_t *offset_ptr
, uint64_t *dst
,
122 uint32_t count
) const {
123 return getUs
<uint64_t>(offset_ptr
, dst
, count
, nullptr);
126 uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr
, uint32_t byte_size
,
127 llvm::Error
*Err
) const {
130 return getU8(offset_ptr
, Err
);
132 return getU16(offset_ptr
, Err
);
134 return getU32(offset_ptr
, Err
);
136 return getU64(offset_ptr
, Err
);
138 llvm_unreachable("getUnsigned unhandled case!");
142 DataExtractor::getSigned(uint64_t *offset_ptr
, uint32_t byte_size
) const {
145 return (int8_t)getU8(offset_ptr
);
147 return (int16_t)getU16(offset_ptr
);
149 return (int32_t)getU32(offset_ptr
);
151 return (int64_t)getU64(offset_ptr
);
153 llvm_unreachable("getSigned unhandled case!");
156 StringRef
DataExtractor::getCStrRef(uint64_t *OffsetPtr
, Error
*Err
) const {
157 ErrorAsOutParameter
ErrAsOut(Err
);
161 uint64_t Start
= *OffsetPtr
;
162 StringRef::size_type Pos
= Data
.find('\0', Start
);
163 if (Pos
!= StringRef::npos
) {
164 *OffsetPtr
= Pos
+ 1;
165 return StringRef(Data
.data() + Start
, Pos
- Start
);
168 *Err
= createStringError(errc::illegal_byte_sequence
,
169 "no null terminated string at offset 0x%" PRIx64
,
174 StringRef
DataExtractor::getFixedLengthString(uint64_t *OffsetPtr
,
176 StringRef TrimChars
) const {
177 StringRef
Bytes(getBytes(OffsetPtr
, Length
));
178 return Bytes
.trim(TrimChars
);
181 StringRef
DataExtractor::getBytes(uint64_t *OffsetPtr
, uint64_t Length
,
183 ErrorAsOutParameter
ErrAsOut(Err
);
187 if (!prepareRead(*OffsetPtr
, Length
, Err
))
190 StringRef Result
= Data
.substr(*OffsetPtr
, Length
);
191 *OffsetPtr
+= Length
;
195 template <typename T
>
196 static T
getLEB128(StringRef Data
, uint64_t *OffsetPtr
, Error
*Err
,
197 T (&Decoder
)(const uint8_t *p
, unsigned *n
,
198 const uint8_t *end
, const char **error
)) {
199 ArrayRef
<uint8_t> Bytes
= arrayRefFromStringRef(Data
);
200 assert(*OffsetPtr
<= Bytes
.size());
201 ErrorAsOutParameter
ErrAsOut(Err
);
205 const char *error
= nullptr;
208 Decoder(Bytes
.data() + *OffsetPtr
, &bytes_read
, Bytes
.end(), &error
);
211 *Err
= createStringError(errc::illegal_byte_sequence
,
212 "unable to decode LEB128 at offset 0x%8.8" PRIx64
217 *OffsetPtr
+= bytes_read
;
221 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr
, Error
*Err
) const {
222 return getLEB128(Data
, offset_ptr
, Err
, decodeULEB128
);
225 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr
, Error
*Err
) const {
226 return getLEB128(Data
, offset_ptr
, Err
, decodeSLEB128
);
229 void DataExtractor::skip(Cursor
&C
, uint64_t Length
) const {
230 ErrorAsOutParameter
ErrAsOut(C
.Err
);
234 if (prepareRead(C
.Offset
, Length
, &C
.Err
))