Skip to content

Commit ded255e

Browse files
authored
[Object] Parsing and dumping of SFrame FDEs (#149828)
Also known as Function Description Entries. The entries occupy a contiguous piece of the section, so the code is mostly straight-forward. For more information about the SFrame unwind format, see the [specification](https://sourceware.org/binutils/wiki/sframe) and the related [RFC](https://discourse.llvm.org/t/rfc-adding-sframe-support-to-llvm/86900).
1 parent c6f7fa7 commit ded255e

File tree

8 files changed

+545
-65
lines changed

8 files changed

+545
-65
lines changed

llvm/include/llvm/BinaryFormat/SFrame.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,27 @@ enum class ABI : uint8_t {
5050

5151
/// SFrame FRE Types. Bits 0-3 of FuncDescEntry.Info.
5252
enum class FREType : uint8_t {
53-
Addr1 = 0,
54-
Addr2 = 1,
55-
Addr4 = 2,
53+
#define HANDLE_SFRAME_FRE_TYPE(CODE, NAME) NAME = CODE,
54+
#include "llvm/BinaryFormat/SFrameConstants.def"
5655
};
5756

5857
/// SFrame FDE Types. Bit 4 of FuncDescEntry.Info.
5958
enum class FDEType : uint8_t {
60-
PCInc = 0,
61-
PCMask = 1,
59+
#define HANDLE_SFRAME_FDE_TYPE(CODE, NAME) NAME = CODE,
60+
#include "llvm/BinaryFormat/SFrameConstants.def"
6261
};
6362

6463
/// Speficies key used for signing return addresses. Bit 5 of
6564
/// FuncDescEntry.Info.
6665
enum class AArch64PAuthKey : uint8_t {
67-
A = 0,
68-
B = 1,
66+
#define HANDLE_SFRAME_AARCH64_PAUTH_KEY(CODE, NAME) NAME = CODE,
67+
#include "llvm/BinaryFormat/SFrameConstants.def"
6968
};
7069

71-
/// Size of stack offsets. Bits 5-6 of FREInfo.Info.
70+
/// Size of stack offsets. Bits 6-7 of FREInfo.Info.
7271
enum class FREOffset : uint8_t {
73-
B1 = 0,
74-
B2 = 1,
75-
B4 = 2,
72+
#define HANDLE_SFRAME_FRE_OFFSET(CODE, NAME) NAME = CODE,
73+
#include "llvm/BinaryFormat/SFrameConstants.def"
7674
};
7775

7876
/// Stack frame base register. Bit 0 of FREInfo.Info.
@@ -167,6 +165,10 @@ template <endianness E> using FrameRowEntryAddr4 = FrameRowEntry<uint32_t, E>;
167165
LLVM_ABI ArrayRef<EnumEntry<Version>> getVersions();
168166
LLVM_ABI ArrayRef<EnumEntry<Flags>> getFlags();
169167
LLVM_ABI ArrayRef<EnumEntry<ABI>> getABIs();
168+
LLVM_ABI ArrayRef<EnumEntry<FREType>> getFRETypes();
169+
LLVM_ABI ArrayRef<EnumEntry<FDEType>> getFDETypes();
170+
LLVM_ABI ArrayRef<EnumEntry<AArch64PAuthKey>> getAArch64PAuthKeys();
171+
LLVM_ABI ArrayRef<EnumEntry<FREOffset>> getFREOffsets();
170172

171173
} // namespace sframe
172174
} // namespace llvm

llvm/include/llvm/BinaryFormat/SFrameConstants.def

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#if !(defined(HANDLE_SFRAME_VERSION) || defined(HANDLE_SFRAME_FLAG) || \
10-
defined(HANDLE_SFRAME_ABI))
9+
#if !(defined(HANDLE_SFRAME_VERSION) || defined(HANDLE_SFRAME_FLAG) || \
10+
defined(HANDLE_SFRAME_ABI) || defined(HANDLE_SFRAME_FRE_TYPE) || \
11+
defined(HANDLE_SFRAME_FDE_TYPE) || \
12+
defined(HANDLE_SFRAME_AARCH64_PAUTH_KEY) || \
13+
defined(HANDLE_SFRAME_FRE_OFFSET))
1114
#error "Missing HANDLE_SFRAME definition"
1215
#endif
1316

@@ -23,6 +26,22 @@
2326
#define HANDLE_SFRAME_ABI(CODE, NAME)
2427
#endif
2528

29+
#ifndef HANDLE_SFRAME_FRE_TYPE
30+
#define HANDLE_SFRAME_FRE_TYPE(CODE, NAME)
31+
#endif
32+
33+
#ifndef HANDLE_SFRAME_FDE_TYPE
34+
#define HANDLE_SFRAME_FDE_TYPE(CODE, NAME)
35+
#endif
36+
37+
#ifndef HANDLE_SFRAME_AARCH64_PAUTH_KEY
38+
#define HANDLE_SFRAME_AARCH64_PAUTH_KEY(CODE, NAME)
39+
#endif
40+
41+
#ifndef HANDLE_SFRAME_FRE_OFFSET
42+
#define HANDLE_SFRAME_FRE_OFFSET(CODE, NAME)
43+
#endif
44+
2645
HANDLE_SFRAME_VERSION(0x01, V1)
2746
HANDLE_SFRAME_VERSION(0x02, V2)
2847

