[llvm] [Object] Parsing and dumping of SFrame FDEs (PR #149828)
Pavel Labath via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 30 00:26:07 PDT 2025
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/149828
>From c797a3e0c87de65d281b77f19bceb0911b6eb0ce Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Fri, 11 Jul 2025 11:21:07 +0200
Subject: [PATCH 1/4] [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).
---
llvm/include/llvm/BinaryFormat/SFrame.h | 24 +-
.../llvm/BinaryFormat/SFrameConstants.def | 41 +++-
llvm/include/llvm/Object/SFrameParser.h | 19 +-
llvm/lib/BinaryFormat/SFrame.cpp | 33 +++
llvm/lib/Object/SFrameParser.cpp | 64 ++++-
.../tools/llvm-readobj/ELF/sframe-fde.test | 232 ++++++++++++++++++
.../tools/llvm-readobj/ELF/sframe-header.test | 67 ++++-
llvm/tools/llvm-readobj/ELFDumper.cpp | 115 ++++++---
8 files changed, 530 insertions(+), 65 deletions(-)
create mode 100644 llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
diff --git a/llvm/include/llvm/BinaryFormat/SFrame.h b/llvm/include/llvm/BinaryFormat/SFrame.h
index 98dbe38fb2bc4..3ecaa32f373cf 100644
--- a/llvm/include/llvm/BinaryFormat/SFrame.h
+++ b/llvm/include/llvm/BinaryFormat/SFrame.h
@@ -49,29 +49,27 @@ enum class ABI : uint8_t {
/// SFrame FRE Types. Bits 0-3 of FuncDescEntry.Info.
enum class FREType : uint8_t {
- Addr1 = 0,
- Addr2 = 1,
- Addr4 = 2,
+#define HANDLE_SFRAME_FRE_TYPE(CODE, NAME) NAME = CODE,
+#include "llvm/BinaryFormat/SFrameConstants.def"
};
/// SFrame FDE Types. Bit 4 of FuncDescEntry.Info.
enum class FDEType : uint8_t {
- PCInc = 0,
- PCMask = 1,
+#define HANDLE_SFRAME_FDE_TYPE(CODE, NAME) NAME = CODE,
+#include "llvm/BinaryFormat/SFrameConstants.def"
};
/// Speficies key used for signing return addresses. Bit 5 of
/// FuncDescEntry.Info.
enum class AArch64PAuthKey : uint8_t {
- A = 0,
- B = 1,
+#define HANDLE_SFRAME_AARCH64_PAUTH_KEY(CODE, NAME) NAME = CODE,
+#include "llvm/BinaryFormat/SFrameConstants.def"
};
-/// Size of stack offsets. Bits 5-6 of FREInfo.Info.
+/// Size of stack offsets. Bits 6-7 of FREInfo.Info.
enum class FREOffset : uint8_t {
- B1 = 0,
- B2 = 1,
- B4 = 2,
+#define HANDLE_SFRAME_FRE_OFFSET(CODE, NAME) NAME = CODE,
+#include "llvm/BinaryFormat/SFrameConstants.def"
};
/// Stack frame base register. Bit 0 of FREInfo.Info.
@@ -166,6 +164,10 @@ template <endianness E> using FrameRowEntryAddr4 = FrameRowEntry<uint32_t, E>;
ArrayRef<EnumEntry<Version>> getVersions();
ArrayRef<EnumEntry<Flags>> getFlags();
ArrayRef<EnumEntry<ABI>> getABIs();
+ArrayRef<EnumEntry<FREType>> getFRETypes();
+ArrayRef<EnumEntry<FDEType>> getFDETypes();
+ArrayRef<EnumEntry<AArch64PAuthKey>> getAArch64PAuthKeys();
+ArrayRef<EnumEntry<FREOffset>> getFREOffsets();
} // namespace sframe
} // namespace llvm
diff --git a/llvm/include/llvm/BinaryFormat/SFrameConstants.def b/llvm/include/llvm/BinaryFormat/SFrameConstants.def
index 643b15f438c86..fddd440e41f32 100644
--- a/llvm/include/llvm/BinaryFormat/SFrameConstants.def
+++ b/llvm/include/llvm/BinaryFormat/SFrameConstants.def
@@ -6,8 +6,11 @@
//
//===----------------------------------------------------------------------===//
-#if !(defined(HANDLE_SFRAME_VERSION) || defined(HANDLE_SFRAME_FLAG) || \
- defined(HANDLE_SFRAME_ABI))
+#if !(defined(HANDLE_SFRAME_VERSION) || defined(HANDLE_SFRAME_FLAG) || \
+ defined(HANDLE_SFRAME_ABI) || defined(HANDLE_SFRAME_FRE_TYPE) || \
+ defined(HANDLE_SFRAME_FDE_TYPE) || \
+ defined(HANDLE_SFRAME_AARCH64_PAUTH_KEY) || \
+ defined(HANDLE_SFRAME_FRE_OFFSET))
#error "Missing HANDLE_SFRAME definition"
#endif
@@ -23,6 +26,22 @@
#define HANDLE_SFRAME_ABI(CODE, NAME)
#endif
+#ifndef HANDLE_SFRAME_FRE_TYPE
+#define HANDLE_SFRAME_FRE_TYPE(CODE, NAME)
+#endif
+
+#ifndef HANDLE_SFRAME_FDE_TYPE
+#define HANDLE_SFRAME_FDE_TYPE(CODE, NAME)
+#endif
+
+#ifndef HANDLE_SFRAME_AARCH64_PAUTH_KEY
+#define HANDLE_SFRAME_AARCH64_PAUTH_KEY(CODE, NAME)
+#endif
+
+#ifndef HANDLE_SFRAME_FRE_OFFSET
+#define HANDLE_SFRAME_FRE_OFFSET(CODE, NAME)
+#endif
+
HANDLE_SFRAME_VERSION(0x01, V1)
HANDLE_SFRAME_VERSION(0x02, V2)
@@ -34,6 +53,24 @@ HANDLE_SFRAME_ABI(0x01, AArch64EndianBig)
HANDLE_SFRAME_ABI(0x02, AArch64EndianLittle)
HANDLE_SFRAME_ABI(0x03, AMD64EndianLittle)
+HANDLE_SFRAME_FRE_TYPE(0x00, Addr1)
+HANDLE_SFRAME_FRE_TYPE(0x01, Addr2)
+HANDLE_SFRAME_FRE_TYPE(0x02, Addr4)
+
+HANDLE_SFRAME_FDE_TYPE(0, PCInc)
+HANDLE_SFRAME_FDE_TYPE(1, PCMask)
+
+HANDLE_SFRAME_AARCH64_PAUTH_KEY(0, A)
+HANDLE_SFRAME_AARCH64_PAUTH_KEY(1, B)
+
+HANDLE_SFRAME_FRE_OFFSET(0, B1)
+HANDLE_SFRAME_FRE_OFFSET(1, B2)
+HANDLE_SFRAME_FRE_OFFSET(2, B4)
+
#undef HANDLE_SFRAME_VERSION
#undef HANDLE_SFRAME_FLAG
#undef HANDLE_SFRAME_ABI
+#undef HANDLE_SFRAME_FRE_TYPE
+#undef HANDLE_SFRAME_FDE_TYPE
+#undef HANDLE_SFRAME_AARCH64_PAUTH_KEY
+#undef HANDLE_SFRAME_FRE_OFFSET
diff --git a/llvm/include/llvm/Object/SFrameParser.h b/llvm/include/llvm/Object/SFrameParser.h
index cf4fe20e84431..974c757419334 100644
--- a/llvm/include/llvm/Object/SFrameParser.h
+++ b/llvm/include/llvm/Object/SFrameParser.h
@@ -19,11 +19,14 @@ namespace object {
template <endianness E> class SFrameParser {
public:
- static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents);
+ static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents,
+ uint64_t SectionAddress);
const sframe::Preamble<E> &getPreamble() const { return Header.Preamble; }
const sframe::Header<E> &getHeader() const { return Header; }
+ Expected<ArrayRef<uint8_t>> getAuxHeader() const;
+
bool usesFixedRAOffset() const {
return getHeader().ABIArch == sframe::ABI::AMD64EndianLittle;
}
@@ -31,12 +34,22 @@ template <endianness E> class SFrameParser {
return false; // Not used in any currently defined ABI.
}
+ using FDERange = ArrayRef<sframe::FuncDescEntry<E>>;
+ Expected<FDERange> fdes() const;
+
+ // Decodes the start address of the given FDE, which must be one of the
+ // objects returned by the `fdes()` function.
+ uint64_t getAbsoluteStartAddress(typename FDERange::iterator FDE) const;
+
private:
ArrayRef<uint8_t> Data;
+ uint64_t SectionAddress;
const sframe::Header<E> &Header;
- SFrameParser(ArrayRef<uint8_t> Data, const sframe::Header<E> &Header)
- : Data(Data), Header(Header) {}
+ SFrameParser(ArrayRef<uint8_t> Data, uint64_t SectionAddress, const sframe::Header<E> &Header)
+ : Data(Data), SectionAddress(SectionAddress), Header(Header) {}
+
+ uint64_t getFDEBegin() const { return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff; }
};
extern template class SFrameParser<endianness::big>;
diff --git a/llvm/lib/BinaryFormat/SFrame.cpp b/llvm/lib/BinaryFormat/SFrame.cpp
index 3b436afd32083..f1765d7f3e852 100644
--- a/llvm/lib/BinaryFormat/SFrame.cpp
+++ b/llvm/lib/BinaryFormat/SFrame.cpp
@@ -35,3 +35,36 @@ ArrayRef<EnumEntry<sframe::ABI>> sframe::getABIs() {
};
return ArrayRef(ABIs);
}
+
+ArrayRef<EnumEntry<sframe::FREType>> sframe::getFRETypes() {
+ static constexpr EnumEntry<sframe::FREType> FRETypes[] = {
+#define HANDLE_SFRAME_FRE_TYPE(CODE, NAME) {#NAME, sframe::FREType::NAME},
+#include "llvm/BinaryFormat/SFrameConstants.def"
+ };
+ return ArrayRef(FRETypes);
+}
+
+ArrayRef<EnumEntry<sframe::FDEType>> sframe::getFDETypes() {
+ static constexpr EnumEntry<sframe::FDEType> FDETypes[] = {
+#define HANDLE_SFRAME_FDE_TYPE(CODE, NAME) {#NAME, sframe::FDEType::NAME},
+#include "llvm/BinaryFormat/SFrameConstants.def"
+ };
+ return ArrayRef(FDETypes);
+}
+
+ArrayRef<EnumEntry<sframe::AArch64PAuthKey>> sframe::getAArch64PAuthKeys() {
+ static constexpr EnumEntry<sframe::AArch64PAuthKey> AArch64PAuthKeys[] = {
+#define HANDLE_SFRAME_AARCH64_PAUTH_KEY(CODE, NAME) \
+ {#NAME, sframe::AArch64PAuthKey::NAME},
+#include "llvm/BinaryFormat/SFrameConstants.def"
+ };
+ return ArrayRef(AArch64PAuthKeys);
+}
+
+ArrayRef<EnumEntry<sframe::FREOffset>> sframe::getFREOffsets() {
+ static constexpr EnumEntry<sframe::FREOffset> FREOffsets[] = {
+#define HANDLE_SFRAME_FRE_OFFSET(CODE, NAME) {#NAME, sframe::FREOffset::NAME},
+#include "llvm/BinaryFormat/SFrameConstants.def"
+ };
+ return ArrayRef(FREOffsets);
+}
diff --git a/llvm/lib/Object/SFrameParser.cpp b/llvm/lib/Object/SFrameParser.cpp
index 2d74d1d6b3827..aa3c481d35db4 100644
--- a/llvm/lib/Object/SFrameParser.cpp
+++ b/llvm/lib/Object/SFrameParser.cpp
@@ -14,23 +14,34 @@
using namespace llvm;
using namespace llvm::object;
-template <typename T>
-static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
- uint64_t Offset) {
- static_assert(std::is_trivial_v<T>);
- if (Data.size() < Offset + sizeof(T)) {
+static Expected<ArrayRef<uint8_t>>
+getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size) {
+ // Check for overflow.
+ if (Offset + Size < Offset || Offset + Size < Size ||
+ Offset + Size > Data.size()) {
return createStringError(
formatv("unexpected end of data at offset {0:x} while reading [{1:x}, "
"{2:x})",
- Data.size(), Offset, Offset + sizeof(T))
+ Data.size(), Offset, Offset + Size)
.str(),
object_error::unexpected_eof);
}
- return *reinterpret_cast<const T *>(Data.data() + Offset);
+ 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) {
+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)
@@ -48,7 +59,42 @@ Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents) {
getDataSliceAs<sframe::Header<E>>(Contents, 0);
if (!Header)
return Header.takeError();
- return SFrameParser(Contents, *Header);
+ 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, getFDEBegin(), 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);
+ assert(FDEPtr < DataPtr + Data.size());
+
+ Result += FDEPtr - DataPtr;
+ }
+
+ return Result;
}
template class llvm::object::SFrameParser<endianness::big>;
diff --git a/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test b/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
new file mode 100644
index 0000000000000..294b28d8f04b4
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
@@ -0,0 +1,232 @@
+## Check parsing and dumping of SFrame Function Descriptor Entries.
+# RUN: yaml2obj --docnum=1 %s -o %t.1
+# RUN: llvm-readobj --sframe=.sframe_short --sframe=.sframe_section_relative \
+# RUN: --sframe=.sframe_fde_relative %t.1 2>&1 | \
+# RUN: FileCheck %s --strict-whitespace --match-full-lines \
+# RUN: -DFILE=%t.1 --check-prefix=CASE1
+
+## Check big-endian support.
+# RUN: yaml2obj --docnum=2 %s -o %t.2
+# RUN: llvm-readobj --sframe %t.2 2>&1 | \
+# RUN: FileCheck %s --strict-whitespace --match-full-lines \
+# RUN: -DFILE=%t.2 --check-prefix=CASE2
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+Sections:
+ - Name: .sframe_short
+ Type: SHT_GNU_SFRAME
+ Flags: [ SHF_ALLOC ]
+ ContentArray: [
+ 0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags)
+ # Header:
+ 0x03, 0x42, 0x47, 0x04, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
+ 0x01, 0x00, 0x00, 0x00, # Number of FDEs
+ 0x10, 0x00, 0x00, 0x00, # Number of FREs
+ 0x00, 0x10, 0x00, 0x00, # FRE length
+ 0x00, 0x00, 0x00, 0x00, # FDE offset
+ 0x00, 0x01, 0x00, 0x00, # FRE offset
+ 0xde, 0xad, 0xbe, 0xef, # AUX header
+ 0x01, 0x02, 0x03, 0x04, # Short FDE
+ ]
+# CASE1-LABEL:SFrame section '.sframe_short' {
+# CASE1: Header {
+# CASE1-NEXT: Magic: 0xDEE2
+# CASE1-NEXT: Version: V2 (0x2)
+# CASE1-NEXT: Flags [ (0x0)
+# CASE1-NEXT: ]
+# CASE1-NEXT: ABI: AMD64EndianLittle (0x3)
+# CASE1-NEXT: CFA fixed FP offset (unused): 66
+# CASE1-NEXT: CFA fixed RA offset: 71
+# CASE1-NEXT: Auxiliary header length: 4
+# CASE1-NEXT: Num FDEs: 1
+# CASE1-NEXT: Num FREs: 16
+# CASE1-NEXT: FRE subsection length: 4096
+# CASE1-NEXT: FDE subsection offset: 0
+# CASE1-NEXT: FRE subsection offset: 256
+# CASE1-NEXT: Auxiliary header: [0xDE, 0xAD, 0xBE, 0xEF]
+# CASE1-NEXT: }
+# CASE1-NEXT:{{.*}}: warning: '[[FILE]]': unexpected end of data at offset 0x24 while reading [0x20, 0x34)
+# CASE1-NEXT:}
+
+ - Name: .sframe_section_relative
+ Type: SHT_GNU_SFRAME
+ Flags: [ SHF_ALLOC ]
+ ContentArray: [
+ 0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags)
+ # Header:
+ 0x03, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
+ 0x01, 0x00, 0x00, 0x00, # Number of FDEs
+ 0x10, 0x00, 0x00, 0x00, # Number of FREs
+ 0x00, 0x10, 0x00, 0x00, # FRE length
+ 0x04, 0x00, 0x00, 0x00, # FDE offset
+ 0x00, 0x01, 0x00, 0x00, # FRE offset
+
+ 0xff, 0xff, 0xff, 0xff, # Unused data skipped due to the FDE offset field
+
+ # FDE:
+ 0x00, 0xde, 0xad, 0x00, # Start Address
+ 0xbe, 0x01, 0x00, 0x00, # Size
+ 0x10, 0x00, 0x00, 0x00, # Start FRE Offset
+ 0x00, 0x00, 0x00, 0x00, # Number of FREs
+ 0x31, 0xde, 0xad, 0x00, # Info, RepSize, Padding2
+ ]
+## Also testing:
+## - dead space between the header and the FDE subsection.
+## - PCMask FDE types
+## - unused PAuth key handling
+# CASE1-LABEL:SFrame section '.sframe_section_relative' {
+# CASE1: Header {
+# CASE1-NEXT: Magic: 0xDEE2
+# CASE1-NEXT: Version: V2 (0x2)
+# CASE1-NEXT: Flags [ (0x0)
+# CASE1-NEXT: ]
+# CASE1-NEXT: ABI: AMD64EndianLittle (0x3)
+# CASE1-NEXT: CFA fixed FP offset (unused): 66
+# CASE1-NEXT: CFA fixed RA offset: 71
+# CASE1-NEXT: Auxiliary header length: 0
+# CASE1-NEXT: Num FDEs: 1
+# CASE1-NEXT: Num FREs: 16
+# CASE1-NEXT: FRE subsection length: 4096
+# CASE1-NEXT: FDE subsection offset: 4
+# CASE1-NEXT: FRE subsection offset: 256
+# CASE1-NEXT: Auxiliary header: []
+# CASE1-NEXT: }
+# CASE1-NEXT: Function Index [
+# CASE1-NEXT: FuncDescEntry [0] {
+# CASE1-NEXT: PC: 0xADDE24
+# CASE1-NEXT: Size: 0x1BE
+# CASE1-NEXT: Start FRE Offset: 0x10
+# CASE1-NEXT: Num FREs: 0
+# CASE1-NEXT: Info: 0x31
+# CASE1-NEXT: FRE Type: Addr2 (0x1)
+# CASE1-NEXT: FDE Type: PCMask (0x1)
+# CASE1-NEXT: PAuth Key (unused): 1
+# CASE1-NEXT: Repetitive block size: 0xDE
+# CASE1-NEXT: Padding2: 0xAD
+# CASE1-NEXT: }
+# CASE1-NEXT: ]
+# CASE1-NEXT:}
+
+ - Name: .sframe_fde_relative
+ Type: SHT_GNU_SFRAME
+ Flags: [ SHF_ALLOC ]
+ ContentArray: [
+ 0xe2, 0xde, 0x02, 0x04, # Preamble (magic, version, flags)
+ # Header:
+ 0x02, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
+ 0x01, 0x00, 0x00, 0x00, # Number of FDEs
+ 0x10, 0x00, 0x00, 0x00, # Number of FREs
+ 0x00, 0x10, 0x00, 0x00, # FRE length
+ 0x04, 0x00, 0x00, 0x00, # FDE offset
+ 0x00, 0x01, 0x00, 0x00, # FRE offset
+
+ 0xff, 0xff, 0xff, 0xff, # Unused data skipped due to the FDE offset field
+
+ # FDE:
+ 0x00, 0xde, 0xad, 0x00, # Start Address
+ 0xbe, 0x01, 0x00, 0x00, # Size
+ 0x10, 0x00, 0x00, 0x00, # Start FRE Offset
+ 0x00, 0x00, 0x00, 0x00, # Number of FREs
+ 0x02, 0xde, 0xad, 0x00, # Info, RepSize, Padding2
+ ]
+## Also testing:
+## - PCInc FDE type
+## - AArch64 PAuth key handling
+# CASE1-LABEL:SFrame section '.sframe_fde_relative' {
+# CASE1: Header {
+# CASE1-NEXT: Magic: 0xDEE2
+# CASE1-NEXT: Version: V2 (0x2)
+# CASE1-NEXT: Flags [ (0x4)
+# CASE1-NEXT: FDEFuncStartPCRel (0x4){{ *}}
+# CASE1-NEXT: ]
+# CASE1-NEXT: ABI: AArch64EndianLittle (0x2)
+# CASE1-NEXT: CFA fixed FP offset (unused): 66
+# CASE1-NEXT: CFA fixed RA offset (unused): 71
+# CASE1-NEXT: Auxiliary header length: 0
+# CASE1-NEXT: Num FDEs: 1
+# CASE1-NEXT: Num FREs: 16
+# CASE1-NEXT: FRE subsection length: 4096
+# CASE1-NEXT: FDE subsection offset: 4
+# CASE1-NEXT: FRE subsection offset: 256
+# CASE1-NEXT: Auxiliary header: []
+# CASE1-NEXT: }
+# CASE1-NEXT: Function Index [
+# CASE1-NEXT: FuncDescEntry [0] {
+# CASE1-NEXT: PC: 0xADDE78
+# CASE1-NEXT: Size: 0x1BE
+# CASE1-NEXT: Start FRE Offset: 0x10
+# CASE1-NEXT: Num FREs: 0
+# CASE1-NEXT: Info: 0x2
+# CASE1-NEXT: FRE Type: Addr4 (0x2)
+# CASE1-NEXT: FDE Type: PCInc (0x0)
+# CASE1-NEXT: PAuth Key: A (0x0)
+# CASE1-NEXT: Repetitive block size (unused): 0xDE
+# CASE1-NEXT: Padding2: 0xAD
+# CASE1-NEXT: }
+# CASE1-NEXT: ]
+# CASE1-NEXT:}
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_EXEC
+Sections:
+ - Name: .sframe
+ Type: SHT_GNU_SFRAME
+ Flags: [ SHF_ALLOC ]
+ ContentArray: [
+ 0xde, 0xe2, 0x02, 0x05, # Preamble (magic, version, flags)
+ # Header:
+ 0x01, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
+ 0x00, 0x00, 0x00, 0x01, # Number of FDEs
+ 0x00, 0x00, 0x00, 0x10, # Number of FREs
+ 0x00, 0x00, 0x10, 0x00, # FRE length
+ 0x00, 0x00, 0x00, 0x00, # FDE offset
+ 0x00, 0x00, 0x01, 0x00, # FRE offset
+
+ # FDE:
+ 0x00, 0xde, 0xad, 0x00, # Start Address
+ 0x00, 0x00, 0x01, 0xbe, # Size
+ 0x00, 0x00, 0x00, 0x10, # Start FRE Offset
+ 0x00, 0x00, 0x00, 0x10, # Number of FREs
+ 0x02, 0xde, 0xad, 0x00, # Info, RepSize, Padding2
+ ]
+# CASE2-LABEL:SFrame section '.sframe' {
+# CASE2: Header {
+# CASE2-NEXT: Magic: 0xDEE2
+# CASE2-NEXT: Version: V2 (0x2)
+# CASE2-NEXT: Flags [ (0x5)
+# CASE2-NEXT: FDEFuncStartPCRel (0x4){{ *}}
+# CASE2-NEXT: FDESorted (0x1){{ *}}
+# CASE2-NEXT: ]
+# CASE2-NEXT: ABI: AArch64EndianBig (0x1)
+# CASE2-NEXT: CFA fixed FP offset (unused): 66
+# CASE2-NEXT: CFA fixed RA offset (unused): 71
+# CASE2-NEXT: Auxiliary header length: 0
+# CASE2-NEXT: Num FDEs: 1
+# CASE2-NEXT: Num FREs: 16
+# CASE2-NEXT: FRE subsection length: 4096
+# CASE2-NEXT: FDE subsection offset: 0
+# CASE2-NEXT: FRE subsection offset: 256
+# CASE2-NEXT: Auxiliary header: []
+# CASE2-NEXT: }
+# CASE2-NEXT: Function Index [
+# CASE2-NEXT: FuncDescEntry [0] {
+# CASE2-NEXT: PC: 0xDEAD1C
+# CASE2-NEXT: Size: 0x1BE
+# CASE2-NEXT: Start FRE Offset: 0x10
+# CASE2-NEXT: Num FREs: 16
+# CASE2-NEXT: Info: 0x2
+# CASE2-NEXT: FRE Type: Addr4 (0x2)
+# CASE2-NEXT: FDE Type: PCInc (0x0)
+# CASE2-NEXT: PAuth Key: A (0x0)
+# CASE2-NEXT: Repetitive block size (unused): 0xDE
+# CASE2-NEXT: Padding2: 0xAD00
+# CASE2-NEXT: }
+# CASE2-NEXT: ]
+# CASE2-NEXT:}
diff --git a/llvm/test/tools/llvm-readobj/ELF/sframe-header.test b/llvm/test/tools/llvm-readobj/ELF/sframe-header.test
index f827296b1c399..e7c0db0d957c1 100644
--- a/llvm/test/tools/llvm-readobj/ELF/sframe-header.test
+++ b/llvm/test/tools/llvm-readobj/ELF/sframe-header.test
@@ -2,7 +2,8 @@
# RUN: yaml2obj --docnum=1 %s -o %t.1
# RUN: llvm-readobj --sframe=.sframe_bad_sh_size --sframe=.sframe_1b \
# RUN: --sframe=.sframe_bad_magic --sframe=.sframe_bad_version \
-# RUN: --sframe=.sframe_6b --sframe=.sframe_header %t.1 2>&1 | \
+# RUN: --sframe=.sframe_6b --sframe=.sframe_short_auxheader \
+# RUN: --sframe=.sframe_header %t.1 2>&1 | \
# RUN: FileCheck %s --strict-whitespace --match-full-lines \
# RUN: -DFILE=%t.1 --check-prefix=CASE1
@@ -60,24 +61,24 @@ Sections:
0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags)
0x01, 0x02
]
-
# CASE1-LABEL:SFrame section '.sframe_6b' {
# CASE1:{{.*}}: warning: '[[FILE]]': invalid sframe section: unexpected end of data at offset 0x6 while reading [0x0, 0x1c)
- - Name: .sframe_header
+ - Name: .sframe_short_auxheader
Type: SHT_GNU_SFRAME
Flags: [ SHF_ALLOC ]
ContentArray: [
0xe2, 0xde, 0x02, 0x06, # Preamble (magic, version, flags)
# Header:
- 0x03, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
+ 0x03, 0x42, 0x47, 0x08, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
0x01, 0x00, 0x00, 0x00, # Number of FDEs
0x10, 0x00, 0x00, 0x00, # Number of FREs
0x00, 0x10, 0x00, 0x00, # FRE length
- 0x04, 0x00, 0x00, 0x00, # FDE offset
+ 0x00, 0x00, 0x00, 0x00, # FDE offset
0x00, 0x01, 0x00, 0x00, # FRE offset
+ 0xde, 0xad, 0xbe, 0xef, # AUX header
]
-# CASE1-LABEL:SFrame section '.sframe_header' {
+# CASE1-LABEL:SFrame section '.sframe_short_auxheader' {
# CASE1: Header {
# CASE1-NEXT: Magic: 0xDEE2
# CASE1-NEXT: Version: V2 (0x2)
@@ -88,13 +89,52 @@ Sections:
# CASE1-NEXT: ABI: AMD64EndianLittle (0x3)
# CASE1-NEXT: CFA fixed FP offset (unused): 66
# CASE1-NEXT: CFA fixed RA offset: 71
-# CASE1-NEXT: Auxiliary header length: 0
+# CASE1-NEXT: Auxiliary header length: 8
# CASE1-NEXT: Num FDEs: 1
# CASE1-NEXT: Num FREs: 16
# CASE1-NEXT: FRE subsection length: 4096
-# CASE1-NEXT: FDE subsection offset: 4
+# CASE1-NEXT: FDE subsection offset: 0
+# CASE1-NEXT: FRE subsection offset: 256
+# CASE1-NEXT:{{.*}}: warning: '[[FILE]]': unexpected end of data at offset 0x20 while reading [0x1c, 0x24)
+# CASE1-NEXT: }
+# CASE1-NEXT:{{.*}}: warning: '[[FILE]]': unexpected end of data at offset 0x20 while reading [0x24, 0x38)
+# CASE1-NEXT:}
+
+ - Name: .sframe_header
+ Type: SHT_GNU_SFRAME
+ Flags: [ SHF_ALLOC ]
+ ContentArray: [
+ 0xe2, 0xde, 0x02, 0x06, # Preamble (magic, version, flags)
+ # Header:
+ 0x03, 0x42, 0x47, 0x04, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
+ 0x00, 0x00, 0x00, 0x00, # Number of FDEs
+ 0x10, 0x00, 0x00, 0x00, # Number of FREs
+ 0x00, 0x10, 0x00, 0x00, # FRE length
+ 0x00, 0x00, 0x00, 0x00, # FDE offset
+ 0x00, 0x01, 0x00, 0x00, # FRE offset
+ 0xde, 0xad, 0xbe, 0xef, # AUX header
+ ]
+# CASE1-LABEL:SFrame section '.sframe_header' {
+# CASE1: Header {
+# CASE1-NEXT: Magic: 0xDEE2
+# CASE1-NEXT: Version: V2 (0x2)
+# CASE1-NEXT: Flags [ (0x6)
+# CASE1-NEXT: FDEFuncStartPCRel (0x4){{ *}}
+# CASE1-NEXT: FramePointer (0x2){{ *}}
+# CASE1-NEXT: ]
+# CASE1-NEXT: ABI: AMD64EndianLittle (0x3)
+# CASE1-NEXT: CFA fixed FP offset (unused): 66
+# CASE1-NEXT: CFA fixed RA offset: 71
+# CASE1-NEXT: Auxiliary header length: 4
+# CASE1-NEXT: Num FDEs: 0
+# CASE1-NEXT: Num FREs: 16
+# CASE1-NEXT: FRE subsection length: 4096
+# CASE1-NEXT: FDE subsection offset: 0
# CASE1-NEXT: FRE subsection offset: 256
+# CASE1-NEXT: Auxiliary header: [0xDE, 0xAD, 0xBE, 0xEF]
# CASE1-NEXT: }
+# CASE1-NEXT: Function Index [
+# CASE1-NEXT: ]
# CASE1-NEXT:}
--- !ELF
@@ -110,10 +150,10 @@ Sections:
0xde, 0xe2, 0x02, 0x01, # Preamble (magic, version, flags)
# Header:
0x01, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
- 0x00, 0x00, 0x00, 0x01, # Number of FDEs
+ 0x00, 0x00, 0x00, 0x00, # Number of FDEs
0x00, 0x00, 0x00, 0x10, # Number of FREs
0x00, 0x00, 0x10, 0x00, # FRE length
- 0x00, 0x00, 0x00, 0x04, # FDE offset
+ 0x00, 0x00, 0x00, 0x00, # FDE offset
0x00, 0x00, 0x01, 0x00, # FRE offset
]
# CASE2-LABEL:SFrame section '.sframe' {
@@ -127,12 +167,15 @@ Sections:
# CASE2-NEXT: CFA fixed FP offset (unused): 66
# CASE2-NEXT: CFA fixed RA offset (unused): 71
# CASE2-NEXT: Auxiliary header length: 0
-# CASE2-NEXT: Num FDEs: 1
+# CASE2-NEXT: Num FDEs: 0
# CASE2-NEXT: Num FREs: 16
# CASE2-NEXT: FRE subsection length: 4096
-# CASE2-NEXT: FDE subsection offset: 4
+# CASE2-NEXT: FDE subsection offset: 0
# CASE2-NEXT: FRE subsection offset: 256
+# CASE2-NEXT: Auxiliary header: []
# CASE2-NEXT: }
+# CASE2-NEXT: Function Index [
+# CASE2-NEXT: ]
# CASE2-NEXT:}
--- !ELF
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 2867d48a400da..fd48958dade45 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -424,6 +424,9 @@ template <typename ELFT> class ELFDumper : public ObjDumper {
ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const;
+ void printSFrameHeader(const SFrameParser<ELFT::Endianness> &Parser);
+ void printSFrameFDEs(const SFrameParser<ELFT::Endianness> &Parser);
+
private:
mutable SmallVector<std::optional<VersionEntry>, 0> VersionMap;
};
@@ -6433,6 +6436,86 @@ template <typename ELFT> void ELFDumper<ELFT>::printMemtag() {
printMemtag(DynamicEntries, AndroidNoteDesc, GlobalDescriptors);
}
+template <typename ELFT>
+void ELFDumper<ELFT>::printSFrameHeader(
+ const SFrameParser<ELFT::Endianness> &Parser) {
+ DictScope HeaderScope(W, "Header");
+
+ const sframe::Preamble<ELFT::Endianness> &Preamble = Parser.getPreamble();
+ W.printHex("Magic", Preamble.Magic.value());
+ W.printEnum("Version", Preamble.Version.value(), sframe::getVersions());
+ W.printFlags("Flags", Preamble.Flags.value(), sframe::getFlags());
+
+ const sframe::Header<ELFT::Endianness> &Header = Parser.getHeader();
+ W.printEnum("ABI", Header.ABIArch.value(), sframe::getABIs());
+
+ W.printNumber(("CFA fixed FP offset" +
+ Twine(Parser.usesFixedFPOffset() ? "" : " (unused)"))
+ .str(),
+ Header.CFAFixedFPOffset.value());
+
+ W.printNumber(("CFA fixed RA offset" +
+ Twine(Parser.usesFixedRAOffset() ? "" : " (unused)"))
+ .str(),
+ Header.CFAFixedRAOffset.value());
+
+ W.printNumber("Auxiliary header length", Header.AuxHdrLen.value());
+ W.printNumber("Num FDEs", Header.NumFDEs.value());
+ W.printNumber("Num FREs", Header.NumFREs.value());
+ W.printNumber("FRE subsection length", Header.FRELen.value());
+ W.printNumber("FDE subsection offset", Header.FDEOff.value());
+ W.printNumber("FRE subsection offset", Header.FREOff.value());
+
+ if (Expected<ArrayRef<uint8_t>> Aux = Parser.getAuxHeader())
+ W.printHexList("Auxiliary header", *Aux);
+ else
+ reportWarning(Aux.takeError(), FileName);
+}
+
+template <typename ELFT>
+void ELFDumper<ELFT>::printSFrameFDEs(
+ const SFrameParser<ELFT::Endianness> &Parser) {
+ typename SFrameParser<ELFT::Endianness>::FDERange FDEs;
+ if (Error Err = Parser.fdes().moveInto(FDEs)) {
+ reportWarning(std::move(Err), FileName);
+ return;
+ }
+
+ ListScope IndexScope(W, "Function Index");
+ for (auto It = FDEs.begin(); It != FDEs.end(); ++It) {
+ DictScope FDEScope(
+ W,
+ formatv("FuncDescEntry [{0}]", std::distance(FDEs.begin(), It)).str());
+
+ W.printHex("PC", Parser.getAbsoluteStartAddress(It));
+ W.printHex("Size", It->Size);
+ W.printHex("Start FRE Offset", It->StartFREOff);
+ W.printNumber("Num FREs", It->NumFREs);
+
+ W.printHex("Info", It->Info);
+ W.printEnum("FRE Type", It->getFREType(), sframe::getFRETypes());
+ W.printEnum("FDE Type", It->getFDEType(), sframe::getFDETypes());
+ switch (Parser.getHeader().ABIArch) {
+ case sframe::ABI::AArch64EndianBig:
+ case sframe::ABI::AArch64EndianLittle:
+ W.printEnum("PAuth Key", sframe::AArch64PAuthKey(It->getPAuthKey()),
+ sframe::getAArch64PAuthKeys());
+ break;
+ default:
+ W.printNumber("PAuth Key (unused)", It->getPAuthKey());
+ break;
+ }
+
+ W.printHex(
+ ("Repetitive block size" +
+ Twine(It->getFDEType() == sframe::FDEType::PCMask ? "" : " (unused)"))
+ .str(),
+ It->RepSize);
+
+ W.printHex("Padding2", It->Padding2);
+ }
+}
+
template <typename ELFT>
void ELFDumper<ELFT>::printSectionsAsSFrame(ArrayRef<std::string> Sections) {
constexpr endianness E = ELFT::Endianness;
@@ -6450,8 +6533,8 @@ void ELFDumper<ELFT>::printSectionsAsSFrame(ArrayRef<std::string> Sections) {
continue;
}
- Expected<object::SFrameParser<E>> Parser =
- object::SFrameParser<E>::create(arrayRefFromStringRef(SectionContent));
+ Expected<object::SFrameParser<E>> Parser = object::SFrameParser<E>::create(
+ arrayRefFromStringRef(SectionContent), Section.getAddress());
if (!Parser) {
reportWarning(createError("invalid sframe section: " +
toString(Parser.takeError())),
@@ -6459,32 +6542,8 @@ void ELFDumper<ELFT>::printSectionsAsSFrame(ArrayRef<std::string> Sections) {
continue;
}
- DictScope HeaderScope(W, "Header");
-
- const sframe::Preamble<E> &Preamble = Parser->getPreamble();
- W.printHex("Magic", Preamble.Magic.value());
- W.printEnum("Version", Preamble.Version.value(), sframe::getVersions());
- W.printFlags("Flags", Preamble.Flags.value(), sframe::getFlags());
-
- const sframe::Header<E> &Header = Parser->getHeader();
- W.printEnum("ABI", Header.ABIArch.value(), sframe::getABIs());
-
- W.printNumber(("CFA fixed FP offset" +
- Twine(Parser->usesFixedFPOffset() ? "" : " (unused)"))
- .str(),
- Header.CFAFixedFPOffset.value());
-
- W.printNumber(("CFA fixed RA offset" +
- Twine(Parser->usesFixedRAOffset() ? "" : " (unused)"))
- .str(),
- Header.CFAFixedRAOffset.value());
-
- W.printNumber("Auxiliary header length", Header.AuxHdrLen.value());
- W.printNumber("Num FDEs", Header.NumFDEs.value());
- W.printNumber("Num FREs", Header.NumFREs.value());
- W.printNumber("FRE subsection length", Header.FRELen.value());
- W.printNumber("FDE subsection offset", Header.FDEOff.value());
- W.printNumber("FRE subsection offset", Header.FREOff.value());
+ printSFrameHeader(*Parser);
+ printSFrameFDEs(*Parser);
}
}
>From fa55874b324d68e2347f0dfb13eb42820574c6b4 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 21 Jul 2025 14:55:38 +0000
Subject: [PATCH 2/4] format
---
llvm/include/llvm/Object/SFrameParser.h | 7 +++++--
llvm/lib/Object/SFrameParser.cpp | 13 +++++++------
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/Object/SFrameParser.h b/llvm/include/llvm/Object/SFrameParser.h
index 974c757419334..c55cf8198ddca 100644
--- a/llvm/include/llvm/Object/SFrameParser.h
+++ b/llvm/include/llvm/Object/SFrameParser.h
@@ -46,10 +46,13 @@ template <endianness E> class SFrameParser {
uint64_t SectionAddress;
const sframe::Header<E> &Header;
- SFrameParser(ArrayRef<uint8_t> Data, uint64_t SectionAddress, const sframe::Header<E> &Header)
+ SFrameParser(ArrayRef<uint8_t> Data, uint64_t SectionAddress,
+ const sframe::Header<E> &Header)
: Data(Data), SectionAddress(SectionAddress), Header(Header) {}
- uint64_t getFDEBegin() const { return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff; }
+ uint64_t getFDEBegin() const {
+ return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff;
+ }
};
extern template class SFrameParser<endianness::big>;
diff --git a/llvm/lib/Object/SFrameParser.cpp b/llvm/lib/Object/SFrameParser.cpp
index aa3c481d35db4..fbe35d6d81b6f 100644
--- a/llvm/lib/Object/SFrameParser.cpp
+++ b/llvm/lib/Object/SFrameParser.cpp
@@ -41,7 +41,8 @@ static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
}
template <endianness E>
-Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents, uint64_t SectionAddress) {
+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)
@@ -62,13 +63,12 @@ Expected<SFrameParser<E>> SFrameParser<E>::create(ArrayRef<uint8_t> Contents, ui
return SFrameParser(Contents, SectionAddress, *Header);
}
-
-template<endianness E>
+template <endianness E>
Expected<ArrayRef<uint8_t>> SFrameParser<E>::getAuxHeader() const {
return getDataSlice(Data, sizeof(Header), Header.AuxHdrLen);
}
-template<endianness E>
+template <endianness E>
Expected<ArrayRef<sframe::FuncDescEntry<E>>> SFrameParser<E>::fdes() const {
Expected<ArrayRef<uint8_t>> Slice = getDataSlice(
Data, getFDEBegin(), Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>));
@@ -79,8 +79,9 @@ Expected<ArrayRef<sframe::FuncDescEntry<E>>> SFrameParser<E>::fdes() const {
Header.NumFDEs);
}
-template<endianness E>
-uint64_t SFrameParser<E>::getAbsoluteStartAddress(typename FDERange::iterator FDE) const {
+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) ==
>From c9845ee8de80c2c9a063188096090f6e3aa8f76a Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 24 Jul 2025 16:39:24 +0200
Subject: [PATCH 3/4] saturate, scope
---
llvm/lib/Object/SFrameParser.cpp | 10 ++++---
.../tools/llvm-readobj/ELF/sframe-fde.test | 29 +++++++++++--------
llvm/tools/llvm-readobj/ELFDumper.cpp | 28 ++++++++++--------
3 files changed, 39 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Object/SFrameParser.cpp b/llvm/lib/Object/SFrameParser.cpp
index fbe35d6d81b6f..bf0e2dc7e3629 100644
--- a/llvm/lib/Object/SFrameParser.cpp
+++ b/llvm/lib/Object/SFrameParser.cpp
@@ -10,19 +10,21 @@
#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) {
- // Check for overflow.
- if (Offset + Size < Offset || Offset + Size < Size ||
- Offset + Size > Data.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, Offset + Size)
+ Data.size(), Offset, End)
.str(),
object_error::unexpected_eof);
}
diff --git a/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test b/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
index 294b28d8f04b4..dee40180c42e6 100644
--- a/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
+++ b/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
@@ -101,10 +101,11 @@ Sections:
# CASE1-NEXT: Size: 0x1BE
# CASE1-NEXT: Start FRE Offset: 0x10
# CASE1-NEXT: Num FREs: 0
-# CASE1-NEXT: Info: 0x31
-# CASE1-NEXT: FRE Type: Addr2 (0x1)
-# CASE1-NEXT: FDE Type: PCMask (0x1)
-# CASE1-NEXT: PAuth Key (unused): 1
+# CASE1-NEXT: Info {
+# CASE1-NEXT: FRE Type: Addr2 (0x1)
+# CASE1-NEXT: FDE Type: PCMask (0x1)
+# CASE1-NEXT: Raw: 0x31
+# CASE1-NEXT: }
# CASE1-NEXT: Repetitive block size: 0xDE
# CASE1-NEXT: Padding2: 0xAD
# CASE1-NEXT: }
@@ -160,10 +161,12 @@ Sections:
# CASE1-NEXT: Size: 0x1BE
# CASE1-NEXT: Start FRE Offset: 0x10
# CASE1-NEXT: Num FREs: 0
-# CASE1-NEXT: Info: 0x2
-# CASE1-NEXT: FRE Type: Addr4 (0x2)
-# CASE1-NEXT: FDE Type: PCInc (0x0)
-# CASE1-NEXT: PAuth Key: A (0x0)
+# CASE1-NEXT: Info {
+# CASE1-NEXT: FRE Type: Addr4 (0x2)
+# CASE1-NEXT: FDE Type: PCInc (0x0)
+# CASE1-NEXT: PAuth Key: A (0x0)
+# CASE1-NEXT: Raw: 0x2
+# CASE1-NEXT: }
# CASE1-NEXT: Repetitive block size (unused): 0xDE
# CASE1-NEXT: Padding2: 0xAD
# CASE1-NEXT: }
@@ -221,10 +224,12 @@ Sections:
# CASE2-NEXT: Size: 0x1BE
# CASE2-NEXT: Start FRE Offset: 0x10
# CASE2-NEXT: Num FREs: 16
-# CASE2-NEXT: Info: 0x2
-# CASE2-NEXT: FRE Type: Addr4 (0x2)
-# CASE2-NEXT: FDE Type: PCInc (0x0)
-# CASE2-NEXT: PAuth Key: A (0x0)
+# CASE2-NEXT: Info {
+# CASE2-NEXT: FRE Type: Addr4 (0x2)
+# CASE2-NEXT: FDE Type: PCInc (0x0)
+# CASE2-NEXT: PAuth Key: A (0x0)
+# CASE2-NEXT: Raw: 0x2
+# CASE2-NEXT: }
# CASE2-NEXT: Repetitive block size (unused): 0xDE
# CASE2-NEXT: Padding2: 0xAD00
# CASE2-NEXT: }
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 41c7f04fd194a..94ce38605f5c9 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -6498,18 +6498,22 @@ void ELFDumper<ELFT>::printSFrameFDEs(
W.printHex("Start FRE Offset", It->StartFREOff);
W.printNumber("Num FREs", It->NumFREs);
- W.printHex("Info", It->Info);
- W.printEnum("FRE Type", It->getFREType(), sframe::getFRETypes());
- W.printEnum("FDE Type", It->getFDEType(), sframe::getFDETypes());
- switch (Parser.getHeader().ABIArch) {
- case sframe::ABI::AArch64EndianBig:
- case sframe::ABI::AArch64EndianLittle:
- W.printEnum("PAuth Key", sframe::AArch64PAuthKey(It->getPAuthKey()),
- sframe::getAArch64PAuthKeys());
- break;
- default:
- W.printNumber("PAuth Key (unused)", It->getPAuthKey());
- break;
+ {
+ DictScope InfoScope(W, "Info");
+ W.printEnum("FRE Type", It->getFREType(), sframe::getFRETypes());
+ W.printEnum("FDE Type", It->getFDEType(), sframe::getFDETypes());
+ switch (Parser.getHeader().ABIArch) {
+ case sframe::ABI::AArch64EndianBig:
+ case sframe::ABI::AArch64EndianLittle:
+ W.printEnum("PAuth Key", sframe::AArch64PAuthKey(It->getPAuthKey()),
+ sframe::getAArch64PAuthKeys());
+ break;
+ case sframe::ABI::AMD64EndianLittle:
+ // unused
+ break;
+ }
+
+ W.printHex("Raw", It->Info);
}
W.printHex(
>From ee148a6bf530f520e409762d522906b5c6c481b7 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 30 Jul 2025 09:25:20 +0200
Subject: [PATCH 4/4] s/getFDEBegin/getFDEBase
---
llvm/include/llvm/Object/SFrameParser.h | 2 +-
llvm/lib/Object/SFrameParser.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Object/SFrameParser.h b/llvm/include/llvm/Object/SFrameParser.h
index 05d213c971c7e..245e7ba40d0b8 100644
--- a/llvm/include/llvm/Object/SFrameParser.h
+++ b/llvm/include/llvm/Object/SFrameParser.h
@@ -51,7 +51,7 @@ template <endianness E> class SFrameParser {
const sframe::Header<E> &Header)
: Data(Data), SectionAddress(SectionAddress), Header(Header) {}
- uint64_t getFDEBegin() const {
+ uint64_t getFDEBase() const {
return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff;
}
};
diff --git a/llvm/lib/Object/SFrameParser.cpp b/llvm/lib/Object/SFrameParser.cpp
index bc9a1a10ca4d7..1befac0b8eddf 100644
--- a/llvm/lib/Object/SFrameParser.cpp
+++ b/llvm/lib/Object/SFrameParser.cpp
@@ -73,7 +73,7 @@ Expected<ArrayRef<uint8_t>> SFrameParser<E>::getAuxHeader() const {
template <endianness E>
Expected<ArrayRef<sframe::FuncDescEntry<E>>> SFrameParser<E>::fdes() const {
Expected<ArrayRef<uint8_t>> Slice = getDataSlice(
- Data, getFDEBegin(), Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>));
+ Data, getFDEBase(), Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>));
if (!Slice)
return Slice.takeError();
return ArrayRef(
More information about the llvm-commits
mailing list