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 static void unexpectedEndReached(Error *E) { 19 if (E) 20 *E = createStringError(errc::illegal_byte_sequence, 21 "unexpected end of data"); 22 } 23 24 static bool isError(Error *E) { return E && *E; } 25 26 template <typename T> 27 static T getU(uint64_t *offset_ptr, const DataExtractor *de, 28 bool isLittleEndian, const char *Data, llvm::Error *Err) { 29 ErrorAsOutParameter ErrAsOut(Err); 30 T val = 0; 31 if (isError(Err)) 32 return val; 33 34 uint64_t offset = *offset_ptr; 35 if (!de->isValidOffsetForDataOfSize(offset, sizeof(T))) { 36 unexpectedEndReached(Err); 37 return val; 38 } 39 std::memcpy(&val, &Data[offset], sizeof(val)); 40 if (sys::IsLittleEndianHost != isLittleEndian) 41 sys::swapByteOrder(val); 42 43 // Advance the offset 44 *offset_ptr += sizeof(val); 45 return val; 46 } 47 48 template <typename T> 49 static T *getUs(uint64_t *offset_ptr, T *dst, uint32_t count, 50 const DataExtractor *de, bool isLittleEndian, const char *Data, 51 llvm::Error *Err) { 52 ErrorAsOutParameter ErrAsOut(Err); 53 if (isError(Err)) 54 return nullptr; 55 56 uint64_t offset = *offset_ptr; 57 58 if (!de->isValidOffsetForDataOfSize(offset, sizeof(*dst) * count)) { 59 unexpectedEndReached(Err); 60 return nullptr; 61 } 62 for (T *value_ptr = dst, *end = dst + count; value_ptr != end; 63 ++value_ptr, offset += sizeof(*dst)) 64 *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data, Err); 65 // Advance the offset 66 *offset_ptr = offset; 67 // Return a non-NULL pointer to the converted data as an indicator of 68 // success 69 return dst; 70 } 71 72 uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const { 73 return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err); 74 } 75 76 uint8_t * 77 DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const { 78 return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian, 79 Data.data(), nullptr); 80 } 81 82 uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const { 83 return getUs<uint8_t>(&C.Offset, Dst, Count, this, IsLittleEndian, 84 Data.data(), &C.Err); 85 } 86 87 uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const { 88 return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err); 89 } 90 91 uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst, 92 uint32_t count) const { 93 return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian, 94 Data.data(), nullptr); 95 } 96 97 uint32_t DataExtractor::getU24(uint64_t *offset_ptr) const { 98 uint24_t ExtractedVal = 99 getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data(), nullptr); 100 // The 3 bytes are in the correct byte order for the host. 101 return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); 102 } 103 104 uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const { 105 return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err); 106 } 107 108 uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst, 109 uint32_t count) const { 110 return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian, 111 Data.data(), nullptr); 112 } 113 114 uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const { 115 return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data(), Err); 116 } 117 118 uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst, 119 uint32_t count) const { 120 return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian, 121 Data.data(), nullptr); 122 } 123 124 uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size, 125 llvm::Error *Err) const { 126 switch (byte_size) { 127 case 1: 128 return getU8(offset_ptr, Err); 129 case 2: 130 return getU16(offset_ptr, Err); 131 case 4: 132 return getU32(offset_ptr, Err); 133 case 8: 134 return getU64(offset_ptr, Err); 135 } 136 llvm_unreachable("getUnsigned unhandled case!"); 137 } 138 139 int64_t 140 DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const { 141 switch (byte_size) { 142 case 1: 143 return (int8_t)getU8(offset_ptr); 144 case 2: 145 return (int16_t)getU16(offset_ptr); 146 case 4: 147 return (int32_t)getU32(offset_ptr); 148 case 8: 149 return (int64_t)getU64(offset_ptr); 150 } 151 llvm_unreachable("getSigned unhandled case!"); 152 } 153 154 const char *DataExtractor::getCStr(uint64_t *offset_ptr) const { 155 uint64_t offset = *offset_ptr; 156 StringRef::size_type pos = Data.find('\0', offset); 157 if (pos != StringRef::npos) { 158 *offset_ptr = pos + 1; 159 return Data.data() + offset; 160 } 161 return nullptr; 162 } 163 164 StringRef DataExtractor::getCStrRef(uint64_t *offset_ptr) const { 165 uint64_t Start = *offset_ptr; 166 StringRef::size_type Pos = Data.find('\0', Start); 167 if (Pos != StringRef::npos) { 168 *offset_ptr = Pos + 1; 169 return StringRef(Data.data() + Start, Pos - Start); 170 } 171 return StringRef(); 172 } 173 174 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, 175 llvm::Error *Err) const { 176 assert(*offset_ptr <= Data.size()); 177 ErrorAsOutParameter ErrAsOut(Err); 178 if (isError(Err)) 179 return 0; 180 181 const char *error; 182 unsigned bytes_read; 183 uint64_t result = decodeULEB128( 184 reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read, 185 reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error); 186 if (error) { 187 if (Err) 188 *Err = createStringError(errc::illegal_byte_sequence, error); 189 return 0; 190 } 191 *offset_ptr += bytes_read; 192 return result; 193 } 194 195 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr) const { 196 assert(*offset_ptr <= Data.size()); 197 198 const char *error; 199 unsigned bytes_read; 200 int64_t result = decodeSLEB128( 201 reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read, 202 reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error); 203 if (error) 204 return 0; 205 *offset_ptr += bytes_read; 206 return result; 207 } 208 209 void DataExtractor::skip(Cursor &C, uint64_t Length) const { 210 ErrorAsOutParameter ErrAsOut(&C.Err); 211 if (isError(&C.Err)) 212 return; 213 214 if (isValidOffsetForDataOfSize(C.Offset, Length)) 215 C.Offset += Length; 216 else 217 unexpectedEndReached(&C.Err); 218 } 219