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 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Support/DataExtractor.h"
10 #include "llvm/Support/Errc.h"
11 #include "llvm/Support/ErrorHandling.h"
12 #include "llvm/Support/Host.h"
13 #include "llvm/Support/LEB128.h"
14 #include "llvm/Support/SwapByteOrder.h"
15
16 using namespace llvm;
17
prepareRead(uint64_t Offset,uint64_t Size,Error * E) const18 bool DataExtractor::prepareRead(uint64_t Offset, uint64_t Size,
19 Error *E) const {
20 if (isValidOffsetForDataOfSize(Offset, Size))
21 return true;
22 if (E) {
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
27 ", 0x%" PRIx64 ")",
28 Data.size(), Offset, Offset + Size);
29 else
30 *E = createStringError(errc::invalid_argument,
31 "offset 0x%" PRIx64
32 " is beyond the end of data at 0x%zx",
33 Offset, Data.size());
34 }
35 return false;
36 }
37
isError(Error * E)38 static bool isError(Error *E) { return E && *E; }
39
40 template <typename T>
getU(uint64_t * offset_ptr,Error * Err) const41 T DataExtractor::getU(uint64_t *offset_ptr, Error *Err) const {
42 ErrorAsOutParameter ErrAsOut(Err);
43 T val = 0;
44 if (isError(Err))
45 return val;
46
47 uint64_t offset = *offset_ptr;
48 if (!prepareRead(offset, sizeof(T), Err))
49 return val;
50 std::memcpy(&val, &Data.data()[offset], sizeof(val));
51 if (sys::IsLittleEndianHost != IsLittleEndian)
52 sys::swapByteOrder(val);
53
54 // Advance the offset
55 *offset_ptr += sizeof(val);
56 return val;
57 }
58
59 template <typename T>
getUs(uint64_t * offset_ptr,T * dst,uint32_t count,Error * Err) const60 T *DataExtractor::getUs(uint64_t *offset_ptr, T *dst, uint32_t count,
61 Error *Err) const {
62 ErrorAsOutParameter ErrAsOut(Err);
63 if (isError(Err))
64 return nullptr;
65
66 uint64_t offset = *offset_ptr;
67
68 if (!prepareRead(offset, sizeof(*dst) * count, Err))
69 return nullptr;
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);
73 // Advance the offset
74 *offset_ptr = offset;
75 // Return a non-NULL pointer to the converted data as an indicator of
76 // success
77 return dst;
78 }
79
getU8(uint64_t * offset_ptr,llvm::Error * Err) const80 uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {
81 return getU<uint8_t>(offset_ptr, Err);
82 }
83
getU8(uint64_t * offset_ptr,uint8_t * dst,uint32_t count) const84 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);
87 }
88
getU8(Cursor & C,uint8_t * Dst,uint32_t Count) const89 uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {
90 return getUs<uint8_t>(&C.Offset, Dst, Count, &C.Err);
91 }
92
getU16(uint64_t * offset_ptr,llvm::Error * Err) const93 uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {
94 return getU<uint16_t>(offset_ptr, Err);
95 }
96
getU16(uint64_t * offset_ptr,uint16_t * dst,uint32_t count) const97 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);
100 }
101
getU24(uint64_t * OffsetPtr,Error * Err) const102 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);
106 }
107
getU32(uint64_t * offset_ptr,llvm::Error * Err) const108 uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {
109 return getU<uint32_t>(offset_ptr, Err);
110 }
111
getU32(uint64_t * offset_ptr,uint32_t * dst,uint32_t count) const112 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);
115 }
116
getU64(uint64_t * offset_ptr,llvm::Error * Err) const117 uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {
118 return getU<uint64_t>(offset_ptr, Err);
119 }
120
getU64(uint64_t * offset_ptr,uint64_t * dst,uint32_t count) const121 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);
124 }
125
getUnsigned(uint64_t * offset_ptr,uint32_t byte_size,llvm::Error * Err) const126 uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
127 llvm::Error *Err) const {
128 switch (byte_size) {
129 case 1:
130 return getU8(offset_ptr, Err);
131 case 2:
132 return getU16(offset_ptr, Err);
133 case 4:
134 return getU32(offset_ptr, Err);
135 case 8:
136 return getU64(offset_ptr, Err);
137 }
138 llvm_unreachable("getUnsigned unhandled case!");
139 }
140
141 int64_t
getSigned(uint64_t * offset_ptr,uint32_t byte_size) const142 DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {
143 switch (byte_size) {
144 case 1:
145 return (int8_t)getU8(offset_ptr);
146 case 2:
147 return (int16_t)getU16(offset_ptr);
148 case 4:
149 return (int32_t)getU32(offset_ptr);
150 case 8:
151 return (int64_t)getU64(offset_ptr);
152 }
153 llvm_unreachable("getSigned unhandled case!");
154 }
155
getCStrRef(uint64_t * OffsetPtr,Error * Err) const156 StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const {
157 ErrorAsOutParameter ErrAsOut(Err);
158 if (isError(Err))
159 return StringRef();
160
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);
166 }
167 if (Err)
168 *Err = createStringError(errc::illegal_byte_sequence,
169 "no null terminated string at offset 0x%" PRIx64,
170 Start);
171 return StringRef();
172 }
173
getFixedLengthString(uint64_t * OffsetPtr,uint64_t Length,StringRef TrimChars) const174 StringRef DataExtractor::getFixedLengthString(uint64_t *OffsetPtr,
175 uint64_t Length,
176 StringRef TrimChars) const {
177 StringRef Bytes(getBytes(OffsetPtr, Length));
178 return Bytes.trim(TrimChars);
179 }
180
getBytes(uint64_t * OffsetPtr,uint64_t Length,Error * Err) const181 StringRef DataExtractor::getBytes(uint64_t *OffsetPtr, uint64_t Length,
182 Error *Err) const {
183 ErrorAsOutParameter ErrAsOut(Err);
184 if (isError(Err))
185 return StringRef();
186
187 if (!prepareRead(*OffsetPtr, Length, Err))
188 return StringRef();
189
190 StringRef Result = Data.substr(*OffsetPtr, Length);
191 *OffsetPtr += Length;
192 return Result;
193 }
194
195 template <typename T>
getLEB128(StringRef Data,uint64_t * OffsetPtr,Error * Err,T (& Decoder)(const uint8_t * p,unsigned * n,const uint8_t * end,const char ** error))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);
202 if (isError(Err))
203 return T();
204
205 const char *error;
206 unsigned bytes_read;
207 T result =
208 Decoder(Bytes.data() + *OffsetPtr, &bytes_read, Bytes.end(), &error);
209 if (error) {
210 if (Err)
211 *Err = createStringError(errc::illegal_byte_sequence,
212 "unable to decode LEB128 at offset 0x%8.8" PRIx64
213 ": %s",
214 *OffsetPtr, error);
215 return T();
216 }
217 *OffsetPtr += bytes_read;
218 return result;
219 }
220
getULEB128(uint64_t * offset_ptr,Error * Err) const221 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const {
222 return getLEB128(Data, offset_ptr, Err, decodeULEB128);
223 }
224
getSLEB128(uint64_t * offset_ptr,Error * Err) const225 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const {
226 return getLEB128(Data, offset_ptr, Err, decodeSLEB128);
227 }
228
skip(Cursor & C,uint64_t Length) const229 void DataExtractor::skip(Cursor &C, uint64_t Length) const {
230 ErrorAsOutParameter ErrAsOut(&C.Err);
231 if (isError(&C.Err))
232 return;
233
234 if (prepareRead(C.Offset, Length, &C.Err))
235 C.Offset += Length;
236 }
237