diff --git a/llvm/include/llvm/BinaryFormat/SFrame.h b/llvm/include/llvm/BinaryFormat/SFrame.h index 6e8f6f9f48e42..0c6c4d176eaec 100644 --- a/llvm/include/llvm/BinaryFormat/SFrame.h +++ b/llvm/include/llvm/BinaryFormat/SFrame.h @@ -50,29 +50,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. @@ -167,6 +165,10 @@ template using FrameRowEntryAddr4 = FrameRowEntry; LLVM_ABI ArrayRef> getVersions(); LLVM_ABI ArrayRef> getFlags(); LLVM_ABI ArrayRef> getABIs(); +LLVM_ABI ArrayRef> getFRETypes(); +LLVM_ABI ArrayRef> getFDETypes(); +LLVM_ABI ArrayRef> getAArch64PAuthKeys(); +LLVM_ABI ArrayRef> 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 e595bedcc3561..245e7ba40d0b8 100644 --- a/llvm/include/llvm/Object/SFrameParser.h +++ b/llvm/include/llvm/Object/SFrameParser.h @@ -20,11 +20,14 @@ namespace object { template class SFrameParser { public: - static Expected create(ArrayRef Contents); + static Expected create(ArrayRef Contents, + uint64_t SectionAddress); const sframe::Preamble &getPreamble() const { return Header.Preamble; } const sframe::Header &getHeader() const { return Header; } + Expected> getAuxHeader() const; + bool usesFixedRAOffset() const { return getHeader().ABIArch == sframe::ABI::AMD64EndianLittle; } @@ -32,12 +35,25 @@ template class SFrameParser { return false; // Not used in any currently defined ABI. } + using FDERange = ArrayRef>; + Expected 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 Data; + uint64_t SectionAddress; const sframe::Header &Header; - SFrameParser(ArrayRef Data, const sframe::Header &Header) - : Data(Data), Header(Header) {} + SFrameParser(ArrayRef Data, uint64_t SectionAddress, + const sframe::Header &Header) + : Data(Data), SectionAddress(SectionAddress), Header(Header) {} + + uint64_t getFDEBase() const { + return sizeof(Header) + Header.AuxHdrLen + Header.FDEOff; + } }; extern template class LLVM_TEMPLATE_ABI SFrameParser; 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> sframe::getABIs() { }; return ArrayRef(ABIs); } + +ArrayRef> sframe::getFRETypes() { + static constexpr EnumEntry FRETypes[] = { +#define HANDLE_SFRAME_FRE_TYPE(CODE, NAME) {#NAME, sframe::FREType::NAME}, +#include "llvm/BinaryFormat/SFrameConstants.def" + }; + return ArrayRef(FRETypes); +} + +ArrayRef> sframe::getFDETypes() { + static constexpr EnumEntry FDETypes[] = { +#define HANDLE_SFRAME_FDE_TYPE(CODE, NAME) {#NAME, sframe::FDEType::NAME}, +#include "llvm/BinaryFormat/SFrameConstants.def" + }; + return ArrayRef(FDETypes); +} + +ArrayRef> sframe::getAArch64PAuthKeys() { + static constexpr EnumEntry AArch64PAuthKeys[] = { +#define HANDLE_SFRAME_AARCH64_PAUTH_KEY(CODE, NAME) \ + {#NAME, sframe::AArch64PAuthKey::NAME}, +#include "llvm/BinaryFormat/SFrameConstants.def" + }; + return ArrayRef(AArch64PAuthKeys); +} + +ArrayRef> sframe::getFREOffsets() { + static constexpr EnumEntry 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 6f0037c547c51..5863490634e32 100644 --- a/llvm/lib/Object/SFrameParser.cpp +++ b/llvm/lib/Object/SFrameParser.cpp @@ -10,27 +10,41 @@ #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; -template -static Expected getDataSliceAs(ArrayRef Data, - uint64_t Offset) { - static_assert(std::is_trivial_v); - if (Data.size() < Offset + sizeof(T)) { +static Expected> +getDataSlice(ArrayRef 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, Offset + sizeof(T)) + Data.size(), Offset, End) .str(), object_error::unexpected_eof); } - return *reinterpret_cast(Data.data() + Offset); + return Data.slice(Offset, Size); +} + +template +static Expected getDataSliceAs(ArrayRef Data, + uint64_t Offset) { + static_assert(std::is_trivial_v); + Expected> Slice = getDataSlice(Data, Offset, sizeof(T)); + if (!Slice) + return Slice.takeError(); + + return *reinterpret_cast(Slice->data()); } template -Expected> SFrameParser::create(ArrayRef Contents) { +Expected> SFrameParser::create(ArrayRef Contents, + uint64_t SectionAddress) { Expected &> Preamble = getDataSliceAs>(Contents, 0); if (!Preamble) @@ -48,7 +62,42 @@ Expected> SFrameParser::create(ArrayRef Contents) { getDataSliceAs>(Contents, 0); if (!Header) return Header.takeError(); - return SFrameParser(Contents, *Header); + return SFrameParser(Contents, SectionAddress, *Header); +} + +template +Expected> SFrameParser::getAuxHeader() const { + return getDataSlice(Data, sizeof(Header), Header.AuxHdrLen); +} + +template +Expected>> SFrameParser::fdes() const { + Expected> Slice = getDataSlice( + Data, getFDEBase(), Header.NumFDEs * sizeof(sframe::FuncDescEntry)); + if (!Slice) + return Slice.takeError(); + return ArrayRef( + reinterpret_cast *>(Slice->data()), + Header.NumFDEs); +} + +template +uint64_t SFrameParser::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(Data.data()); + uintptr_t FDEPtr = reinterpret_cast(&*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; 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..dee40180c42e6 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/sframe-fde.test @@ -0,0 +1,237 @@ +## 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 { +# 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: } +# 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 { +# 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: } +# 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 { +# 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: } +# 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 2699e1061e1b8..94ce38605f5c9 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -424,6 +424,9 @@ template class ELFDumper : public ObjDumper { ArrayRef getShndxTable(const Elf_Shdr *Symtab) const; + void printSFrameHeader(const SFrameParser &Parser); + void printSFrameFDEs(const SFrameParser &Parser); + private: mutable SmallVector, 0> VersionMap; }; @@ -6439,6 +6442,90 @@ template void ELFDumper::printMemtag() { printMemtag(DynamicEntries, AndroidNoteDesc, GlobalDescriptors); } +template +void ELFDumper::printSFrameHeader( + const SFrameParser &Parser) { + DictScope HeaderScope(W, "Header"); + + const sframe::Preamble &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 &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> Aux = Parser.getAuxHeader()) + W.printHexList("Auxiliary header", *Aux); + else + reportWarning(Aux.takeError(), FileName); +} + +template +void ELFDumper::printSFrameFDEs( + const SFrameParser &Parser) { + typename SFrameParser::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); + + { + 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( + ("Repetitive block size" + + Twine(It->getFDEType() == sframe::FDEType::PCMask ? "" : " (unused)")) + .str(), + It->RepSize); + + W.printHex("Padding2", It->Padding2); + } +} + template void ELFDumper::printSectionsAsSFrame(ArrayRef Sections) { constexpr endianness E = ELFT::Endianness; @@ -6456,8 +6543,8 @@ void ELFDumper::printSectionsAsSFrame(ArrayRef Sections) { continue; } - Expected> Parser = - object::SFrameParser::create(arrayRefFromStringRef(SectionContent)); + Expected> Parser = object::SFrameParser::create( + arrayRefFromStringRef(SectionContent), Section.getAddress()); if (!Parser) { reportWarning(createError("invalid sframe section: " + toString(Parser.takeError())), @@ -6465,32 +6552,8 @@ void ELFDumper::printSectionsAsSFrame(ArrayRef Sections) { continue; } - DictScope HeaderScope(W, "Header"); - - const sframe::Preamble &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 &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); } }