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/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" |
15 | |
16 | using namespace llvm; |
17 | |
18 | bool DataExtractor::(uint64_t Offset, uint64_t Size, |
19 | Error *E) const { |
20 | if (isValidOffsetForDataOfSize(offset: Offset, length: Size)) |
21 | return true; |
22 | if (E) { |
23 | if (Offset <= Data.size()) |
24 | *E = createStringError( |
25 | EC: errc::illegal_byte_sequence, |
26 | Fmt: "unexpected end of data at offset 0x%zx while reading [0x%" PRIx64 |
27 | ", 0x%" PRIx64 ")" , |
28 | Vals: Data.size(), Vals: Offset, Vals: Offset + Size); |
29 | else |
30 | *E = createStringError(EC: errc::invalid_argument, |
31 | Fmt: "offset 0x%" PRIx64 |
32 | " is beyond the end of data at 0x%zx" , |
33 | Vals: Offset, Vals: Data.size()); |
34 | } |
35 | return false; |
36 | } |
37 | |
38 | static bool isError(Error *E) { return E && *E; } |
39 | |
40 | template <typename T> |
41 | T DataExtractor::(uint64_t *offset_ptr, Error *Err) const { |
42 | ErrorAsOutParameter ErrAsOut(Err); |
43 | T val = 0; |
44 | if (isError(E: Err)) |
45 | return val; |
46 | |
47 | uint64_t offset = *offset_ptr; |
48 | if (!prepareRead(Offset: offset, Size: sizeof(T), E: Err)) |
49 | return val; |
50 | std::memcpy(dest: &val, src: &Data.data()[offset], n: 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> |
60 | T *DataExtractor::(uint64_t *offset_ptr, T *dst, uint32_t count, |
61 | Error *Err) const { |
62 | ErrorAsOutParameter ErrAsOut(Err); |
63 | if (isError(E: Err)) |
64 | return nullptr; |
65 | |
66 | uint64_t offset = *offset_ptr; |
67 | |
68 | if (!prepareRead(Offset: offset, Size: sizeof(*dst) * count, E: 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 | |
80 | uint8_t DataExtractor::(uint64_t *offset_ptr, llvm::Error *Err) const { |
81 | return getU<uint8_t>(offset_ptr, Err); |
82 | } |
83 | |
84 | uint8_t *DataExtractor::(uint64_t *offset_ptr, uint8_t *dst, |
85 | uint32_t count) const { |
86 | return getUs<uint8_t>(offset_ptr, dst, count, Err: nullptr); |
87 | } |
88 | |
89 | uint8_t *DataExtractor::(Cursor &C, uint8_t *Dst, uint32_t Count) const { |
90 | return getUs<uint8_t>(offset_ptr: &C.Offset, dst: Dst, count: Count, Err: &C.Err); |
91 | } |
92 | |
93 | uint16_t DataExtractor::(uint64_t *offset_ptr, llvm::Error *Err) const { |
94 | return getU<uint16_t>(offset_ptr, Err); |
95 | } |
96 | |
97 | uint16_t *DataExtractor::(uint64_t *offset_ptr, uint16_t *dst, |
98 | uint32_t count) const { |
99 | return getUs<uint16_t>(offset_ptr, dst, count, Err: nullptr); |
100 | } |
101 | |
102 | uint32_t DataExtractor::(uint64_t *OffsetPtr, Error *Err) const { |
103 | uint24_t = getU<uint24_t>(offset_ptr: OffsetPtr, Err); |
104 | // The 3 bytes are in the correct byte order for the host. |
105 | return ExtractedVal.getAsUint32(IsLittleEndian: sys::IsLittleEndianHost); |
106 | } |
107 | |
108 | uint32_t DataExtractor::(uint64_t *offset_ptr, llvm::Error *Err) const { |
109 | return getU<uint32_t>(offset_ptr, Err); |
110 | } |
111 | |
112 | uint32_t *DataExtractor::(uint64_t *offset_ptr, uint32_t *dst, |
113 | uint32_t count) const { |
114 | return getUs<uint32_t>(offset_ptr, dst, count, Err: nullptr); |
115 | } |
116 | |
117 | uint64_t DataExtractor::(uint64_t *offset_ptr, llvm::Error *Err) const { |
118 | return getU<uint64_t>(offset_ptr, Err); |
119 | } |
120 | |
121 | uint64_t *DataExtractor::(uint64_t *offset_ptr, uint64_t *dst, |
122 | uint32_t count) const { |
123 | return getUs<uint64_t>(offset_ptr, dst, count, Err: nullptr); |
124 | } |
125 | |
126 | uint64_t DataExtractor::(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 |
142 | DataExtractor::(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 | |
156 | StringRef DataExtractor::(uint64_t *OffsetPtr, Error *Err) const { |
157 | ErrorAsOutParameter ErrAsOut(Err); |
158 | if (isError(E: Err)) |
159 | return StringRef(); |
160 | |
161 | uint64_t Start = *OffsetPtr; |
162 | StringRef::size_type Pos = Data.find(C: '\0', From: 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(EC: errc::illegal_byte_sequence, |
169 | Fmt: "no null terminated string at offset 0x%" PRIx64, |
170 | Vals: Start); |
171 | return StringRef(); |
172 | } |
173 | |
174 | StringRef DataExtractor::(uint64_t *OffsetPtr, |
175 | uint64_t Length, |
176 | StringRef TrimChars) const { |
177 | StringRef Bytes(getBytes(OffsetPtr, Length)); |
178 | return Bytes.trim(Chars: TrimChars); |
179 | } |
180 | |
181 | StringRef DataExtractor::(uint64_t *OffsetPtr, uint64_t Length, |
182 | Error *Err) const { |
183 | ErrorAsOutParameter ErrAsOut(Err); |
184 | if (isError(E: Err)) |
185 | return StringRef(); |
186 | |
187 | if (!prepareRead(Offset: *OffsetPtr, Size: Length, E: Err)) |
188 | return StringRef(); |
189 | |
190 | StringRef Result = Data.substr(Start: *OffsetPtr, N: Length); |
191 | *OffsetPtr += Length; |
192 | return Result; |
193 | } |
194 | |
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(Input: Data); |
200 | assert(*OffsetPtr <= Bytes.size()); |
201 | ErrorAsOutParameter ErrAsOut(Err); |
202 | if (isError(E: Err)) |
203 | return T(); |
204 | |
205 | const char *error = nullptr; |
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(EC: errc::illegal_byte_sequence, |
212 | Fmt: "unable to decode LEB128 at offset 0x%8.8" PRIx64 |
213 | ": %s" , |
214 | Vals: *OffsetPtr, Vals: error); |
215 | return T(); |
216 | } |
217 | *OffsetPtr += bytes_read; |
218 | return result; |
219 | } |
220 | |
221 | uint64_t DataExtractor::(uint64_t *offset_ptr, Error *Err) const { |
222 | return getLEB128(Data, OffsetPtr: offset_ptr, Err, Decoder&: decodeULEB128); |
223 | } |
224 | |
225 | int64_t DataExtractor::(uint64_t *offset_ptr, Error *Err) const { |
226 | return getLEB128(Data, OffsetPtr: offset_ptr, Err, Decoder&: decodeSLEB128); |
227 | } |
228 | |
229 | void DataExtractor::(Cursor &C, uint64_t Length) const { |
230 | ErrorAsOutParameter ErrAsOut(&C.Err); |
231 | if (isError(E: &C.Err)) |
232 | return; |
233 | |
234 | if (prepareRead(Offset: C.Offset, Size: Length, E: &C.Err)) |
235 | C.Offset += Length; |
236 | } |
237 | |