[llvm] Reapply "[Object] Parsing and dumping of SFrame Frame Row Entries" (#152650) (PR #152695)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 8 04:56:01 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-binary-utilities

Author: Pavel Labath (labath)

<details>
<summary>Changes</summary>

This reapplies #<!-- -->152650 with a build fix for clang-11 (need explicit template parameters for ArrayRef construction) and avoiding the default-in-a-switch-covering-enum warning. It also adds two new tests.

The original commit message was:

The trickiest part here is that the FREs have a variable size, in two (or three?) dimensions:
- the size of the StartAddress field. This determined by the FDE they are in, so it is uniform across all FREs in one FDE.
- the number and sizes of offsets following the FRE. This can be different for each FRE.
    
While vending this information through a template API would be possible, I believe such an approach would be very unwieldy, and it would still require a sequential scan through the FRE list. This is why I'm implementing this by reading the data into a common data structure using the fallible iterator pattern.
    
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).


---

Patch is 24.61 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/152695.diff


7 Files Affected:

- (modified) llvm/include/llvm/BinaryFormat/SFrame.h (+1) 
- (modified) llvm/include/llvm/Object/SFrameParser.h (+51) 
- (modified) llvm/lib/BinaryFormat/SFrame.cpp (+8) 
- (modified) llvm/lib/Object/SFrameParser.cpp (+129-4) 
- (modified) llvm/test/tools/llvm-readobj/ELF/sframe-fde.test (+8-2) 
- (added) llvm/test/tools/llvm-readobj/ELF/sframe-fre.test (+303) 
- (modified) llvm/tools/llvm-readobj/ELFDumper.cpp (+28-1) 


``````````diff
diff --git a/llvm/include/llvm/BinaryFormat/SFrame.h b/llvm/include/llvm/BinaryFormat/SFrame.h
index 0c6c4d176eaec..74e47ea8acca9 100644
--- a/llvm/include/llvm/BinaryFormat/SFrame.h
+++ b/llvm/include/llvm/BinaryFormat/SFrame.h
@@ -169,6 +169,7 @@ LLVM_ABI ArrayRef<EnumEntry<FREType>> getFRETypes();
 LLVM_ABI ArrayRef<EnumEntry<FDEType>> getFDETypes();
 LLVM_ABI ArrayRef<EnumEntry<AArch64PAuthKey>> getAArch64PAuthKeys();
 LLVM_ABI ArrayRef<EnumEntry<FREOffset>> getFREOffsets();
+LLVM_ABI ArrayRef<EnumEntry<BaseReg>> getBaseRegisters();
 
 } // namespace sframe
 } // namespace llvm
diff --git a/llvm/include/llvm/Object/SFrameParser.h b/llvm/include/llvm/Object/SFrameParser.h
index 245e7ba40d0b8..539bb1872cc99 100644
--- a/llvm/include/llvm/Object/SFrameParser.h
+++ b/llvm/include/llvm/Object/SFrameParser.h
@@ -10,6 +10,7 @@
 #define LLVM_OBJECT_SFRAME_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/fallible_iterator.h"
 #include "llvm/BinaryFormat/SFrame.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Error.h"