@@ -34,6 +53,24 @@ HANDLE_SFRAME_ABI(0x01, AArch64EndianBig)
3453
HANDLE_SFRAME_ABI(0x02, AArch64EndianLittle)
3554
HANDLE_SFRAME_ABI(0x03, AMD64EndianLittle)
3655

56+
HANDLE_SFRAME_FRE_TYPE(0x00, Addr1)
57+
HANDLE_SFRAME_FRE_TYPE(0x01, Addr2)
58+
HANDLE_SFRAME_FRE_TYPE(0x02, Addr4)
59+
60+
HANDLE_SFRAME_FDE_TYPE(0, PCInc)
61+
HANDLE_SFRAME_FDE_TYPE(1, PCMask)
62+
63+
HANDLE_SFRAME_AARCH64_PAUTH_KEY(0, A)
64+
HANDLE_SFRAME_AARCH64_PAUTH_KEY(1, B)
65+
66+
HANDLE_SFRAME_FRE_OFFSET(0, B1)
67+
HANDLE_SFRAME_FRE_OFFSET(1, B2)
68+
HANDLE_SFRAME_FRE_OFFSET(2, B4)
69+
3770
#undef HANDLE_SFRAME_VERSION
3871
#undef HANDLE_SFRAME_FLAG
3972
#undef HANDLE_SFRAME_ABI
73+
#undef HANDLE_SFRAME_FRE_TYPE
74+
#undef HANDLE_SFRAME_FDE_TYPE
75+
#undef HANDLE_SFRAME_AARCH64_PAUTH_KEY
76+
#undef HANDLE_SFRAME_FRE_OFFSET

llvm/include/llvm/Object/SFrameParser.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,40 @@ namespace object {
2020

2121
template <endianness E> class SFrameParser {
2222
public:
23-
static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents);
23+
static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents,
24+
uint64_t SectionAddress);
2425

2526
const sframe::Preamble<E> &getPreamble() const { return Header.Preamble; }
2627
const sframe::Header<E> &getHeader() const { return Header; }
2728

29+
Expected<ArrayRef<uint8_t>> getAuxHeader() const;
30+
2831
bool usesFixedRAOffset() const {
2932
return getHeader().ABIArch == sframe::ABI::AMD64EndianLittle;
3033
}
3134
bool usesFixedFPOffset() const {
3235
return false; // Not used in any currently defined ABI.
3336
}
3437

38+
using FDERange = ArrayRef<sframe::FuncDescEntry<E>>;
39+
Expected<FDERange> fdes() const;
40+
41+
// Decodes the start address of the given FDE, which must be one of the
42+
// objects returned by the `fdes()` function.
43+
uint64_t getAbsoluteStartAddress(typename FDERange::iterator FDE) const;
44+
3545
private:
3646
ArrayRef<uint8_t> Data;
47+
uint64_t SectionAddress;
3748
const sframe::Header<E> &Header;
3849

39-
SFrameParser(ArrayRef<uint8_t> Data, const sframe::Header<E> &Header)
40-
: Data(Data), Header(Header) {}
50+
SFrameParser(ArrayRef<uint8_t> Data, uint64_t SectionAddress,
51+
const sframe::Header<E> &Header)
52+
: Data(Data), SectionAddress(SectionAddress), Header(Header) {}
53+
54+
uint64_t getFDEBase() const {
55+
return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff;
56+
}
4157
};
4258

4359
extern template class LLVM_TEMPLATE_ABI SFrameParser<endianness::big>;

