brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 7390093 Raw
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