Skip to content

Commit c797a3e

Browse files
committed
[Object] Parsing and dumping of SFrame FDEs
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 aa7ada1 commit c797a3e

File tree

8 files changed

+530
-65
lines changed

8 files changed

+530
-65
lines changed

llvm/include/llvm/BinaryFormat/SFrame.h

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

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

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

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

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

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

170172
} // namespace sframe
171173
} // 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: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,37 @@ namespace object {
1919

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

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

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

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

38-
SFrameParser(ArrayRef<uint8_t> Data, const sframe::Header<E> &Header)
39-
: Data(Data), Header(Header) {}
49+
SFrameParser(ArrayRef<uint8_t> Data, uint64_t SectionAddress, const sframe::Header<E> &Header)
50+
: Data(Data), SectionAddress(SectionAddress), Header(Header) {}
51+
52+
uint64_t getFDEBegin() const { return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff; }
4053
};
4154

4255
extern template class 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: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,34 @@
1414
using namespace llvm;
1515
using namespace llvm::object;
1616

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)) {
17+
static Expected<ArrayRef<uint8_t>>
18+
getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size) {
19+
// Check for overflow.
20+
if (Offset + Size < Offset || Offset + Size < Size ||
21+
Offset + Size > Data.size()) {
2222
return createStringError(
2323
formatv("unexpected end of data at offset {0:x} while reading [{1:x}, "
2424
"{2:x})",
25-
Data.size(), Offset, Offset + sizeof(T))
25+
Data.size(), Offset, Offset + Size)
2626
.str(),
2727
object_error::unexpected_eof);
2828
}
29-
return *reinterpret_cast<const T *>(Data.data() + Offset);
29+
return Data.slice(Offset, Size);
30+
}
31+
32+
template <typename T>
33+
static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
34+
uint64_t Offset) {
35+
static_assert(std::is_trivial_v<T>);
36+
Expected<ArrayRef<uint8_t>> Slice = getDataSlice(Data, Offset, sizeof(T));
37+
if (!Slice)
38+
return Slice.takeError();
39+
40+
return *reinterpret_cast<const T *>(Slice->data());
3041
}
3142

3243
template <endianness E>
33-
Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents) {
44+
Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents, uint64_t SectionAddress) {
3445
Expected<const sframe::Preamble<E> &> Preamble =
3546
getDataSliceAs<sframe::Preamble<E>>(Contents, 0);
3647
if (!Preamble)
@@ -48,7 +59,42 @@ Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents) {
4859
getDataSliceAs<sframe::Header<E>>(Contents, 0);
4960
if (!Header)
5061
return Header.takeError();
51-
return SFrameParser(Contents, *Header);
62+
return SFrameParser(Contents, SectionAddress, *Header);
63+
}
64+
65+
66+
template<endianness E>
67+
Expected<ArrayRef<uint8_t>> SFrameParser<E>::getAuxHeader() const {
68+
return getDataSlice(Data, sizeof(Header), Header.AuxHdrLen);
69+
}
70+
71+
template<endianness E>
72+
Expected<ArrayRef<sframe::FuncDescEntry<E>>> SFrameParser<E>::fdes() const {
73+
Expected<ArrayRef<uint8_t>> Slice = getDataSlice(
74+
Data, getFDEBegin(), Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>));
75+
if (!Slice)
76+
return Slice.takeError();
77+
return ArrayRef(
78+
reinterpret_cast<const sframe::FuncDescEntry<E> *>(Slice->data()),
79+
Header.NumFDEs);
80+
}
81+
82+
template<endianness E>
83+
uint64_t SFrameParser<E>::getAbsoluteStartAddress(typename FDERange::iterator FDE) const {
84+
uint64_t Result = SectionAddress + FDE->StartAddress;
85+
86+
if ((getPreamble().Flags.value() & sframe::Flags::FDEFuncStartPCRel) ==
87+
sframe::Flags::FDEFuncStartPCRel) {
88+
uintptr_t DataPtr = reinterpret_cast<uintptr_t>(Data.data());
89+
uintptr_t FDEPtr = reinterpret_cast<uintptr_t>(&*FDE);
90+
91+
assert(DataPtr <= FDEPtr);
92+
assert(FDEPtr < DataPtr + Data.size());
93+
94+
Result += FDEPtr - DataPtr;
95+
}
96+
97+
return Result;
5298
}
5399

54100
template class llvm::object::SFrameParser<endianness::big>;

0 commit comments

Comments
 (0)