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 18 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 38 static bool isError(Error *E) { return E && *E; } 39 40 template <typename T> 41 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> 60 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 80 uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const { 81 return getU<uint8_t>(offset_ptr, Err); 82 } 83 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); 87 } 88 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); 91 } 92 93 uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const { 94 return getU<uint16_t>(offset_ptr, Err); 95 } 96 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); 100 } 101 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); 106 } 107 108 uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const { 109 return getU<uint32_t>(offset_ptr, Err); 110 } 111 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); 115 } 116 117 uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const { 118 return getU<uint64_t>(offset_ptr, Err); 119 } 120 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); 124 } 125 126 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 142 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 156 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 174 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 181 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> 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 221 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const { 222 return getLEB128(Data, offset_ptr, Err, decodeULEB128); 223 } 224 225 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const { 226 return getLEB128(Data, offset_ptr, Err, decodeSLEB128); 227 } 228 229 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