aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/SFrameParser.cpp
blob: 5863490634e3277c1fa517b793798e978bbfc464 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//===- SFrameParser.cpp ---------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/Object/SFrameParser.h"
#include "llvm/BinaryFormat/SFrame.h"
#include "llvm/Object/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"

using namespace llvm;
using namespace llvm::object;

static Expected<ArrayRef<uint8_t>>
getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size) {
  uint64_t End = SaturatingAdd(Offset, Size);
  // Data.size() cannot be UINT64_MAX, as it would occupy the whole address
  // space.
  if (End > Data.size()) {
    return createStringError(
        formatv("unexpected end of data at offset {0:x} while reading [{1:x}, "
                "{2:x})",
                Data.size(), Offset, End)
            .str(),
        object_error::unexpected_eof);
  }
  return Data.slice(Offset, Size);
}

template <typename T>
static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
                                          uint64_t Offset) {
  static_assert(std::is_trivial_v<T>);
  Expected<ArrayRef<uint8_t>> Slice = getDataSlice(Data, Offset, sizeof(T));
  if (!Slice)
    return Slice.takeError();

  return *reinterpret_cast<const T *>(Slice->data());
}

template <endianness E>
Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents,
                                                  uint64_t SectionAddress) {
  Expected<const sframe::Preamble<E> &> Preamble =
      getDataSliceAs<sframe::Preamble<E>>(Contents, 0);
  if (!Preamble)
    return Preamble.takeError();

  if (Preamble->Magic != sframe::Magic)
    return createError(
        formatv("invalid magic number ({0:x+4})", Preamble->Magic.value()));
  if (Preamble->Version != sframe::Version::V2)
    return createError(
        formatv("invalid/unsupported version number ({0})",
                static_cast<unsigned>(Preamble->Version.value())));

  Expected<const sframe::Header<E> &> Header =
      getDataSliceAs<sframe::Header<E>>(Contents, 0);
  if (!Header)
    return Header.takeError();
  return SFrameParser(Contents, SectionAddress, *Header);
}

template <endianness E>
Expected<ArrayRef<uint8_t>> SFrameParser<E>::getAuxHeader() const {
  return getDataSlice(Data, sizeof(Header), Header.AuxHdrLen);
}

template <endianness E>
Expected<ArrayRef<sframe::FuncDescEntry<E>>> SFrameParser<E>::fdes() const {
  Expected<ArrayRef<uint8_t>> Slice = getDataSlice(
      Data, getFDEBase(), Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>));
  if (!Slice)
    return Slice.takeError();
  return ArrayRef(
      reinterpret_cast<const sframe::FuncDescEntry<E> *>(Slice->data()),
      Header.NumFDEs);
}

template <endianness E>
uint64_t SFrameParser<E>::getAbsoluteStartAddress(
    typename FDERange::iterator FDE) const {
  uint64_t Result = SectionAddress + FDE->StartAddress;

  if ((getPreamble().Flags.value() & sframe::Flags::FDEFuncStartPCRel) ==
      sframe::Flags::FDEFuncStartPCRel) {
    uintptr_t DataPtr = reinterpret_cast<uintptr_t>(Data.data());
    uintptr_t FDEPtr = reinterpret_cast<uintptr_t>(&*FDE);

    assert(DataPtr <= FDEPtr && FDEPtr < DataPtr + Data.size() &&
           "Iterator does not belong to this object!");

    Result += FDEPtr - DataPtr;
  }

  return Result;
}

template class LLVM_EXPORT_TEMPLATE llvm::object::SFrameParser<endianness::big>;
template class LLVM_EXPORT_TEMPLATE
    llvm::object::SFrameParser<endianness::little>;