237 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/DataExtractor.h"10#include "llvm/ADT/StringExtras.h"11#include "llvm/Support/Errc.h"12#include "llvm/Support/ErrorHandling.h"13#include "llvm/Support/LEB128.h"14#include "llvm/Support/SwapByteOrder.h"15 16using namespace llvm;17 18bool 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%" PRIx6427 ", 0x%" PRIx64 ")",28 Data.size(), Offset, Offset + Size);29 else30 *E = createStringError(errc::invalid_argument,31 "offset 0x%" PRIx6432 " is beyond the end of data at 0x%zx",33 Offset, Data.size());34 }35 return false;36}37 38static bool isError(Error *E) { return E && *E; }39 40template <typename T>41T 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 offset55 *offset_ptr += sizeof(val);56 return val;57}58 59template <typename T>60T *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 offset74 *offset_ptr = offset;75 // Return a non-NULL pointer to the converted data as an indicator of76 // success77 return dst;78}79 80uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {81 return getU<uint8_t>(offset_ptr, Err);82}83 84uint8_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 89uint8_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 93uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {94 return getU<uint16_t>(offset_ptr, Err);95}96 97uint16_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 102uint32_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 108uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {109 return getU<uint32_t>(offset_ptr, Err);110}111 112uint32_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 117uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {118 return getU<uint64_t>(offset_ptr, Err);119}120 121uint64_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 126uint64_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 141int64_t142DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {143 switch (byte_size) {144 case 1:145 return getS8(offset_ptr);146 case 2:147 return getS16(offset_ptr);148 case 4:149 return getS32(offset_ptr);150 case 8:151 return getS64(offset_ptr);152 }153 llvm_unreachable("getSigned unhandled case!");154}155 156StringRef 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 174StringRef 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 181StringRef 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 195template <typename T>196static 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 = nullptr;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" PRIx64213 ": %s",214 *OffsetPtr, error);215 return T();216 }217 *OffsetPtr += bytes_read;218 return result;219}220 221uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const {222 return getLEB128(Data, offset_ptr, Err, decodeULEB128);223}224 225int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const {226 return getLEB128(Data, offset_ptr, Err, decodeSLEB128);227}228 229void 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