llvm/lib/BinaryFormat/SFrame.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,36 @@ ArrayRef<EnumEntry<sframe::ABI>> sframe::getABIs() {
3535
};
3636
return ArrayRef(ABIs);
3737
}
38+
39+
ArrayRef<EnumEntry<sframe::FREType>> sframe::getFRETypes() {
40+
static constexpr EnumEntry<sframe::FREType> FRETypes[] = {
41+
#define HANDLE_SFRAME_FRE_TYPE(CODE, NAME) {#NAME, sframe::FREType::NAME},
42+
#include "llvm/BinaryFormat/SFrameConstants.def"
43+
};
44+
return ArrayRef(FRETypes);
45+
}
46+
47+
ArrayRef<EnumEntry<sframe::FDEType>> sframe::getFDETypes() {
48+
static constexpr EnumEntry<sframe::FDEType> FDETypes[] = {
49+
#define HANDLE_SFRAME_FDE_TYPE(CODE, NAME) {#NAME, sframe::FDEType::NAME},
50+
#include "llvm/BinaryFormat/SFrameConstants.def"
51+
};
52+
return ArrayRef(FDETypes);
53+
}
54+
55+
ArrayRef<EnumEntry<sframe::AArch64PAuthKey>> sframe::getAArch64PAuthKeys() {
56+
static constexpr EnumEntry<sframe::AArch64PAuthKey> AArch64PAuthKeys[] = {
57+
#define HANDLE_SFRAME_AARCH64_PAUTH_KEY(CODE, NAME) \
58+
{#NAME, sframe::AArch64PAuthKey::NAME},
59+
#include "llvm/BinaryFormat/SFrameConstants.def"
60+
};
61+
return ArrayRef(AArch64PAuthKeys);
62+
}
63+
64+
ArrayRef<EnumEntry<sframe::FREOffset>> sframe::getFREOffsets() {
65+
static constexpr EnumEntry<sframe::FREOffset> FREOffsets[] = {
66+
#define HANDLE_SFRAME_FRE_OFFSET(CODE, NAME) {#NAME, sframe::FREOffset::NAME},
67+
#include "llvm/BinaryFormat/SFrameConstants.def"
68+
};
69+
return ArrayRef(FREOffsets);
70+
}

llvm/lib/Object/SFrameParser.cpp

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,41 @@
1010
#include "llvm/BinaryFormat/SFrame.h"
1111
#include "llvm/Object/Error.h"
1212
#include "llvm/Support/FormatVariadic.h"
13+
#include "llvm/Support/MathExtras.h"
1314

1415
using namespace llvm;
1516
using namespace llvm::object;
1617

17-
template <typename T>
18-
static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
19-
uint64_t Offset) {
20-
static_assert(std::is_trivial_v<T>);
21-
if (Data.size() < Offset + sizeof(T)) {
18+
static Expected<ArrayRef<uint8_t>>
19+
getDataSlice(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 address
22+
// space.
23+
if (End > Data.size()) {
2224
return createStringError(
2325
formatv("unexpected end of data at offset {0:x} while reading [{1:x}, "
2426
"{2:x})",
25-
Data.size(), Offset, Offset + sizeof(T))
27+
Data.size(), Offset, End)
2628
.str(),
2729
object_error::unexpected_eof);
2830
}
29-
return *reinterpret_cast<const T *>(Data.data() + Offset);
31+
return Data.slice(Offset, Size);
32+
}
33+
34+
template <typename T>
35+
static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
36+
uint64_t Offset) {
37+
static_assert(std::is_trivial_v<T>);
38+
Expected<ArrayRef<uint8_t>> Slice = getDataSlice(Data, Offset, sizeof(T));
39+
if (!Slice)
40+
return Slice.takeError();
41+
42+
return *reinterpret_cast<const T *>(Slice->data());
3043
}
3144

3245
template <endianness E>
33-
Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents) {
46+
Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents,
47+
uint64_t SectionAddress) {
3448
Expected<const sframe::Preamble<E> &> Preamble =
3549
getDataSliceAs<sframe::Preamble<E>>(Contents, 0);
3650
if (!Preamble)
@@ -48,7 +62,42 @@ Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents) {
4862
getDataSliceAs<sframe::Header<E>>(Contents, 0);
4963
if (!Header)
5064
return Header.takeError();
51-
return SFrameParser(Contents, *Header);
65+
return SFrameParser(Contents, SectionAddress, *Header);
66+
}
67+
68+
template <endianness E>
69+
Expected<ArrayRef<uint8_t>> SFrameParser<E>::getAuxHeader() const {
70+
return getDataSlice(Data, sizeof(Header), Header.AuxHdrLen);
71+
}
72+
73+
template <endianness E>
74+
Expected<ArrayRef<sframe::FuncDescEntry<E>>> SFrameParser<E>::fdes() const {
75+
Expected<ArrayRef<uint8_t>> Slice = getDataSlice(
76+
Data, getFDEBase(), Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>));
77+
if (!Slice)
78+
return Slice.takeError();
79+
return ArrayRef(
80+
reinterpret_cast<const sframe::FuncDescEntry<E> *>(Slice->data()),
81+
Header.NumFDEs);
82+
}
83+
84+
template <endianness E>
85+
uint64_t SFrameParser<E>::getAbsoluteStartAddress(
86+
typename FDERange::iterator FDE) const {
87+
uint64_t Result = SectionAddress + FDE->StartAddress;
88+
89+
if ((getPreamble().Flags.value() & sframe::Flags::FDEFuncStartPCRel) ==
90+
sframe::Flags::FDEFuncStartPCRel) {
91+
uintptr_t DataPtr = reinterpret_cast<uintptr_t>(Data.data());
92+
uintptr_t FDEPtr = reinterpret_cast<uintptr_t>(&*FDE);
93+
94+
assert(DataPtr <= FDEPtr && FDEPtr < DataPtr + Data.size() &&
95+
"Iterator does not belong to this object!");
96+
97+
Result += FDEPtr - DataPtr;
98+
}
99+
100+
return Result;
52101
}
53102

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

0 commit comments

Comments
 (0)