Path: blob/main/contrib/llvm-project/llvm/lib/Support/DataExtractor.cpp
35232 views
//===-- DataExtractor.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/Support/DataExtractor.h"9#include "llvm/ADT/StringExtras.h"10#include "llvm/Support/Errc.h"11#include "llvm/Support/ErrorHandling.h"12#include "llvm/Support/LEB128.h"13#include "llvm/Support/SwapByteOrder.h"1415using namespace llvm;1617bool DataExtractor::prepareRead(uint64_t Offset, uint64_t Size,18Error *E) const {19if (isValidOffsetForDataOfSize(Offset, Size))20return true;21if (E) {22if (Offset <= Data.size())23*E = createStringError(24errc::illegal_byte_sequence,25"unexpected end of data at offset 0x%zx while reading [0x%" PRIx6426", 0x%" PRIx64 ")",27Data.size(), Offset, Offset + Size);28else29*E = createStringError(errc::invalid_argument,30"offset 0x%" PRIx6431" is beyond the end of data at 0x%zx",32Offset, Data.size());33}34return false;35}3637static bool isError(Error *E) { return E && *E; }3839template <typename T>40T DataExtractor::getU(uint64_t *offset_ptr, Error *Err) const {41ErrorAsOutParameter ErrAsOut(Err);42T val = 0;43if (isError(Err))44return val;4546uint64_t offset = *offset_ptr;47if (!prepareRead(offset, sizeof(T), Err))48return val;49std::memcpy(&val, &Data.data()[offset], sizeof(val));50if (sys::IsLittleEndianHost != IsLittleEndian)51sys::swapByteOrder(val);5253// Advance the offset54*offset_ptr += sizeof(val);55return val;56}5758template <typename T>59T *DataExtractor::getUs(uint64_t *offset_ptr, T *dst, uint32_t count,60Error *Err) const {61ErrorAsOutParameter ErrAsOut(Err);62if (isError(Err))63return nullptr;6465uint64_t offset = *offset_ptr;6667if (!prepareRead(offset, sizeof(*dst) * count, Err))68return nullptr;69for (T *value_ptr = dst, *end = dst + count; value_ptr != end;70++value_ptr, offset += sizeof(*dst))71*value_ptr = getU<T>(offset_ptr, Err);72// Advance the offset73*offset_ptr = offset;74// Return a non-NULL pointer to the converted data as an indicator of75// success76return dst;77}7879uint8_t DataExtractor::getU8(uint64_t *offset_ptr, llvm::Error *Err) const {80return getU<uint8_t>(offset_ptr, Err);81}8283uint8_t *DataExtractor::getU8(uint64_t *offset_ptr, uint8_t *dst,84uint32_t count) const {85return getUs<uint8_t>(offset_ptr, dst, count, nullptr);86}8788uint8_t *DataExtractor::getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const {89return getUs<uint8_t>(&C.Offset, Dst, Count, &C.Err);90}9192uint16_t DataExtractor::getU16(uint64_t *offset_ptr, llvm::Error *Err) const {93return getU<uint16_t>(offset_ptr, Err);94}9596uint16_t *DataExtractor::getU16(uint64_t *offset_ptr, uint16_t *dst,97uint32_t count) const {98return getUs<uint16_t>(offset_ptr, dst, count, nullptr);99}100101uint32_t DataExtractor::getU24(uint64_t *OffsetPtr, Error *Err) const {102uint24_t ExtractedVal = getU<uint24_t>(OffsetPtr, Err);103// The 3 bytes are in the correct byte order for the host.104return ExtractedVal.getAsUint32(sys::IsLittleEndianHost);105}106107uint32_t DataExtractor::getU32(uint64_t *offset_ptr, llvm::Error *Err) const {108return getU<uint32_t>(offset_ptr, Err);109}110111uint32_t *DataExtractor::getU32(uint64_t *offset_ptr, uint32_t *dst,112uint32_t count) const {113return getUs<uint32_t>(offset_ptr, dst, count, nullptr);114}115116uint64_t DataExtractor::getU64(uint64_t *offset_ptr, llvm::Error *Err) const {117return getU<uint64_t>(offset_ptr, Err);118}119120uint64_t *DataExtractor::getU64(uint64_t *offset_ptr, uint64_t *dst,121uint32_t count) const {122return getUs<uint64_t>(offset_ptr, dst, count, nullptr);123}124125uint64_t DataExtractor::getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,126llvm::Error *Err) const {127switch (byte_size) {128case 1:129return getU8(offset_ptr, Err);130case 2:131return getU16(offset_ptr, Err);132case 4:133return getU32(offset_ptr, Err);134case 8:135return getU64(offset_ptr, Err);136}137llvm_unreachable("getUnsigned unhandled case!");138}139140int64_t141DataExtractor::getSigned(uint64_t *offset_ptr, uint32_t byte_size) const {142switch (byte_size) {143case 1:144return (int8_t)getU8(offset_ptr);145case 2:146return (int16_t)getU16(offset_ptr);147case 4:148return (int32_t)getU32(offset_ptr);149case 8:150return (int64_t)getU64(offset_ptr);151}152llvm_unreachable("getSigned unhandled case!");153}154155StringRef DataExtractor::getCStrRef(uint64_t *OffsetPtr, Error *Err) const {156ErrorAsOutParameter ErrAsOut(Err);157if (isError(Err))158return StringRef();159160uint64_t Start = *OffsetPtr;161StringRef::size_type Pos = Data.find('\0', Start);162if (Pos != StringRef::npos) {163*OffsetPtr = Pos + 1;164return StringRef(Data.data() + Start, Pos - Start);165}166if (Err)167*Err = createStringError(errc::illegal_byte_sequence,168"no null terminated string at offset 0x%" PRIx64,169Start);170return StringRef();171}172173StringRef DataExtractor::getFixedLengthString(uint64_t *OffsetPtr,174uint64_t Length,175StringRef TrimChars) const {176StringRef Bytes(getBytes(OffsetPtr, Length));177return Bytes.trim(TrimChars);178}179180StringRef DataExtractor::getBytes(uint64_t *OffsetPtr, uint64_t Length,181Error *Err) const {182ErrorAsOutParameter ErrAsOut(Err);183if (isError(Err))184return StringRef();185186if (!prepareRead(*OffsetPtr, Length, Err))187return StringRef();188189StringRef Result = Data.substr(*OffsetPtr, Length);190*OffsetPtr += Length;191return Result;192}193194template <typename T>195static T getLEB128(StringRef Data, uint64_t *OffsetPtr, Error *Err,196T (&Decoder)(const uint8_t *p, unsigned *n,197const uint8_t *end, const char **error)) {198ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(Data);199assert(*OffsetPtr <= Bytes.size());200ErrorAsOutParameter ErrAsOut(Err);201if (isError(Err))202return T();203204const char *error = nullptr;205unsigned bytes_read;206T result =207Decoder(Bytes.data() + *OffsetPtr, &bytes_read, Bytes.end(), &error);208if (error) {209if (Err)210*Err = createStringError(errc::illegal_byte_sequence,211"unable to decode LEB128 at offset 0x%8.8" PRIx64212": %s",213*OffsetPtr, error);214return T();215}216*OffsetPtr += bytes_read;217return result;218}219220uint64_t DataExtractor::getULEB128(uint64_t *offset_ptr, Error *Err) const {221return getLEB128(Data, offset_ptr, Err, decodeULEB128);222}223224int64_t DataExtractor::getSLEB128(uint64_t *offset_ptr, Error *Err) const {225return getLEB128(Data, offset_ptr, Err, decodeSLEB128);226}227228void DataExtractor::skip(Cursor &C, uint64_t Length) const {229ErrorAsOutParameter ErrAsOut(&C.Err);230if (isError(&C.Err))231return;232233if (prepareRead(C.Offset, Length, &C.Err))234C.Offset += Length;235}236237238