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(uint64_t *offset_ptr, const DataExtractor *de, 18 bool isLittleEndian, const char *Data) { 19 T val = 0; 20 uint64_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(uint64_t *offset_ptr, T *dst, uint32_t count, 34 const DataExtractor *de, bool isLittleEndian, const char *Data){ 35 uint64_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(uint64_t *offset_ptr) const { 51 return getU<uint8_t>(offset_ptr, this, IsLittleEndian, Data.data()); 52 } 53 54 uint8_t * 55 DataExtractor::getU8(uint64_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 uint16_t DataExtractor::getU16(uint64_t *offset_ptr) const { 61 return getU<uint16_t>(offset_ptr, this, IsLittleEndian, Data.data()); 62 } 63 64 uint16_t *DataExtractor::getU16(uint64_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(uint64_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(uint64_t *offset_ptr) const { 78 return getU<uint32_t>(offset_ptr, this, IsLittleEndian, Data.data()); 79 } 80 81 uint32_t *DataExtractor::getU32(uint64_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(uint64_t *offset_ptr) const { 88 return getU<uint64_t>(offset_ptr, this, IsLittleEndian, Data.data()); 89 } 90 91 uint64_t *DataExtractor::getU64(uint64_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(uint64_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(uint64_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(uint64_t *offset_ptr) const { 128 uint64_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(uint64_t *offset_ptr) const { 138 uint64_t Start = *offset_ptr; 139 StringRef::size_type Pos = Data.find('\0', Start); 140 if (Pos != StringRef::npos) { 141 *offset_ptr = Pos + 1; 142 return StringRef(Data.data() + Start, Pos - Start); 143 } 144 return StringRef(); 145 } 146 147 uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr) const { 148 assert(*offset_ptr <= Data.size()); 149 150 const char *error; 151 unsigned bytes_read; 152 uint64_t result = decodeULEB128( 153 reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read, 154 reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error); 155 if (error) 156 return 0; 157 *offset_ptr += bytes_read; 158 return result; 159 } 160 161 int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr) const { 162 assert(*offset_ptr <= Data.size()); 163 164 const char *error; 165 unsigned bytes_read; 166 int64_t result = decodeSLEB128( 167 reinterpret_cast<const uint8_t *>(Data.data() + *offset_ptr), &bytes_read, 168 reinterpret_cast<const uint8_t *>(Data.data() + Data.size()), &error); 169 if (error) 170 return 0; 171 *offset_ptr += bytes_read; 172 return result; 173 } 174