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/LEB128.h" 13 #include "llvm/Support/SwapByteOrder.h" 14 15 using namespace llvm; 16 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()); 33 } 34 return false; 35 } 36 37 static bool isError(Error *E) { return E && *E; } 38 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; 45 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); 52 53 // Advance the offset 54 *offset_ptr += sizeof(val); 55 return val; 56 } 57 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; 64 65 uint64_t offset = *offset_ptr; 66 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; 77 } 78 79 uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const { 80 return getU<uint8_t>(offset_ptr, Err); 81 } 82 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); 86 } 87 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); 90 } 91 92 uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const { 93 return getU<uint16_t>(offset_ptr, Err); 94 } 95 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); 99 } 100 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); 105 } 106 107 uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const { 108 return getU<uint32_t>(offset_ptr, Err); 109 } 110 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); 114 } 115 116 uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const { 117 return getU<uint64_t>(offset_ptr, Err); 118 } 119 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); 123 } 124 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); 136 } 137 llvm_unreachable("getUnsigned unhandled case!"); 138 } 139 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); 151 } 152 llvm_unreachable("getSigned unhandled case!"); 153 } 154 155 StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const { 156 ErrorAsOutParameter ErrAsOut(Err); 157 if (isError(Err)) 158 return StringRef(); 159 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); 165 } 166 if (Err) 167 *Err = createStringError(errc::illegal_byte_sequence, 168 "no null terminated string at offset 0x%" PRIx64, 169 Start); 170 return StringRef(); 171 } 172 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); 178 } 179 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(); 185 186 if (!prepareRead(*OffsetPtr, Length, Err)) 187 return StringRef(); 188 189 StringRef Result = Data.substr(*OffsetPtr, Length); 190 *OffsetPtr += Length; 191 return Result; 192 } 193 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(); 203 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(); 215 } 216 *OffsetPtr += bytes_read; 217 return result; 218 } 219 220 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const { 221 return getLEB128(Data, offset_ptr, Err, decodeULEB128); 222 } 223 224 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const { 225 return getLEB128(Data, offset_ptr, Err, decodeSLEB128); 226 } 227 228 void DataExtractor::skip(Cursor &C, uint64_t Length) const { 229 ErrorAsOutParameter ErrAsOut(&C.Err); 230 if (isError(&C.Err)) 231 return; 232 233 if (prepareRead(C.Offset, Length, &C.Err)) 234 C.Offset += Length; 235 } 236