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