brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.9 KiB · 759b579 Raw
234 lines · cpp
1//===- SFrameParser.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/Object/SFrameParser.h"10#include "llvm/BinaryFormat/SFrame.h"11#include "llvm/Object/Error.h"12#include "llvm/Support/FormatVariadic.h"13#include "llvm/Support/MathExtras.h"14 15using namespace llvm;16using namespace llvm::object;17 18static Expected<ArrayRef<uint8_t>>19getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size) {20  uint64_t End = SaturatingAdd(Offset, Size);21  // Data.size() cannot be UINT64_MAX, as it would occupy the whole address22  // space.23  if (End > Data.size()) {24    return createStringError(25        formatv("unexpected end of data at offset {0:x} while reading [{1:x}, "26                "{2:x})",27                Data.size(), Offset, End)28            .str(),29        object_error::unexpected_eof);30  }31  return Data.slice(Offset, Size);32}33 34template <typename T>35static Expected<ArrayRef<T>>36getDataSliceAsArrayOf(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Count) {37  static_assert(std::is_trivial_v<T>);38  Expected<ArrayRef<uint8_t>> Slice =39      getDataSlice(Data, Offset, sizeof(T) * Count);40  if (!Slice)41    return Slice.takeError();42 43  return ArrayRef(reinterpret_cast<const T *>(Slice->data()), Count);44}45 46template <typename T>47static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,48                                          uint64_t Offset) {49  Expected<ArrayRef<T>> Array = getDataSliceAsArrayOf<T>(Data, Offset, 1);50  if (!Array)51    return Array.takeError();52 53  return Array->front();54}55 56template <endianness E>57Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents,58                                                  uint64_t SectionAddress) {59  Expected<const sframe::Preamble<E> &> Preamble =60      getDataSliceAs<sframe::Preamble<E>>(Contents, 0);61  if (!Preamble)62    return Preamble.takeError();63 64  if (Preamble->Magic != sframe::Magic)65    return createError(66        formatv("invalid magic number ({0:x+4})", Preamble->Magic.value()));67  if (Preamble->Version != sframe::Version::V2)68    return createError(69        formatv("invalid/unsupported version number ({0})",70                static_cast<unsigned>(Preamble->Version.value())));71 72  Expected<const sframe::Header<E> &> Header =73      getDataSliceAs<sframe::Header<E>>(Contents, 0);74  if (!Header)75    return Header.takeError();76  return SFrameParser(Contents, SectionAddress, *Header);77}78 79template <endianness E>80Expected<ArrayRef<uint8_t>> SFrameParser<E>::getAuxHeader() const {81  return getDataSlice(Data, sizeof(Header), Header.AuxHdrLen);82}83 84template <endianness E>85Expected<ArrayRef<sframe::FuncDescEntry<E>>> SFrameParser<E>::fdes() const {86  Expected<ArrayRef<uint8_t>> Slice = getDataSlice(87      Data, getFDEBase(), Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>));88  if (!Slice)89    return Slice.takeError();90  return ArrayRef(91      reinterpret_cast<const sframe::FuncDescEntry<E> *>(Slice->data()),92      Header.NumFDEs);93}94 95template <endianness E>96uint64_t SFrameParser<E>::getAbsoluteStartAddress(97    typename FDERange::iterator FDE) const {98  uint64_t Result = SectionAddress + FDE->StartAddress;99 100  if ((getPreamble().Flags.value() & sframe::Flags::FDEFuncStartPCRel) ==101      sframe::Flags::FDEFuncStartPCRel)102    Result += offsetOf(FDE);103 104  return Result;105}106 107template <endianness E>108uint64_t SFrameParser<E>::offsetOf(typename FDERange::iterator FDE) const {109  uintptr_t DataPtr = reinterpret_cast<uintptr_t>(Data.data());110  uintptr_t FDEPtr = reinterpret_cast<uintptr_t>(&*FDE);111 112  assert(DataPtr <= FDEPtr && FDEPtr < DataPtr + Data.size() &&113         "Iterator does not belong to this object!");114  return FDEPtr - DataPtr;115}116 117template <typename EndianT>118static Error readArray(ArrayRef<uint8_t> Data, uint64_t Count, uint64_t &Offset,119                       SmallVectorImpl<int32_t> &Vec) {120  Expected<ArrayRef<EndianT>> RawArray =121      getDataSliceAsArrayOf<EndianT>(Data, Offset, Count);122  if (!RawArray)123    return RawArray.takeError();124  Offset += Count * sizeof(EndianT);125  Vec.resize(Count);126  llvm::copy(*RawArray, Vec.begin());127  return Error::success();128}129 130template <typename T, endianness E>131static Error readFRE(ArrayRef<uint8_t> Data, uint64_t &Offset,132                     typename SFrameParser<E>::FrameRowEntry &FRE) {133  Expected<sframe::FrameRowEntry<T, E>> RawFRE =134      getDataSliceAs<sframe::FrameRowEntry<T, E>>(Data, Offset);135  if (!RawFRE)136    return RawFRE.takeError();137 138  Offset += sizeof(*RawFRE);139  FRE.StartAddress = RawFRE->StartAddress;140  FRE.Info.Info = RawFRE->Info.Info;141 142  switch (FRE.Info.getOffsetSize()) {143  case sframe::FREOffset::B1:144    return readArray<sframe::detail::packed<int8_t, E>>(145        Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets);146  case sframe::FREOffset::B2:147    return readArray<sframe::detail::packed<int16_t, E>>(148        Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets);149  case sframe::FREOffset::B4:150    return readArray<sframe::detail::packed<int32_t, E>>(151        Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets);152  }153  return createError(formatv("unsupported FRE offset size {0} at offset {1:x+}",154                             static_cast<unsigned>(FRE.Info.getOffsetSize()),155                             Offset));156}157 158template <endianness E> Error SFrameParser<E>::FallibleFREIterator::inc() {159  if (++Idx == Size)160    return Error::success();161 162  switch (FREType) {163  case sframe::FREType::Addr1:164    return readFRE<uint8_t, E>(Data, Offset, FRE);165  case sframe::FREType::Addr2:166    return readFRE<uint16_t, E>(Data, Offset, FRE);167  case sframe::FREType::Addr4:168    return readFRE<uint32_t, E>(Data, Offset, FRE);169  }170  return createError(formatv("unsupported FRE type {0} at offset {1:x+}",171                             static_cast<unsigned>(FREType), Offset));172}173 174template <endianness E>175iterator_range<typename SFrameParser<E>::fre_iterator>176SFrameParser<E>::fres(const sframe::FuncDescEntry<E> &FDE, Error &Err) const {177  uint64_t Offset = getFREBase() + FDE.StartFREOff;178  fre_iterator BeforeBegin = make_fallible_itr(179      FallibleFREIterator(Data, FDE.Info.getFREType(), -1, FDE.NumFREs, Offset),180      Err);181  fre_iterator End = make_fallible_end(182      FallibleFREIterator(Data, FDE.Info.getFREType(), FDE.NumFREs, FDE.NumFREs,183                          /*Offset=*/0));184  return {++BeforeBegin, End};185}186 187static std::optional<int32_t> getOffset(ArrayRef<int32_t> Offsets, size_t Idx) {188  if (Offsets.size() > Idx)189    return Offsets[Idx];190  return std::nullopt;191}192 193// The interpretation of offsets is ABI-specific. The implementation of this and194// the following functions may need to be adjusted when adding support for a new195// ABI.196template <endianness E>197std::optional<int32_t>198SFrameParser<E>::getCFAOffset(const FrameRowEntry &FRE) const {199  return getOffset(FRE.Offsets, 0);200}201 202template <endianness E>203std::optional<int32_t>204SFrameParser<E>::getRAOffset(const FrameRowEntry &FRE) const {205  if (usesFixedRAOffset())206    return Header.CFAFixedRAOffset;207  return getOffset(FRE.Offsets, 1);208}209 210template <endianness E>211std::optional<int32_t>212SFrameParser<E>::getFPOffset(const FrameRowEntry &FRE) const {213  if (usesFixedFPOffset())214    return Header.CFAFixedFPOffset;215  return getOffset(FRE.Offsets, usesFixedRAOffset() ? 1 : 2);216}217 218template <endianness E>219ArrayRef<int32_t>220SFrameParser<E>::getExtraOffsets(const FrameRowEntry &FRE) const {221  size_t UsedOffsets = 1; // CFA222  if (!usesFixedRAOffset())223    ++UsedOffsets;224  if (!usesFixedFPOffset())225    ++UsedOffsets;226  if (FRE.Offsets.size() > UsedOffsets)227    return ArrayRef<int32_t>(FRE.Offsets).drop_front(UsedOffsets);228  return {};229}230 231template class LLVM_EXPORT_TEMPLATE llvm::object::SFrameParser<endianness::big>;232template class LLVM_EXPORT_TEMPLATE233    llvm::object::SFrameParser<endianness::little>;234