@@ -19,6 +20,8 @@ namespace llvm {
 namespace object {
 
 template <endianness E> class SFrameParser {
+  class FallibleFREIterator;
+
 public:
   static Expected<SFrameParser> create(ArrayRef<uint8_t> Contents,
                                        uint64_t SectionAddress);
@@ -42,6 +45,21 @@ template <endianness E> class SFrameParser {
   // objects returned by the `fdes()` function.
   uint64_t getAbsoluteStartAddress(typename FDERange::iterator FDE) const;
 
+  struct FrameRowEntry {
+    uint32_t StartAddress;
+    sframe::FREInfo<endianness::native> Info;
+    SmallVector<int32_t, 3> Offsets;
+  };
+
+  using fre_iterator = fallible_iterator<FallibleFREIterator>;
+  iterator_range<fre_iterator> fres(const sframe::FuncDescEntry<E> &FDE,
+                                    Error &Err) const;
+
+  std::optional<int32_t> getCFAOffset(const FrameRowEntry &FRE) const;
+  std::optional<int32_t> getRAOffset(const FrameRowEntry &FRE) const;
+  std::optional<int32_t> getFPOffset(const FrameRowEntry &FRE) const;
+  ArrayRef<int32_t> getExtraOffsets(const FrameRowEntry &FRE) const;
+
 private:
   ArrayRef<uint8_t> Data;
   uint64_t SectionAddress;
@@ -54,6 +72,39 @@ template <endianness E> class SFrameParser {
   uint64_t getFDEBase() const {
     return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff;
   }
+
+  uint64_t getFREBase() const {
+    return getFDEBase() + Header.NumFDEs * sizeof(sframe::FuncDescEntry<E>);
+  }
+};
+
+template <endianness E> class SFrameParser<E>::FallibleFREIterator {
+public:
+  // NB: This iterator starts out in the before_begin() state. It must be
+  // ++'ed to reach the first element.
+  FallibleFREIterator(ArrayRef<uint8_t> Data, sframe::FREType FREType,
+                      uint32_t Idx, uint32_t Size, uint64_t Offset)
+      : Data(Data), FREType(FREType), Idx(Idx), Size(Size), Offset(Offset) {}
+
+  Error inc();
+  const FrameRowEntry &operator*() const { return FRE; }
+
+  friend bool operator==(const FallibleFREIterator &LHS,
+                         const FallibleFREIterator &RHS) {
+    assert(LHS.Data.data() == RHS.Data.data());
+    assert(LHS.Data.size() == RHS.Data.size());
+    assert(LHS.FREType == RHS.FREType);
+    assert(LHS.Size == RHS.Size);
+    return LHS.Idx == RHS.Idx;
+  }
+
+private:
+  ArrayRef<uint8_t> Data;
+  sframe::FREType FREType;
+  uint32_t Idx;
+  uint32_t Size;
+  uint64_t Offset;
+  FrameRowEntry FRE;
 };
 
 extern template class LLVM_TEMPLATE_ABI SFrameParser<endianness::big>;
diff --git a/llvm/lib/BinaryFormat/SFrame.cpp b/llvm/lib/BinaryFormat/SFrame.cpp
index f1765d7f3e852..8076a26f27f32 100644
--- a/llvm/lib/BinaryFormat/SFrame.cpp
+++ b/llvm/lib/BinaryFormat/SFrame.cpp
@@ -68,3 +68,11 @@ ArrayRef<EnumEntry<sframe::FREOffset>> sframe::getFREOffsets() {
   };
   return ArrayRef(FREOffsets);
 }
+
+ArrayRef<EnumEntry<sframe::BaseReg>> sframe::getBaseRegisters() {
+  static constexpr EnumEntry<sframe::BaseReg> BaseRegs[] = {
+      {"FP", sframe::BaseReg::FP},
+      {"SP", sframe::BaseReg::SP},
+  };
+  return ArrayRef(BaseRegs);
+}
diff --git a/llvm/lib/Object/SFrameParser.cpp b/llvm/lib/Object/SFrameParser.cpp
index 5863490634e32..847067a7ae989 100644
--- a/llvm/lib/Object/SFrameParser.cpp
+++ b/llvm/lib/Object/SFrameParser.cpp
@@ -32,14 +32,25 @@ getDataSlice(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Size) {
 }
 
 template <typename T>
-static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
-                                          uint64_t Offset) {
+static Expected<ArrayRef<T>>
+getDataSliceAsArrayOf(ArrayRef<uint8_t> Data, uint64_t Offset, uint64_t Count) {
   static_assert(std::is_trivial_v<T>);
-  Expected<ArrayRef<uint8_t>> Slice = getDataSlice(Data, Offset, sizeof(T));
+  Expected<ArrayRef<uint8_t>> Slice =
+      getDataSlice(Data, Offset, sizeof(T) * Count);
   if (!Slice)
     return Slice.takeError();
 
-  return *reinterpret_cast<const T *>(Slice->data());
+  return ArrayRef(reinterpret_cast<const T *>(Slice->data()), Count);
+}
+
+template <typename T>
+static Expected<const T &> getDataSliceAs(ArrayRef<uint8_t> Data,
+                                          uint64_t Offset) {
+  Expected<ArrayRef<T>> Array = getDataSliceAsArrayOf<T>(Data, Offset, 1);
+  if (!Array)
+    return Array.takeError();
+
+  return Array->front();
 }
 
 template <endianness E>
@@ -100,6 +111,120 @@ uint64_t SFrameParser<E>::getAbsoluteStartAddress(
   return Result;
 }
 
+template <typename EndianT>
+static Error readArray(ArrayRef<uint8_t> Data, uint64_t Count, uint64_t &Offset,
+                       SmallVectorImpl<int32_t> &Vec) {
+  Expected<ArrayRef<EndianT>> RawArray =
+      getDataSliceAsArrayOf<EndianT>(Data, Offset, Count);
+  if (!RawArray)
+    return RawArray.takeError();
+  Offset += Count * sizeof(EndianT);
+  Vec.resize(Count);
+  llvm::copy(*RawArray, Vec.begin());
+  return Error::success();
+}
+
+template <typename T, endianness E>
+static Error readFRE(ArrayRef<uint8_t> Data, uint64_t &Offset,
+                     typename SFrameParser<E>::FrameRowEntry &FRE) {
+  Expected<sframe::FrameRowEntry<T, E>> RawFRE =
+      getDataSliceAs<sframe::FrameRowEntry<T, E>>(Data, Offset);
+  if (!RawFRE)
+    return RawFRE.takeError();
+
+  Offset += sizeof(*RawFRE);
+  FRE.StartAddress = RawFRE->StartAddress;
+  FRE.Info.Info = RawFRE->Info.Info;
+
+  switch (FRE.Info.getOffsetSize()) {
+  case sframe::FREOffset::B1:
+    return readArray<sframe::detail::packed<int8_t, E>>(
+        Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets);
+  case sframe::FREOffset::B2:
+    return readArray<sframe::detail::packed<int16_t, E>>(
+        Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets);
+  case sframe::FREOffset::B4:
+    return readArray<sframe::detail::packed<int32_t, E>>(
+        Data, FRE.Info.getOffsetCount(), Offset, FRE.Offsets);
+  }
+  return createError(formatv("unsupported FRE offset size {0} at offset {1:x+}",
+                             static_cast<unsigned>(FRE.Info.getOffsetSize()),
+                             Offset));
+}
+
+template <endianness E> Error SFrameParser<E>::FallibleFREIterator::inc() {
+  if (++Idx == Size)
+    return Error::success();
+
+  switch (FREType) {
+  case sframe::FREType::Addr1:
+    return readFRE<uint8_t, E>(Data, Offset, FRE);
+  case sframe::FREType::Addr2:
+    return readFRE<uint16_t, E>(Data, Offset, FRE);
+  case sframe::FREType::Addr4:
+    return readFRE<uint32_t, E>(Data, Offset, FRE);
+  }
+  return createError(formatv("unsupported FRE type {0} at offset {1:x+}",
+                             static_cast<unsigned>(FREType), Offset));
+}
+
+template <endianness E>
+iterator_range<typename SFrameParser<E>::fre_iterator>
+SFrameParser<E>::fres(const sframe::FuncDescEntry<E> &FDE, Error &Err) const {
+  uint64_t Offset = getFREBase() + FDE.StartFREOff;
+  fre_iterator BeforeBegin = make_fallible_itr(
+      FallibleFREIterator(Data, FDE.getFREType(), -1, FDE.NumFREs, Offset),
+      Err);
+  fre_iterator End = make_fallible_end(
+      FallibleFREIterator(Data, FDE.getFREType(), FDE.NumFREs, FDE.NumFREs,
+                          /*Offset=*/0));
+  return {++BeforeBegin, End};
+}
+
+static std::optional<int32_t> getOffset(ArrayRef<int32_t> Offsets, size_t Idx) {
+  if (Offsets.size() > Idx)
+    return Offsets[Idx];
+  return std::nullopt;
+}
+
+// The interpretation of offsets is ABI-specific. The implementation of this and
+// the following functions may need to be adjusted when adding support for a new
+// ABI.
+template <endianness E>
+std::optional<int32_t>
+SFrameParser<E>::getCFAOffset(const FrameRowEntry &FRE) const {
+  return getOffset(FRE.Offsets, 0);
+}
+
+template <endianness E>
+std::optional<int32_t>
+SFrameParser<E>::getRAOffset(const FrameRowEntry &FRE) const {
+  if (usesFixedRAOffset())
+    return Header.CFAFixedRAOffset;
+  return getOffset(FRE.Offsets, 1);
+}
+
+template <endianness E>
+std::optional<int32_t>
+SFrameParser<E>::getFPOffset(const FrameRowEntry &FRE) const {
+  if (usesFixedFPOffset())
+    return Header.CFAFixedFPOffset;
+  return getOffset(FRE.Offsets, usesFixedRAOffset() ? 1 : 2);
+}
+
+template <endianness E>
+ArrayRef<int32_t>
+SFrameParser<E>::getExtraOffsets(const FrameRowEntry &FRE) const {
+  size_t UsedOffsets = 1; // CFA
+  if (!usesFixedRAOffset())
+    ++UsedOffsets;
+  if (!usesFixedFPOffset())
+    ++UsedOffsets;
+  if (FRE.Offsets.size() > UsedOffsets)
+    return ArrayRef<int32_t>(FRE.Offsets).drop_front(UsedOffsets);
+  return {};
+}
+
 template class LLVM_EXPORT_TEMPLATE llvm::object::SFrameParser<endianness::big>;
 template class LLVM_EXPORT_TEMPLATE
     llvm::object::SFrameParser<endianness::little>;
diff --git a/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test b/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
index dee40180c42e6..b9075a81eba4b 100644
--- a/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
+++ b/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test
@@ -108,6 +108,8 @@ Sections:
 #  CASE1-NEXT:      }
 #  CASE1-NEXT:      Repetitive block size: 0xDE
 #  CASE1-NEXT:      Padding2: 0xAD
+#  CASE1-NEXT:      FREs [
+#  CASE1-NEXT:      ]
 #  CASE1-NEXT:    }
 #  CASE1-NEXT:  ]
 #  CASE1-NEXT:}
@@ -169,6 +171,8 @@ Sections:
 #  CASE1-NEXT:      }
 #  CASE1-NEXT:      Repetitive block size (unused): 0xDE
 #  CASE1-NEXT:      Padding2: 0xAD
+#  CASE1-NEXT:      FREs [
+#  CASE1-NEXT:      ]
 #  CASE1-NEXT:    }
 #  CASE1-NEXT:  ]
 #  CASE1-NEXT:}
@@ -196,7 +200,7 @@ Sections:
       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
+      0x00, 0x00, 0x00, 0x00,  # Number of FREs
       0x02, 0xde, 0xad, 0x00,  # Info, RepSize, Padding2
     ]
 # CASE2-LABEL:SFrame section '.sframe' {
@@ -223,7 +227,7 @@ Sections:
 #  CASE2-NEXT:      PC: 0xDEAD1C
 #  CASE2-NEXT:      Size: 0x1BE
 #  CASE2-NEXT:      Start FRE Offset: 0x10
-#  CASE2-NEXT:      Num FREs: 16
+#  CASE2-NEXT:      Num FREs: 0
 #  CASE2-NEXT:      Info {
 #  CASE2-NEXT:        FRE Type: Addr4 (0x2)
 #  CASE2-NEXT:        FDE Type: PCInc (0x0)
@@ -232,6 +236,8 @@ Sections:
 #  CASE2-NEXT:      }
 #  CASE2-NEXT:      Repetitive block size (unused): 0xDE
 #  CASE2-NEXT:      Padding2: 0xAD00
+#  CASE2-NEXT:      FREs [
+#  CASE2-NEXT:      ]
 #  CASE2-NEXT:    }
 #  CASE2-NEXT:  ]
 #  CASE2-NEXT:}
diff --git a/llvm/test/tools/llvm-readobj/ELF/sframe-fre.test b/llvm/test/tools/llvm-readobj/ELF/sframe-fre.test
new file mode 100644
index 0000000000000..3f1e7d667f47e
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/sframe-fre.test
@@ -0,0 +1,303 @@
+# RUN: yaml2obj --docnum=1 %s -o %t.1
+# RUN: llvm-readobj --sframe=.sframe_eof_address --sframe=.sframe_eof_offset --sframe \
+# RUN:   %t.1 2>&1 | \
+# RUN:   FileCheck %s --strict-whitespace --match-full-lines \
+# RUN:   -DFILE=%t.1 --check-prefix=CASE1
+
+# 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_eof_address
+    Type:  SHT_GNU_SFRAME
+    Flags: [ SHF_ALLOC ]
+    ContentArray: [
+      0xe2, 0xde, 0x02, 0x04,  # 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
+      0x01, 0x00, 0x00, 0x00,  # Number of FREs
+      0x00, 0x10, 0x00, 0x00,  # FRE length
+      0x00, 0x00, 0x00, 0x00,  # FDE offset
+      0x00, 0x00, 0x00, 0x00,  # FRE offset
+
+      # FDE[0]:
+      0x00, 0xde, 0xad, 0x00,  # Start Address
+      0xbe, 0x01, 0x00, 0x00,  # Size
+      0x00, 0x00, 0x00, 0x00,  # Start FRE Offset
+      0x01, 0x00, 0x00, 0x00,  # Number of FREs
+      0x00, 0xde, 0xad, 0x00,  # Info, RepSize, Padding2
+
+      # FRE[0]:
+      0x00                     # Start Address, (missing) Info
+    ]
+# CASE1-LABEL:SFrame section '.sframe_eof_address' {
+#       CASE1:    FuncDescEntry [0] {
+#       CASE1:      Info {
+#  CASE1-NEXT:        FRE Type: Addr1 (0x0)
+#  CASE1-NEXT:        FDE Type: PCInc (0x0)
+#       CASE1:      FREs [
+#  CASE1-NEXT:{{.*}}: warning: '[[FILE]]': unexpected end of data at offset 0x31 while reading [0x30, 0x32)
+#  CASE1-NEXT:      ]
+
+  - Name:  .sframe_eof_offset
+    Type:  SHT_GNU_SFRAME
+    Flags: [ SHF_ALLOC ]
+    ContentArray: [
+      0xe2, 0xde, 0x02, 0x04,  # 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
+      0x01, 0x00, 0x00, 0x00,  # Number of FREs
+      0x00, 0x10, 0x00, 0x00,  # FRE length
+      0x00, 0x00, 0x00, 0x00,  # FDE offset
+      0x00, 0x00, 0x00, 0x00,  # FRE offset
+
+      # FDE[0]:
+      0x00, 0xde, 0xad, 0x00,  # Start Address
+      0xbe, 0x01, 0x00, 0x00,  # Size
+      0x00, 0x00, 0x00, 0x00,  # Start FRE Offset
+      0x01, 0x00, 0x00, 0x00,  # Number of FREs
+      0x00, 0xde, 0xad, 0x00,  # Info, RepSize, Padding2
+
+      # FRE[0]:
+      0x00, 0x02               # Start Address, Info, (missing) Offsets
+    ]
+# CASE1-LABEL:SFrame section '.sframe_eof_offset' {
+#       CASE1:    FuncDescEntry [0] {
+#       CASE1:      Info {
+#  CASE1-NEXT:        FRE Type: Addr1 (0x0)
+#  CASE1-NEXT:        FDE Type: PCInc (0x0)
+#       CASE1:      FREs [
+#  CASE1-NEXT:{{.*}}: warning: '[[FILE]]': unexpected end of data at offset 0x32 while reading [0x32, 0x33)
+#  CASE1-NEXT:      ]
+
+  - Name:  .sframe
+    Type:  SHT_GNU_SFRAME
+    Flags: [ SHF_ALLOC ]
+    ContentArray: [
+      0xe2, 0xde, 0x02, 0x04,  # Preamble (magic, version, flags)
+      # Header:
+      0x03, 0x42, 0x40, 0x00,  # ABI, Fixed FP offset, Fixed RA Offset, AUX header length
+      0x03, 0x00, 0x00, 0x00,  # Number of FDEs
+      0x01, 0x00, 0x00, 0x00,  # Number of FREs
+      0x00, 0x10, 0x00, 0x00,  # FRE length
+      0x00, 0x00, 0x00, 0x00,  # FDE offset
+      0x00, 0x00, 0x00, 0x00,  # FRE offset
+
+      # FDE[0]:
+      0x00, 0x00, 0xde, 0x00,  # Start Address
+      0xbe, 0x01, 0x00, 0x00,  # Size
+      0x00, 0x00, 0x00, 0x00,  # Start FRE Offset
+      0x02, 0x00, 0x00, 0x00,  # Number of FREs
+      0x00, 0xde, 0xad, 0x00,  # Info, RepSize, Padding2
+
+      # FDE[1]:
+      0x00, 0x00, 0xad, 0x00,  # Start Address
+      0xbe, 0x01, 0x00, 0x00,  # Size
+      0x08, 0x00, 0x00, 0x00,  # Start FRE Offset
+      0x03, 0x00, 0x00, 0x00,  # Number of FREs
+      0x11, 0xde, 0xad, 0x00,  # Info, RepSize, Padding2
+
+      # FDE[2]:
+      0x00, 0x00, 0xbe, 0x00,  # Start Address
+      0xbe, 0x01, 0x00, 0x00,  # Size
+      0x08, 0x00, 0x00, 0x00,  # Start FRE Offset
+      0x01, 0x00, 0x00, 0x00,  # Number of FREs
+      0x03, 0xde, 0xad, 0x00,  # Info, RepSize, Padding2
+
+      # FRE[0,0]: Zero offsets
+      0x00, 0x00,              # Start Address, Info
+
+      # FRE[0,1]: One four-byte offset, SP-based
+      0x01, 0x43,              # Start Address, Info
+      0x74, 0x00, 0x00, 0x00,  # Offset[0]
+
+      # FRE[1,0]: Two two-byte offsets, FP-based
+      0x00, 0x00, 0x24,        # Start Address, Info
+      0x10, 0x00, 0x20, 0x00,  # Offset[0], Offset[1]
+
+      # FRE[1,1]: Four one-byte offsets, FP-based
+      0x00, 0x01, 0x08,        # Start Address, Info
+      0x10, 0x20, 0x30, 0x40,  # Offset[0-3]
+    ]
+## Testing:
+## - little-endian support
+## - AMD64 ABI
+## - one and two byte address sizes
+## - PCInc and PCMask FDE types
+## - all offset sizes
+## - various offset counts
+## - hitting EOF after printing some number of FREs
+## - invalid FRE type
+# CASE1-LABEL:SFrame section '.sframe' {
+#       CASE1:    ABI: AMD64EndianLittle (0x3)
+#       CASE1:    CFA fixed RA offset: 64
+#       CASE1:    FuncDescEntry [0] {
+#  CASE1-NEXT:      PC: 0xDE007F
+#       CASE1:      Info {
+#  CASE1-NEXT:        FRE Type: Addr1 (0x0)
+#  CASE1-NEXT:        FDE Type: PCInc (0x0)
+#       CASE1:      FREs [
+#  CASE1-NEXT:        Frame Row Entry {
+#  CASE1-NEXT:          Start Address: 0xDE007F
+#  CASE1-NEXT:          Return Address Signed: No
+#  CASE1-NEXT:          Offset Size: B1 (0x0)
+#  CASE1-NEXT:          Base Register: FP (0x0)
+#  CASE1-NEXT:          RA Offset: 64
+#  CASE1-NEXT:        }
+#  CASE1-NEXT:        Frame Row Entry {
+#  CASE1-NEXT:          Start Address: 0xDE0080
+#  CASE1-NEXT:          Return Address Signed: No
+#  CASE1-NEXT:          Offset Size: B4 (0x2)
+#  CASE1-NEXT:          Base Register: SP (0x1)
+#  CASE1-NEXT:          CFA Offset: 116
+#  CASE1-NEXT:          RA Offset: 64
+#  CASE1-NEXT:        }
+#  CASE1-NEXT:      ]
+#       CASE1:    FuncDescEntry [1] {
+#  CASE1-NEXT:      PC: 0xAD0093
+#       CASE1:      Info {
+#  CASE1-NEXT:        FRE Type: Addr2 (0x1)
+#  CASE1-NEXT:        FDE Type: PCMask (0x1)
+#       CASE1:      FREs [
+#  CASE1-NEXT:        Frame Row Entry {
+#  CASE1-NEXT:          Start Address: 0x0
+#  CASE1-NEXT:          Return Address Signed: No
+#  CASE1-NEXT:          Offset Size: B2 (0x1)
+#  CASE1-NEXT:          Base Register: FP (0x0)
+#  CASE1-NEXT:          CFA Offset: 16
+#  CASE1-NEXT:          RA Offset: 64
+#  CASE1-NEXT:          FP Offset: 32
+#  CASE1-NEXT:        }
+#  CASE1-NEXT:        Frame Row Entry {
+#  CASE1-NEXT:          Start Address: 0x100
+#  CASE1-NEXT:          Return Address Signed: No
+#  CASE1-NEXT:          Offset Size: B1 (0x0)
+#  CASE1-NEXT:          Base Register: FP (0x0)
+#  CASE1-NEXT:          CFA Offset: 16
+#  CASE1-NEXT:          RA Offset: 64
+#  CASE1-NEXT:          FP Offset: 32
+#  CASE1-NEXT:          Extra Offsets: [48, 64]
+#  CASE1-NEXT:        }
+#  CASE1-NEXT:{{.*}}: warning: '[[FILE]]': unexpected end of data at offset 0x6e while reading [0x6e, 0x71)
+#       CASE1:    FuncDescEntry [2] {
+#       CASE1:      Info {
+#  CASE1-NEXT:        FRE Type: 0x3
+#       CASE1:      FREs [
+#  CASE1-NEXT:{{.*}}: warning: '[[FILE]]': unsupported FRE type 3 at offset 0x60
+
+--- !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, 0x00, 0x00,  # Start Address
+      0x00, 0x00, 0x01, 0xbe,  # Size
+      0x00, 0x00, 0x00, 0x00,  # Start FRE Offset
+      0x00, 0x00, 0x00, 0x06,  # Number of FREs
+      0x02, 0xde, 0xad, 0x00,  # Info, RepSize, Padding2
+
+      # FRE[0]: Zero offsets
+      0x00, 0x00, 0x00, 0x00,  # Start Address
+      0x00,                    # Info
+
+      # FRE[1]: One offset
+      0x00, 0x00, 0x00, 0x01,  # Start Address
+      0x82, 0x10,              # Info, Offset[0]
+
+      # FRE[2]: Two offsets
+      0x00, 0x00, 0x00, 0x02,  # Start Address
+      0x04, 0x10, 0x20,        # Info, Offset[0-1]
+
+      # FRE[3]: Three ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/152695


More information about the llvm-commits mailing list