[WebAssembly] Add new target feature in support of 'extended-const' proposal
[llvm-project.git] / llvm / lib / Support / DataExtractor.cpp
blob8cf312191153962ca6491a7ebd2e2e8b3b01969f
1 //===-- DataExtractor.cpp -------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Support/DataExtractor.h"
10 #include "llvm/Support/Errc.h"
11 #include "llvm/Support/ErrorHandling.h"
12 #include "llvm/Support/LEB128.h"
13 #include "llvm/Support/SwapByteOrder.h"
15 using namespace llvm;
17 bool DataExtractor::prepareRead(uint64_t Offset, uint64_t Size,
18 Error *E) const {
19 if (isValidOffsetForDataOfSize(Offset, Size))
20 return true;
21 if (E) {
22 if (Offset <= Data.size())
23 *E = createStringError(
24 errc::illegal_byte_sequence,
25 "unexpected end of data at offset 0x%zx while reading [0x%" PRIx64
26 ", 0x%" PRIx64 ")",
27 Data.size(), Offset, Offset + Size);
28 else
29 *E = createStringError(errc::invalid_argument,
30 "offset 0x%" PRIx64
31 " is beyond the end of data at 0x%zx",
32 Offset, Data.size());
34 return false;
37 static bool isError(Error *E) { return E && *E; }
39 template <typename T>
40 T DataExtractor::getU(uint64_t *offset_ptr, Error *Err) const {
41 ErrorAsOutParameter ErrAsOut(Err);
42 T val = 0;
43 if (isError(Err))
44 return val;
46 uint64_t offset = *offset_ptr;
47 if (!prepareRead(offset, sizeof(T), Err))
48 return val;
49 std::memcpy(&val, &Data.data()[offset], sizeof(val));
50 if (sys::IsLittleEndianHost != IsLittleEndian)
51 sys::swapByteOrder(val);
53 // Advance the offset
54 *offset_ptr += sizeof(val);
55 return val;
58 template <typename T>
59 T *DataExtractor::getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
60 Error *Err) const {
61 ErrorAsOutParameter ErrAsOut(Err);
62 if (isError(Err))
63 return nullptr;
65 uint64_t offset = *offset_ptr;
67 if (!prepareRead(offset, sizeof(*dst) * count, Err))
68 return nullptr;
69 for (T *value_ptr = dst, *end = dst + count; value_ptr != end;
70 ++value_ptr, offset += sizeof(*dst))
71 *value_ptr = getU<T>(offset_ptr, Err);
72 // Advance the offset
73 *offset_ptr = offset;
74 // Return a non-NULL pointer to the converted data as an indicator of
75 // success
76 return dst;
79 uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
80 return getU<uint8_t>(offset_ptr, Err);
83 uint8_t *DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst,
84 uint32_t count) const {
85 return getUs<uint8_t>(offset_ptr, dst, count, nullptr);
88 uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
89 return getUs<uint8_t>(&C.Offset, Dst, Count, &C.Err);
92 uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
93 return getU<uint16_t>(offset_ptr, Err);
96 uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,
97 uint32_t count) const {
98 return getUs<uint16_t>(offset_ptr, dst, count, nullptr);
101 uint32_t DataExtractor::getU24(uint64_t *OffsetPtr, Error *Err) const {
102 uint24_t ExtractedVal = getU<uint24_t>(OffsetPtr, Err);
103 // The 3 bytes are in the correct byte order for the host.
104 return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);
107 uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
108 return getU<uint32_t>(offset_ptr, Err);
111 uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,
112 uint32_t count) const {
113 return getUs<uint32_t>(offset_ptr, dst, count, nullptr);
116 uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
117 return getU<uint64_t>(offset_ptr, Err);
120 uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,
121 uint32_t count) const {
122 return getUs<uint64_t>(offset_ptr, dst, count, nullptr);
125 uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
126 llvm::Error *Err) const {
127 switch (byte_size) {
128 case 1:
129 return getU8(offset_ptr, Err);
130 case 2:
131 return getU16(offset_ptr, Err);
132 case 4:
133 return getU32(offset_ptr, Err);
134 case 8:
135 return getU64(offset_ptr, Err);
137 llvm_unreachable("getUnsigned unhandled case!");
140 int64_t
141 DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
142 switch (byte_size) {
143 case 1:
144 return (int8_t)getU8(offset_ptr);
145 case 2:
146 return (int16_t)getU16(offset_ptr);
147 case 4:
148 return (int32_t)getU32(offset_ptr);
149 case 8:
150 return (int64_t)getU64(offset_ptr);
152 llvm_unreachable("getSigned unhandled case!");
155 StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const {
156 ErrorAsOutParameter ErrAsOut(Err);
157 if (isError(Err))
158 return StringRef();
160 uint64_t Start = *OffsetPtr;
161 StringRef::size_type Pos = Data.find('\0', Start);
162 if (Pos != StringRef::npos) {
163 *OffsetPtr = Pos + 1;
164 return StringRef(Data.data() + Start, Pos - Start);
166 if (Err)
167 *Err = createStringError(errc::illegal_byte_sequence,
168 "no null terminated string at offset 0x%" PRIx64,
169 Start);
170 return StringRef();
173 StringRef DataExtractor::getFixedLengthString(uint64_t *OffsetPtr,
174 uint64_t Length,
175 StringRef TrimChars) const {
176 StringRef Bytes(getBytes(OffsetPtr, Length));
177 return Bytes.trim(TrimChars);
180 StringRef DataExtractor::getBytes(uint64_t *OffsetPtr, uint64_t Length,
181 Error *Err) const {
182 ErrorAsOutParameter ErrAsOut(Err);
183 if (isError(Err))
184 return StringRef();
186 if (!prepareRead(*OffsetPtr, Length, Err))
187 return StringRef();
189 StringRef Result = Data.substr(*OffsetPtr, Length);
190 *OffsetPtr += Length;
191 return Result;
194 template <typename T>
195 static T getLEB128(StringRef Data, uint64_t *OffsetPtr, Error *Err,
196 T (&Decoder)(const uint8_t *p, unsigned *n,
197 const uint8_t *end, const char **error)) {
198 ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(Data);
199 assert(*OffsetPtr <= Bytes.size());
200 ErrorAsOutParameter ErrAsOut(Err);
201 if (isError(Err))
202 return T();
204 const char *error;
205 unsigned bytes_read;
206 T result =
207 Decoder(Bytes.data() + *OffsetPtr, &bytes_read, Bytes.end(), &error);
208 if (error) {
209 if (Err)
210 *Err = createStringError(errc::illegal_byte_sequence,
211 "unable to decode LEB128 at offset 0x%8.8" PRIx64
212 ": %s",
213 *OffsetPtr, error);
214 return T();
216 *OffsetPtr += bytes_read;
217 return result;
220 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const {
221 return getLEB128(Data, offset_ptr, Err, decodeULEB128);
224 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const {
225 return getLEB128(Data, offset_ptr, Err, decodeSLEB128);
228 void DataExtractor::skip(Cursor &C, uint64_t Length) const {
229 ErrorAsOutParameter ErrAsOut(&C.Err);
230 if (isError(&C.Err))
231 return;
233 if (prepareRead(C.Offset, Length, &C.Err))
234 C.Offset += Length;