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/ErrorHandling.h" 11 #include "llvm/Support/Host.h" 12 #include "llvm/Support/SwapByteOrder.h" 13 using namespace llvm; 14 15 template <typename T> 16 static T getU(uint32_t *offset_ptr, const DataExtractor *de, 17 bool isLittleEndian, const char *Data) { 18 T val = 0; 19 uint32_t offset = *offset_ptr; 20 if (de->isValidOffsetForDataOfSize(offset, sizeof(val))) { 21 std::memcpy(&val, &Data[offset], sizeof(val)); 22 if (sys::IsLittleEndianHost != isLittleEndian) 23 sys::swapByteOrder(val); 24 25 // Advance the offset 26 *offset_ptr += sizeof(val); 27 } 28 return val; 29 } 30 31 template <typename T> 32 static T *getUs(uint32_t *offset_ptr, T *dst, uint32_t count, 33 const DataExtractor *de, bool isLittleEndian, const char *Data){ 34 uint32_t offset = *offset_ptr; 35 36 if (count > 0 && de->isValidOffsetForDataOfSize(offset, sizeof(*dst)*count)) { 37 for (T *value_ptr = dst, *end = dst + count; value_ptr != end; 38 ++value_ptr, offset += sizeof(*dst)) 39 *value_ptr = getU<T>(offset_ptr, de, isLittleEndian, Data); 40 // Advance the offset 41 *offset_ptr = offset; 42 // Return a non-NULL pointer to the converted data as an indicator of 43 // success 44 return dst; 45 } 46 return nullptr; 47 } 48 49 uint8_t DataExtractor::getU8(uint32_t *offset_ptr) const { 50 return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data()); 51 } 52 53 uint8_t * 54 DataExtractor::getU8(uint32_t *offset_ptr, uint8_t *dst, uint32_t count) const { 55 return getUs<uint8_t>(offset_ptr, dst, count, this, IsLittleEndian, 56 Data.data()); 57 } 58 59 60 uint16_t DataExtractor::getU16(uint32_t *offset_ptr) const { 61 return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data()); 62 } 63 64 uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst, 65 uint32_t count) const { 66 return getUs<uint16_t>(offset_ptr, dst, count, this, IsLittleEndian, 67 Data.data()); 68 } 69 70 uint32_t DataExtractor::getU24(uint32_t *offset_ptr) const { 71 uint24_t ExtractedVal = 72 getU<uint24_t>(offset_ptr, this, IsLittleEndian, Data.data()); 73 // The 3 bytes are in the correct byte order for the host. 74 return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); 75 } 76 77 uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { 78 return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data()); 79 } 80 81 uint32_t *DataExtractor::getU32(uint32_t *offset_ptr, uint32_t *dst, 82 uint32_t count) const { 83 return getUs<uint32_t>(offset_ptr, dst, count, this, IsLittleEndian, 84 Data.data()); 85 } 86 87 uint64_t DataExtractor::getU64(uint32_t *offset_ptr) const { 88 return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data()); 89 } 90 91 uint64_t *DataExtractor::getU64(uint32_t *offset_ptr, uint64_t *dst, 92 uint32_t count) const { 93 return getUs<uint64_t>(offset_ptr, dst, count, this, IsLittleEndian, 94 Data.data()); 95 } 96 97 uint64_t 98 DataExtractor::getUnsigned(uint32_t *offset_ptr, uint32_t byte_size) const { 99 switch (byte_size) { 100 case 1: 101 return getU8(offset_ptr); 102 case 2: 103 return getU16(offset_ptr); 104 case 4: 105 return getU32(offset_ptr); 106 case 8: 107 return getU64(offset_ptr); 108 } 109 llvm_unreachable("getUnsigned unhandled case!"); 110 } 111 112 int64_t 113 DataExtractor::getSigned(uint32_t *offset_ptr, uint32_t byte_size) const { 114 switch (byte_size) { 115 case 1: 116 return (int8_t)getU8(offset_ptr); 117 case 2: 118 return (int16_t)getU16(offset_ptr); 119 case 4: 120 return (int32_t)getU32(offset_ptr); 121 case 8: 122 return (int64_t)getU64(offset_ptr); 123 } 124 llvm_unreachable("getSigned unhandled case!"); 125 } 126 127 const char *DataExtractor::getCStr(uint32_t *offset_ptr) const { 128 uint32_t offset = *offset_ptr; 129 StringRef::size_type pos = Data.find('\0', offset); 130 if (pos != StringRef::npos) { 131 *offset_ptr = pos + 1; 132 return Data.data() + offset; 133 } 134 return nullptr; 135 } 136 137 StringRef DataExtractor::getCStrRef(uint32_t *OffsetPtr) const { 138 uint32_t Start = *OffsetPtr; 139 StringRef::size_type Pos = Data.find('\0', Start); 140 if (Pos != StringRef::npos) { 141 *OffsetPtr = Pos + 1; 142 return StringRef(Data.data() + Start, Pos - Start); 143 } 144 return StringRef(); 145 } 146 147 uint64_t DataExtractor::getULEB128(uint32_t *offset_ptr) const { 148 uint64_t result = 0; 149 if (Data.empty()) 150 return 0; 151 152 unsigned shift = 0; 153 uint32_t offset = *offset_ptr; 154 uint8_t byte = 0; 155 156 while (isValidOffset(offset)) { 157 byte = Data[offset++]; 158 result |= uint64_t(byte & 0x7f) << shift; 159 shift += 7; 160 if ((byte & 0x80) == 0) 161 break; 162 } 163 164 *offset_ptr = offset; 165 return result; 166 } 167 168 int64_t DataExtractor::getSLEB128(uint32_t *offset_ptr) const { 169 int64_t result = 0; 170 if (Data.empty()) 171 return 0; 172 173 unsigned shift = 0; 174 uint32_t offset = *offset_ptr; 175 uint8_t byte = 0; 176 177 while (isValidOffset(offset)) { 178 byte = Data[offset++]; 179 result |= uint64_t(byte & 0x7f) << shift; 180 shift += 7; 181 if ((byte & 0x80) == 0) 182 break; 183 } 184 185 // Sign bit of byte is 2nd high order bit (0x40) 186 if (shift < 64 && (byte & 0x40)) 187 result |= -(1ULL << shift); 188 189 *offset_ptr = offset; 190 return result; 191 } 192