binutils-gdb/include/sframe.h

561 lines
23 KiB
C
Raw Permalink Normal View History

/* SFrame format description.
Copyright (C) 2022-2026 Free Software Foundation, Inc.
This file is part of libsframe.
libsframe is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not see
<http://www.gnu.org/licenses/>. */
#ifndef _SFRAME_H
#define _SFRAME_H
#include <sys/types.h>
#include <limits.h>
#include <stdint.h>
#include "ansidecl.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* SFrame format.
SFrame format is a simple format to represent the information needed
for generating vanilla backtraces. SFrame format keeps track of the
minimal necessary information needed for stack tracing:
- Canonical Frame Address (CFA)
- Frame Pointer (FP)
- Return Address (RA)
The SFrame section itself has the following structure:
+--------+------------+---------+
| file | function | frame |
| header | descriptor | row |
| | entries | entries |
+--------+------------+---------+
The file header stores a magic number and version information, flags, and
the byte offset of each of the sections relative to the end of the header
itself. The file header also specifies the total number of Function
Descriptor Entries, Frame Row Entries and length of the FRE sub-section.
Following the header is a list of Function Descriptor Entries (FDEs).
This list may be sorted if the flags in the file header indicate it to be
so. The sort order, if applicable, is the order of functions in the
.text.* sections in the resulting binary artifact. Each Function
Descriptor Entry specifies the start PC of a function, the size in bytes
of the function and an offset to its first Frame Row Entry (FRE). Each FDE
additionally also specifies the type of FRE it uses to encode the stack
trace information.
Next, the SFrame Frame Row Entry sub-section is a list of variable size
records. Each entry represents stack trace information for a set of PCs
of the function. A singular Frame Row Entry is a self-sufficient record
which contains information on how to generate stack trace from the
applicable set of PCs.
*/
/* SFrame format versions. */
#define SFRAME_VERSION_1 1
sframe: bfd: gas: ld: format bump to SFrame version 2 SFrame version 2 encodes the size of repetitive insn block explicitly in the format. Add information in the SFrame FDE to convey the size of the block of repeating instructions. This information is used only for SFrame FDEs of type SFRAME_FDE_TYPE_PCMASK. Introduce two extra bytes for padding: this ensures that the memory accesses to the members of the SFrame Frame Descriptor Entry (FDE) are naturally aligned. gas generates SFrame section with version SFRAME_VERSION_2 by default. libsframe provides two new APIs to: - get an SFrame FDE data from the decoder context, and - add an SFrame FDE to the encoder context. The additional argument (for rep_block_size) is useful for SFrame FDEs where FDE type is SFRAME_FDE_TYPE_PCMASK. The linker will generate the output SFrame sections in the SFRAME_VERSION_2 format. If the input sections offered to the linker are not all in the SFRAME_VERSION_2 format, the linker issues an error to the user. objdump/readelf will show the following message to the user if .sframe section in SFRAME_VERSION_1 format is seen: "No further information can be displayed. SFrame version not supported." In other words, like the rest of the binutils, only the current SFrame format version, i.e., SFRAME_VERSION_2 is supported by the textual dump facilities. bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Generate an output SFrame section with version SFRAME_VERSION_2. Also, error out if the SFrame sections do not all have SFRAME_VERSION_2. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Generate SFrame section for plt entries with version SFRAME_VERSION_2. gas/ * gen-sframe.c (sframe_set_version): Update to SFRAME_VERSION_2. (output_sframe): Likewise. gas/testsuite/ * gas/cfi-sframe/cfi-sframe-aarch64-1.d: Use SFRAME_VERSION_2. * gas/cfi-sframe/cfi-sframe-aarch64-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-aarch64-pac-ab-key-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-3.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-4.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-5.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-6.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-7.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-8.d: Likewise. * gas/cfi-sframe/cfi-sframe-x86_64-1.d: Likewise. * gas/cfi-sframe/common-empty-1.d: Likewise. * gas/cfi-sframe/common-empty-2.d: Likewise. * gas/cfi-sframe/common-empty-3.d: Likewise. ld/testsuite/ * ld-aarch64/sframe-simple-1.d: Adjust for SFRAME_VERSION_2. * ld-x86-64/sframe-plt-1.d: Likewise. * ld-x86-64/sframe-simple-1.d: Likewise. libsframe/ * libsframe.ver: Add the new APIs. * sframe.c (sframe_decoder_get_funcdesc_v2): New definition. (sframe_encoder_add_funcdesc_v2): Likewise. (sframe_header_sanity_check_p): Include SFRAME_VERSION_2. (sframe_fre_check_range_p): Get rep_block_size info from SFrame FDE. * sframe-dump.c (dump_sframe_header): Add support for SFRAME_VERSION_2. (dump_sframe): Inform user if SFrame section in SFRAME_VERSION_1 format is seen. libsframe/testsuite/ * libsframe.decode/DATA-BE: Regenerated data file. * libsframe.decode/DATA1: Likewise. * libsframe.decode/DATA2: Likewise. * libsframe.find/plt-findfre-1.c: Use new API in the testcase. include/ * sframe.h: Add member to encode size of the code block of repeating instructions. Add 2 bytes of padding. * sframe-api.h (sframe_decoder_get_funcdesc_v2): New declaration. (sframe_encoder_add_funcdesc_v2): Likewise.
2023-06-29 16:29:09 -07:00
#define SFRAME_VERSION_2 2
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
#define SFRAME_VERSION_3 3
/* SFrame magic number. */
#define SFRAME_MAGIC 0xdee2
/* Current version of SFrame format. */
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
#define SFRAME_VERSION SFRAME_VERSION_3
/* Various flags for SFrame. */
/* Function Descriptor Entries are sorted on PC. */
include: sframe: doc: define new flag SFRAME_F_FDE_FUNC_START_PCREL Add a new flag SFRAME_F_FDE_FUNC_START_PCREL to SFrame stack trace format. If set, this flag indicates that the function start address field (sfde_func_start_address) is the offset to the function start address from the SFrame FDE function start address field itself. Such an encoding is friendlier to the exisitng PC-REL relocations available in the ABIs supported in SFrame: AMD64 (R_X86_64_PC32) and AArch64 (R_AARCH64_PREL32). In subsequent patches, we will make the implementation in gas and ld to both: - emit the values in the same (above-mentioned) encoding uniformly. - set the flag SFRAME_F_FDE_FUNC_START_PCREL in the SFrame header for consumers to be able to distinguish. Define SFRAME_V2_F_ALL_FLAGS in sframe.h to help keep the implementation less error-prone by keeping a set of all defined flags at a central place. Adjust the check in sframe_header_sanity_check_p () to use the SFRAME_V2_F_ALL_FLAGS instead. Add documentation for SFRAME_F_FDE_FUNC_START_PCREL. Update the documentation about the encoding of the sfde_func_start_address field. Also, update the section "Changes from Version 1 to Version 2" to include the specification of the new flag SFRAME_F_FDE_FUNC_START_PCREL as an erratum to the SFrame Version 2 specification. include/ * sframe.h (SFRAME_F_FDE_FUNC_START_PCREL): New definition. (SFRAME_V2_F_ALL_FLAGS): Likewise. libsframe/ * sframe-dump.c (dump_sframe_header_flags): Update to include the new flag SFRAME_F_FDE_FUNC_START_PCREL. * sframe.c (sframe_header_sanity_check_p): Use SFRAME_V2_F_ALL_FLAGS. libsframe/doc/ * sframe-spec.texi: Add details about the new flag. Also update the defails about the sfde_func_start_address encoding.
2025-07-06 12:46:43 -07:00
#define SFRAME_F_FDE_SORTED 0x1
/* Functions preserve frame pointer. */
include: sframe: doc: define new flag SFRAME_F_FDE_FUNC_START_PCREL Add a new flag SFRAME_F_FDE_FUNC_START_PCREL to SFrame stack trace format. If set, this flag indicates that the function start address field (sfde_func_start_address) is the offset to the function start address from the SFrame FDE function start address field itself. Such an encoding is friendlier to the exisitng PC-REL relocations available in the ABIs supported in SFrame: AMD64 (R_X86_64_PC32) and AArch64 (R_AARCH64_PREL32). In subsequent patches, we will make the implementation in gas and ld to both: - emit the values in the same (above-mentioned) encoding uniformly. - set the flag SFRAME_F_FDE_FUNC_START_PCREL in the SFrame header for consumers to be able to distinguish. Define SFRAME_V2_F_ALL_FLAGS in sframe.h to help keep the implementation less error-prone by keeping a set of all defined flags at a central place. Adjust the check in sframe_header_sanity_check_p () to use the SFRAME_V2_F_ALL_FLAGS instead. Add documentation for SFRAME_F_FDE_FUNC_START_PCREL. Update the documentation about the encoding of the sfde_func_start_address field. Also, update the section "Changes from Version 1 to Version 2" to include the specification of the new flag SFRAME_F_FDE_FUNC_START_PCREL as an erratum to the SFrame Version 2 specification. include/ * sframe.h (SFRAME_F_FDE_FUNC_START_PCREL): New definition. (SFRAME_V2_F_ALL_FLAGS): Likewise. libsframe/ * sframe-dump.c (dump_sframe_header_flags): Update to include the new flag SFRAME_F_FDE_FUNC_START_PCREL. * sframe.c (sframe_header_sanity_check_p): Use SFRAME_V2_F_ALL_FLAGS. libsframe/doc/ * sframe-spec.texi: Add details about the new flag. Also update the defails about the sfde_func_start_address encoding.
2025-07-06 12:46:43 -07:00
#define SFRAME_F_FRAME_POINTER 0x2
/* Function start address in SFrame FDE is encoded as the distance from the
location of the sfde_func_start_address to the start PC of the function.
If absent, the function start address in SFrame FDE is encoded as the
distance from the start of the SFrame FDE section to the start PC of the
function. */
#define SFRAME_F_FDE_FUNC_START_PCREL 0x4
/* Set of all defined flags in SFrame V2. */
#define SFRAME_V2_F_ALL_FLAGS \
(SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER \
| SFRAME_F_FDE_FUNC_START_PCREL)
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
/* Set of all defined flags in SFrame V3. */
#define SFRAME_V3_F_ALL_FLAGS \
(SFRAME_F_FDE_SORTED | SFRAME_F_FDE_FUNC_START_PCREL)
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
#define SFRAME_CFA_FIXED_FP_INVALID 0
#define SFRAME_CFA_FIXED_RA_INVALID 0
/* Supported ABIs/Arch. */
#define SFRAME_ABI_AARCH64_ENDIAN_BIG 1 /* AARCH64 big endian. */
#define SFRAME_ABI_AARCH64_ENDIAN_LITTLE 2 /* AARCH64 little endian. */
#define SFRAME_ABI_AMD64_ENDIAN_LITTLE 3 /* AMD64 little endian. */
s390: Initial support to generate .sframe from CFI directives in assembler This introduces initial support to generate .sframe from CFI directives in assembler on s390 64-bit (s390x). Due to SFrame V2 format limitations it has the following limitations, some of them getting addressed by subsequent patches, which cause generation of SFrame FDE to be skipped: - SFrame FP/RA tracking only supports register contents being saved on the stack (i.e. .cfi_offset). It does not support FP/RA register contents being saved in other registers (i.e. .cfi_register). GCC on s390x can be observed to save the FP/RA register contents in floating- point registers, but only in leaf functions. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP/RA saved in register in SFrame". - SFrame FP/RA tracking cannot represent FP without RA saved. This is because the format assumes SFrame FDE offset2 to be the RA offset, if there are two offsets, and offset3 to be the FP offset, if there are three offsets. There is no mean to distinguish whether offset2 is the RA or FP offset, if there are only two offsets. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP without RA saved in SFrame". - SFrame assumes a dedicated FP register number. The s390x ELF ABI [1] does only designate register 11 as preferred FP register number. In general GCC and Clang on s390x use register 11 as frame pointer. GCC on s390x can be observed to use register 14 as frame pointer in the stack clash protector in the function prologue. glibc on s390x contains hand-written assembler code that uses register 12 as frame pointer. This s390x support is largely based on the AArch64 support from commit b52c4ee46657 ("gas: generate .sframe from CFI directives"). The SFrame ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG is introduced for s390x and added to the SFrame format specification. The s390x ELF ABI [1] specifies the following C calling conventions for s390x architecture: - Register 15 is the stack pointer (SP). - Register 14 contains the return address (RA) at function entry. - There is no dedicated frame pointer register. Register 11 is the preferred frame pointer (FP). [2] GCC and Clang in general use register 11 as frame pointer. - The CFA is defined as SP at call site +160. [3] The SP at call site can therefore be derived from the CFA using a SP value offset from CFA of -160. The s390x ELF ABI [1] does not assign any standard save slot to each register in the register save area of a stack frame. Neither the return address (RA, r14) nor preferred frame pointer (FP, r11) necessarily need to be saved. Therefore SFrame RA and FP tracking is used. Support for SFrame on s390 is only enabled for the 64-bit s390x ELF ABI (z/Architecture with 64-bit addressing mode). It is disabled for the 32-bit s390 ELF ABI (ESA/390 or z/Architecture with 32-bit addressing mode). s390x-specific SFrame assembler and linker tests are added, including error tests for use of a non-preferred frame pointer (FP) register and specification of a non-default return address (RA) register. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit f00421825979 ("Add information about the frame pointer register"), https://github.com/IBM/s390x-abi/commit/f00421825979 [3]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h: Add reference to s390x architecture in comments. (SFRAME_ABI_S390X_ENDIAN_BIG): Define SFrame ABI/arch identifier for s390x. (SFRAME_S390X_SP_VAL_OFFSET): Define s390x-specific SP value offset from CFA. libsframe/ * sframe.c (need_swapping): Add SFRAME_ABI_S390X_ENDIAN_BIG. * doc/sframe-spec.texi (SFRAME_ABI_S390X_ENDIAN_BIG, s390x, SFRAME_S390X_SP_VAL_OFFSET): Document SFrame ABI/arch identifier for s390x, add references to s390x architecture, and document s390x-specifics, such as the SP value offset from CFA of -160. gas/ * config/tc-s390.h: s390x support to generate .sframe from CFI directives in assembler. (support_sframe_p): Define. (SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG): Define. (sframe_ra_tracking_p): Define. (sframe_cfa_ra_offset): Define. (sframe_get_abi_arch): Define. * config/tc-s390.c: s390x support to generate .sframe from CFI directives in assembler. (s390_sframe_cfa_sp_reg, s390_sframe_cfa_fp_reg, s390_sframe_cfa_ra_reg): New. Initialize to DWARF register numbers of stack pointer (SP, r15), preferred frame pointer (FP, r11), and return address (RA, r14) registers. (s390_support_sframe_p): New function. Return true if s390x. (s390_sframe_ra_tracking_p): New function. Return true. (s390_sframe_cfa_ra_offset): New function. Return SFRAME_CFA_FIXED_RA_INVALID. (s390_sframe_get_abi_arch): New function. Return SFRAME_ABI_S390X_ENDIAN_BIG if s390x, otherwise zero. * gen-sframe.c: Add reference to s390x architecture in comments. (sframe_xlate_do_val_offset): Add support for s390x-specific SFRAME_S390X_SP_VAL_OFFSET. * NEWS: Add news entry. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests for s390x. Add s390x-specific SFrame (error) tests. * gas/cfi-sframe/cfi-sframe-s390x-1.d: New s390x-specific SFrame test. * gas/cfi-sframe/cfi-sframe-s390x-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-1.d: New s390x-specific SFrame error test that uses a non-default frame-pointer register as CFA base register. * gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-3.d: New s390x-specific SFrame error test that uses a non-default return address register. * gas/cfi-sframe/cfi-sframe-s390x-err-3.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d: New s390x- specific SFrame test that saves RA and FP individually on the stack. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually, to trigger FP without RA saved. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: New s390x-specific SFrame error test that saves RA and FP individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s: Likewise. ld/testsuite/ * ld-s390/s390.exp: Add simple SFrame test. * ld-s390/sframe-simple-1.d: New simple SFrame test. * ld-s390/sframe-bar.s: Likewise. * ld-s390/sframe-foo.s: Likewise. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
#define SFRAME_ABI_S390X_ENDIAN_BIG 4 /* s390x big endian. */
/* SFrame FRE types. */
#define SFRAME_FRE_TYPE_ADDR1 0
#define SFRAME_FRE_TYPE_ADDR2 1
#define SFRAME_FRE_TYPE_ADDR4 2
/* SFrame Function Descriptor Entry PC types.
The SFrame format has two possible representations for functions' PC Type.
The choice of which PC type to use is made according to the instruction
patterns in the relevant program stub.
For more details, see the (renamed to) entries SFRAME_V3_FDE_PCTYPE_INC and
SFRAME_V3_FDE_PCTYPE_MASK for SFrame V3. */
/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE.
NB: Use SFRAME_V3_FDE_PCTYPE_INC in SFrame V3 instead. */
#define SFRAME_FDE_TYPE_PCINC 0
libsframe: fix sframe_find_fre for pltN entries For a toy application on x86_64, for example, following is the SFrame stack trace information for the 3 pltN entries of 16 bytes each: func idx [1]: pc = 0x401030, size = 48 bytes STARTPC[m] CFA FP RA 0000000000000000 sp+8 u u 000000000000000b sp+16 u u The data in first column is the start_ip_offset. Also note that the FDE is of type SFRAME_FDE_TYPE_PCMASK (denoted by the [m] on LHS). Where each pltN (note: excluding plt0 entry) entry looks like: 401030: jmp *0x2fca(%rip) 401036: push $0x0 40103b: jmp 401020<_init+0x20> 401040: jmp *0x2fc2(%rip) 401046: push $0x1 40104b: jmp 401020<_init+0x20> 401050: jmp *0x2fba(%rip) 401056: push $0x2 40105b: jmp 401020<_init+0x20> Now, to find SFrame stack trace information from an FDE of type SFRAME_FDE_TYPE_PCMASK, sframe_find_fre () was doing an operation like, (start_ip_offset & 0xf) >= (pc & 0xf) This works for pltN entry of size, say, less than 16 bytes. But if the pltN entries or similar code stubs (for which SFrame FDE of type SFRAME_FDE_TYPE_PCMASK may be used), evolve to be of size > 16 bytes, this will cease to work. To match the range covered by the SFrame FRE, one should instead perform a modulo operation. The constant for the modulo operation must be the size of the pltN entry. Further, this constant should ideally be encoded in the format, as it may be different for each ABI. In SFrame Version 2 of the format, we will move towards encoding it explicitly in the SFrame FDE. For now, fix up the logic to at least move towards modulo operation. libsframe/ * sframe.c (sframe_fre_check_range_p): New definition. (sframe_find_fre): Refactor a bit and use the new definition above. include/ * sframe.h (SFRAME_FDE_TYPE_PCMASK): Update comment. libsframe/doc/ * sframe-spec.texi: Fix the text for SFRAME_FDE_TYPE_PCMASK FDE type.
2023-06-29 11:03:32 -07:00
/* Unwinders perform a (PC % REP_BLOCK_SIZE >= FRE_START_ADDR) to look up a
matching FRE. NB: Use SFRAME_V3_FDE_PCTYPE_MASK in SFrame V3 instead. */
#define SFRAME_FDE_TYPE_PCMASK 1
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
/* SFrame FDE types. */
/* Default FDE type. */
#define SFRAME_FDE_TYPE_DEFAULT 0
/* Flexible Frame FDE type.
The recovery rule for CFA, RA and FP allow more flexibility. Examples of
patterns supported include:
- CFA may be non-SP/FP based.
- CFA, FP may encode dereferencing of register after offset adjustment
- RA may be in a non-default register.
Currently used for SFRAME_ABI_AMD64_ENDIAN_LITTLE. */
#define SFRAME_FDE_TYPE_FLEX 1
typedef struct sframe_preamble
{
uint16_t sfp_magic; /* Magic number (SFRAME_MAGIC). */
uint8_t sfp_version; /* Data format version number (SFRAME_VERSION). */
uint8_t sfp_flags; /* Flags. */
} ATTRIBUTE_PACKED sframe_preamble;
typedef struct sframe_header
{
sframe_preamble sfh_preamble;
/* Information about the arch (endianness) and ABI. */
uint8_t sfh_abi_arch;
/* Offset for the Frame Pointer (FP) from CFA may be fixed for some
ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used). When fixed,
this field specifies the fixed stack frame offset and the individual
FREs do not need to track it. When not fixed, it is set to
SFRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide
the applicable stack frame offset, if any. */
int8_t sfh_cfa_fixed_fp_offset;
/* Offset for the Return Address from CFA is fixed for some ABIs
(e.g., AMD64 has it as CFA-8). When fixed, the header specifies the
fixed stack frame offset and the individual FREs do not track it. When
not fixed, it is set to SFRAME_CFA_FIXED_RA_INVALID, and individual
FREs provide the applicable stack frame offset, if any. */
int8_t sfh_cfa_fixed_ra_offset;
/* Number of bytes making up the auxiliary header, if any.
Some ABI/arch, in the future, may use this space for extending the
information in SFrame header. Auxiliary header is contained in
bytes sequentially following the sframe_header. */
uint8_t sfh_auxhdr_len;
/* Number of SFrame FDEs in this SFrame section. */
uint32_t sfh_num_fdes;
/* Number of SFrame Frame Row Entries. */
uint32_t sfh_num_fres;
/* Number of bytes in the SFrame Frame Row Entry section. */
uint32_t sfh_fre_len;
/* Offset of SFrame Function Descriptor Entry section. */
uint32_t sfh_fdeoff;
/* Offset of SFrame Frame Row Entry section. */
uint32_t sfh_freoff;
} ATTRIBUTE_PACKED sframe_header;
#define SFRAME_V1_HDR_SIZE(sframe_hdr) \
((sizeof (sframe_header) + (sframe_hdr).sfh_auxhdr_len))
/* Two possible keys for executable (instruction) pointers signing. */
#define SFRAME_AARCH64_PAUTH_KEY_A 0 /* Key A. */
#define SFRAME_AARCH64_PAUTH_KEY_B 1 /* Key B. */
typedef struct sframe_func_desc_entry_v2
{
/* Function start address. Encoded as a signed offset, relative to the
beginning of the current FDE. */
int32_t sfde_func_start_address;
/* Size of the function in bytes. */
uint32_t sfde_func_size;
/* Offset of the first SFrame Frame Row Entry of the function, relative to the
beginning of the SFrame Frame Row Entry sub-section. */
uint32_t sfde_func_start_fre_off;
/* Number of frame row entries for the function. */
uint32_t sfde_func_num_fres;
/* Additional information for stack tracing from the function:
- 4-bits: Identify the FRE type used for the function.
- 1-bit: Identify the FDE type of the function - mask or inc.
- 1-bit: PAC authorization A/B key (aarch64).
- 2-bits: Unused.
------------------------------------------------------------------------
| Unused | PAC auth A/B key (aarch64) | FDE type | FRE type |
s390: Initial support to generate .sframe from CFI directives in assembler This introduces initial support to generate .sframe from CFI directives in assembler on s390 64-bit (s390x). Due to SFrame V2 format limitations it has the following limitations, some of them getting addressed by subsequent patches, which cause generation of SFrame FDE to be skipped: - SFrame FP/RA tracking only supports register contents being saved on the stack (i.e. .cfi_offset). It does not support FP/RA register contents being saved in other registers (i.e. .cfi_register). GCC on s390x can be observed to save the FP/RA register contents in floating- point registers, but only in leaf functions. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP/RA saved in register in SFrame". - SFrame FP/RA tracking cannot represent FP without RA saved. This is because the format assumes SFrame FDE offset2 to be the RA offset, if there are two offsets, and offset3 to be the FP offset, if there are three offsets. There is no mean to distinguish whether offset2 is the RA or FP offset, if there are only two offsets. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP without RA saved in SFrame". - SFrame assumes a dedicated FP register number. The s390x ELF ABI [1] does only designate register 11 as preferred FP register number. In general GCC and Clang on s390x use register 11 as frame pointer. GCC on s390x can be observed to use register 14 as frame pointer in the stack clash protector in the function prologue. glibc on s390x contains hand-written assembler code that uses register 12 as frame pointer. This s390x support is largely based on the AArch64 support from commit b52c4ee46657 ("gas: generate .sframe from CFI directives"). The SFrame ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG is introduced for s390x and added to the SFrame format specification. The s390x ELF ABI [1] specifies the following C calling conventions for s390x architecture: - Register 15 is the stack pointer (SP). - Register 14 contains the return address (RA) at function entry. - There is no dedicated frame pointer register. Register 11 is the preferred frame pointer (FP). [2] GCC and Clang in general use register 11 as frame pointer. - The CFA is defined as SP at call site +160. [3] The SP at call site can therefore be derived from the CFA using a SP value offset from CFA of -160. The s390x ELF ABI [1] does not assign any standard save slot to each register in the register save area of a stack frame. Neither the return address (RA, r14) nor preferred frame pointer (FP, r11) necessarily need to be saved. Therefore SFrame RA and FP tracking is used. Support for SFrame on s390 is only enabled for the 64-bit s390x ELF ABI (z/Architecture with 64-bit addressing mode). It is disabled for the 32-bit s390 ELF ABI (ESA/390 or z/Architecture with 32-bit addressing mode). s390x-specific SFrame assembler and linker tests are added, including error tests for use of a non-preferred frame pointer (FP) register and specification of a non-default return address (RA) register. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit f00421825979 ("Add information about the frame pointer register"), https://github.com/IBM/s390x-abi/commit/f00421825979 [3]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h: Add reference to s390x architecture in comments. (SFRAME_ABI_S390X_ENDIAN_BIG): Define SFrame ABI/arch identifier for s390x. (SFRAME_S390X_SP_VAL_OFFSET): Define s390x-specific SP value offset from CFA. libsframe/ * sframe.c (need_swapping): Add SFRAME_ABI_S390X_ENDIAN_BIG. * doc/sframe-spec.texi (SFRAME_ABI_S390X_ENDIAN_BIG, s390x, SFRAME_S390X_SP_VAL_OFFSET): Document SFrame ABI/arch identifier for s390x, add references to s390x architecture, and document s390x-specifics, such as the SP value offset from CFA of -160. gas/ * config/tc-s390.h: s390x support to generate .sframe from CFI directives in assembler. (support_sframe_p): Define. (SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG): Define. (sframe_ra_tracking_p): Define. (sframe_cfa_ra_offset): Define. (sframe_get_abi_arch): Define. * config/tc-s390.c: s390x support to generate .sframe from CFI directives in assembler. (s390_sframe_cfa_sp_reg, s390_sframe_cfa_fp_reg, s390_sframe_cfa_ra_reg): New. Initialize to DWARF register numbers of stack pointer (SP, r15), preferred frame pointer (FP, r11), and return address (RA, r14) registers. (s390_support_sframe_p): New function. Return true if s390x. (s390_sframe_ra_tracking_p): New function. Return true. (s390_sframe_cfa_ra_offset): New function. Return SFRAME_CFA_FIXED_RA_INVALID. (s390_sframe_get_abi_arch): New function. Return SFRAME_ABI_S390X_ENDIAN_BIG if s390x, otherwise zero. * gen-sframe.c: Add reference to s390x architecture in comments. (sframe_xlate_do_val_offset): Add support for s390x-specific SFRAME_S390X_SP_VAL_OFFSET. * NEWS: Add news entry. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests for s390x. Add s390x-specific SFrame (error) tests. * gas/cfi-sframe/cfi-sframe-s390x-1.d: New s390x-specific SFrame test. * gas/cfi-sframe/cfi-sframe-s390x-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-1.d: New s390x-specific SFrame error test that uses a non-default frame-pointer register as CFA base register. * gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-3.d: New s390x-specific SFrame error test that uses a non-default return address register. * gas/cfi-sframe/cfi-sframe-s390x-err-3.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d: New s390x- specific SFrame test that saves RA and FP individually on the stack. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually, to trigger FP without RA saved. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: New s390x-specific SFrame error test that saves RA and FP individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s: Likewise. ld/testsuite/ * ld-s390/s390.exp: Add simple SFrame test. * ld-s390/sframe-simple-1.d: New simple SFrame test. * ld-s390/sframe-bar.s: Likewise. * ld-s390/sframe-foo.s: Likewise. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
| | Unused (amd64, s390x) | | |
------------------------------------------------------------------------
8 6 5 4 0 */
uint8_t sfde_func_info;
sframe: bfd: gas: ld: format bump to SFrame version 2 SFrame version 2 encodes the size of repetitive insn block explicitly in the format. Add information in the SFrame FDE to convey the size of the block of repeating instructions. This information is used only for SFrame FDEs of type SFRAME_FDE_TYPE_PCMASK. Introduce two extra bytes for padding: this ensures that the memory accesses to the members of the SFrame Frame Descriptor Entry (FDE) are naturally aligned. gas generates SFrame section with version SFRAME_VERSION_2 by default. libsframe provides two new APIs to: - get an SFrame FDE data from the decoder context, and - add an SFrame FDE to the encoder context. The additional argument (for rep_block_size) is useful for SFrame FDEs where FDE type is SFRAME_FDE_TYPE_PCMASK. The linker will generate the output SFrame sections in the SFRAME_VERSION_2 format. If the input sections offered to the linker are not all in the SFRAME_VERSION_2 format, the linker issues an error to the user. objdump/readelf will show the following message to the user if .sframe section in SFRAME_VERSION_1 format is seen: "No further information can be displayed. SFrame version not supported." In other words, like the rest of the binutils, only the current SFrame format version, i.e., SFRAME_VERSION_2 is supported by the textual dump facilities. bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Generate an output SFrame section with version SFRAME_VERSION_2. Also, error out if the SFrame sections do not all have SFRAME_VERSION_2. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Generate SFrame section for plt entries with version SFRAME_VERSION_2. gas/ * gen-sframe.c (sframe_set_version): Update to SFRAME_VERSION_2. (output_sframe): Likewise. gas/testsuite/ * gas/cfi-sframe/cfi-sframe-aarch64-1.d: Use SFRAME_VERSION_2. * gas/cfi-sframe/cfi-sframe-aarch64-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-aarch64-pac-ab-key-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-3.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-4.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-5.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-6.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-7.d: Likewise. * gas/cfi-sframe/cfi-sframe-common-8.d: Likewise. * gas/cfi-sframe/cfi-sframe-x86_64-1.d: Likewise. * gas/cfi-sframe/common-empty-1.d: Likewise. * gas/cfi-sframe/common-empty-2.d: Likewise. * gas/cfi-sframe/common-empty-3.d: Likewise. ld/testsuite/ * ld-aarch64/sframe-simple-1.d: Adjust for SFRAME_VERSION_2. * ld-x86-64/sframe-plt-1.d: Likewise. * ld-x86-64/sframe-simple-1.d: Likewise. libsframe/ * libsframe.ver: Add the new APIs. * sframe.c (sframe_decoder_get_funcdesc_v2): New definition. (sframe_encoder_add_funcdesc_v2): Likewise. (sframe_header_sanity_check_p): Include SFRAME_VERSION_2. (sframe_fre_check_range_p): Get rep_block_size info from SFrame FDE. * sframe-dump.c (dump_sframe_header): Add support for SFRAME_VERSION_2. (dump_sframe): Inform user if SFrame section in SFRAME_VERSION_1 format is seen. libsframe/testsuite/ * libsframe.decode/DATA-BE: Regenerated data file. * libsframe.decode/DATA1: Likewise. * libsframe.decode/DATA2: Likewise. * libsframe.find/plt-findfre-1.c: Use new API in the testcase. include/ * sframe.h: Add member to encode size of the code block of repeating instructions. Add 2 bytes of padding. * sframe-api.h (sframe_decoder_get_funcdesc_v2): New declaration. (sframe_encoder_add_funcdesc_v2): Likewise.
2023-06-29 16:29:09 -07:00
/* Size of the block of repeating insns. Used for SFrame FDEs of type
SFRAME_FDE_TYPE_PCMASK. */
uint8_t sfde_func_rep_size;
uint16_t sfde_func_padding2;
} ATTRIBUTE_PACKED sframe_func_desc_entry_v2;
/* Macros to compose and decompose function info in FDE. */
/* Note: Set PAC auth key to SFRAME_AARCH64_PAUTH_KEY_A by default. */
#define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \
(((SFRAME_AARCH64_PAUTH_KEY_A & 0x1) << 5) | \
(((fde_type) & 0x1) << 4) | ((fre_enc_type) & 0xf))
#define SFRAME_V1_FUNC_FRE_TYPE(data) ((data) & 0xf)
#define SFRAME_V1_FUNC_FDE_TYPE(data) (((data) >> 4) & 0x1)
#define SFRAME_V1_FUNC_PAUTH_KEY(data) (((data) >> 5) & 0x1)
/* Set the pauth key as indicated. */
#define SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY(pauth_key, fde_info) \
((((pauth_key) & 0x1) << 5) | ((fde_info) & 0xdf))
/* SFrame V2 has similar SFrame FDE representation as SFrame V1. */
#define SFRAME_V2_FUNC_INFO(fde_type, fre_enc_type) \
(SFRAME_V1_FUNC_INFO (fde_type, fre_enc_type))
#define SFRAME_V2_FUNC_FRE_TYPE(data) (SFRAME_V1_FUNC_FRE_TYPE (data))
#define SFRAME_V2_FUNC_PC_TYPE(data) (SFRAME_V1_FUNC_FDE_TYPE (data))
#define SFRAME_V2_FUNC_PAUTH_KEY(data) (SFRAME_V1_FUNC_PAUTH_KEY (data))
#define SFRAME_V2_FUNC_INFO_UPDATE_PAUTH_KEY(pauth_key, fde_info) \
SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, fde_info)
/* SFrame Function Descriptor Entry PC types.
The SFrame format has two possible representations for functions' PC Type.
The choice of which PC type to use is made according to the instruction
patterns in the relevant program stub.
The PC type SFRAME_V3_FDE_PCTYPE_INC is an indication that the PCs in the
FREs should be treated as increments in bytes. This is used for a bulk of
the executable code of a program, which contains instructions with no
specific pattern.
The PC type SFRAME_V3_FDE_PCTYPE_MASK is an indication that the PCs in the
FREs should be treated as masks. This type is useful for the cases when a
small pattern of instructions in a program stub is repeatedly to cover a
specific functionality. Typical usescases are pltN entries, trampolines
etc.
NB: In SFrame version 2 or lower, the names SFRAME_FDE_TYPE_PCINC and
SFRAME_FDE_TYPE_PCMASK were used. */
/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE. */
#define SFRAME_V3_FDE_PCTYPE_INC SFRAME_FDE_TYPE_PCINC
/* Unwinders perform a (PC % REP_BLOCK_SIZE >= FRE_START_ADDR) to look up a
matching FRE. */
#define SFRAME_V3_FDE_PCTYPE_MASK SFRAME_FDE_TYPE_PCMASK
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
typedef struct sframe_func_desc_idx_v3
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
{
[SFrame-V3] include: libsframe: bfd: gas: testsuite: support for signed 64-bit offset in SFrame FDE This change enables support text > 2 GiB in SFrame format. Each SFrame FDE needs to hold information about the start PC of the function it pertains to. Currently, the field 'sfde_func_start_address' in SFrame FDE is encoded as a 32-bit offset to the start PC of the function from the field itself. In SFrame V2, this offset was a signed 32-bit offset. The signedness gives the flexibility of having .sframe ELF section before or after the .text* sections. But the size of 32-bit puts the limitation that .sframe togther with the .text* sections must fit the 2 GiB range. Currently, if the linker sees the offset not representable as 32-bit signed offset, it issues an error (not seen in the wild, simulated by forcing a function to align via an '.align 2147483648' directive): test.o:(.sframe+0x1c): relocation truncated to fit: R_X86_64_PC32 against `.text' make: *** [Makefile:7: all] Error 1 ATM, EH Frame also suffers with the same issue. Moving forward, some cloud applications have been shown to be nearing 1.5 GiB threshold. Extending the offset to int64_t now seems to be good choice to make now for future-proof'ing the sections. The use of int64_t offset is done for all SFrame V3 sections. This bump from int32_t to int64_t should not lead to an increase in the size of SFrame sections, because of the following additional changes to the SFrame FDE specification: - Reduce the type of sfde_func_num_fres (from uint32_t to uint16_t) - Remove the 2 bytes of padding (sfde_func_padding2). These served the two-fold purpose of keeping FDE data aligned _and_ unused space for future needs. Now that the offset is int64_t, start using the sframe_decoder_get_funcdesc_v3 () instead of sframe_decoder_get_funcdesc_v2 () in GNU ld. This patch changes the offset type in the SFrame FDE definition to an int64_t. No further changes in gas are necessary because the code already accounts for writing out as per the size of the member of the struct: emit_expr (&exp, sizeof_member (sframe_func_desc_entry, sfde_func_start_offset)); bfd/ * elf-sframe.c (sframe_read_value): Signed offset for start PC is 8-bytes now. (_bfd_elf_merge_section_sframe): Likewise. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Use V3 API. (elf_s390_finish_dynamic_sections): Signed offset for start PC is 8-bytes now. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Use V3 API. (_bfd_x86_elf_finish_dynamic_sections): Signed offset for start PC is 8-bytes now. gas/ * sframe.c (output_sframe_funcdesc): Rename to sfde_func_start_offset. libsframe/ * libsframe/sframe.c (sframe_fde_tbl_init): Rename to sfde_func_start_offset. (flip_fde): Likewise. (sframe_decoder_get_secrel_func_start_addr): Use int64_t. (sframe_fre_check_range_p): Likewise. (sframe_decoder_get_offsetof_fde_start_addr): Rename to sfde_func_start_offset. (sframe_get_funcdesc_with_addr_internal): Use int64_t. (sframe_find_fre): Likewise. (sframe_encoder_get_offsetof_fde_start_addr): Rename to sfde_func_start_offset. (sframe_encoder_add_funcdesc_internal): Use int64_t. (sframe_encoder_add_funcdesc): Likewise. And rename to sfde_func_start_offset. (sframe_encoder_write_fde): Rename to sfde_func_start_offset. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate the data file. * libsframe.encode/encode-1.c: Use int64_t for start pc offset. * libsframe.find/findfre-1.c: Likewise. * libsframe.find/findfunc-1.c: Likewise. * libsframe.find/plt-findfre-1.c: Likewise. * libsframe.find/plt-findfre-2.c: Likewise. include/ * sframe-api.h (sframe_find_fre): Update arg type to int64_t. (sframe_encoder_add_funcdesc): Likewise. * sframe.h: Change data type to int64_t.
2026-01-15 16:42:03 -08:00
/* Offset to the function start address. Encoded as a signed offset,
relative to the beginning of the current FDE. */
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
int64_t sfdi_func_start_offset;
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
/* Size of the function in bytes. */
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
uint32_t sfdi_func_size;
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
/* Offset of the first SFrame Frame Row Entry of the function, relative to the
beginning of the SFrame Frame Row Entry sub-section. */
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
uint32_t sfdi_func_start_fre_off;
} ATTRIBUTE_PACKED sframe_func_desc_idx_v3;
typedef struct sframe_func_desc_attr_v3
{
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
/* Number of frame row entries for the function. */
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
uint16_t sfda_func_num_fres;
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
/* Additional information for stack tracing from the function:
- 4-bits: Identify the FRE type used for the function.
- 1-bit: Identify the PC type of the function - mask or inc.
- 1-bit: PAC authorization A/B key (aarch64).
- 1-bits: Unused.
- 1-bit: Signal frame.
-------------------------------------------------------------------------------
| Signal | Unused | PAC auth A/B key (aarch64) | FDE | FRE Type |
| frame | | Unused (amd64) | PC Type | |
-------------------------------------------------------------------------------
8 7 6 5 4 0 */
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
uint8_t sfda_func_info;
[SFrame-V3] include: gas: libsframe: add 8-bits of func_info2 for extensibility in FDE The existing field func_info (in the SFrame FDE) is used to convey important information around the encoding and interpretation of the rest of the stack trace data for the respective SFrame FDE: the SFrame FRE type, SFrame FDE PC type, etc. Currently there is 1 bit left for AArch64, and 2 bits for AMD64, s390x (and other future ABIs to be supported). Provision some additional space now (specifically an additional 8-bits) for future needs for V3 and beyond. Compared to V2, this now increases the size of SFrame FDE by 1 byte in V3. In this patch, the additional func_info2 byte is not used functionally yet. Hence, rather mechanical changes in libsframe, bfd and libsframe/testsuite accompany. We will put func_info2 into use in a later patch by reserving 5 of these bits for SFrame FDE types. With the addition of a new byte for additional func info (func_info2), add a new arg to allow usecases like textual dumper to get all data members in one API: sframe_decoder_get_funcdesc_v3. To keep the APIs symmetric looking, add new arg to sframe_encoder_add_funcdesc_v3 too. Since bfd uses these APIs, carry out the mechanical change in the respective APIs too. And of course, the testsuite which exercises these APIs. bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Get and set func_info2. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Pass 0 for func_info2 for SFrame FDE for PLT. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (output_sframe_funcdesc): Emit the uint8_t for func_info2. libsframe/ * sframe-dump.c (dump_sframe_func_with_fres): * sframe.c (sframe_fde_tbl_init): Handle the new additional member. (sframe_encoder_write_fde): Likewise. * sframe.c (sframe_decoder_get_funcdesc_v3): Update func_info2. libsframe/testsuite/ * libsframe.decode/DATA2: Update data file with SFrame section data. * libsframe.encode/encode-1.c: Pass 0 for func_info2 arg. * libsframe.find/findfre-1.c: Likewise. * libsframe.find/findfunc-1.c: Likewise. * libsframe.find/plt-findfre-1.c: Likewise. * libsframe.find/plt-findfre-2.c: Likewise. include/ * sframe.h: Add new uint8_t sfde_func_info2 to sframe_func_desc_entry_v3. * sframe-api.h (sframe_decoder_get_funcdesc_v3): New arg. (sframe_encoder_add_funcdesc_v3): Likewise.
2026-01-15 16:42:17 -08:00
/* Additional information for stack tracing from the function:
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
- 5-bits: FDE type.
- 3-bits: Unused.
[SFrame-V3] include: gas: libsframe: add 8-bits of func_info2 for extensibility in FDE The existing field func_info (in the SFrame FDE) is used to convey important information around the encoding and interpretation of the rest of the stack trace data for the respective SFrame FDE: the SFrame FRE type, SFrame FDE PC type, etc. Currently there is 1 bit left for AArch64, and 2 bits for AMD64, s390x (and other future ABIs to be supported). Provision some additional space now (specifically an additional 8-bits) for future needs for V3 and beyond. Compared to V2, this now increases the size of SFrame FDE by 1 byte in V3. In this patch, the additional func_info2 byte is not used functionally yet. Hence, rather mechanical changes in libsframe, bfd and libsframe/testsuite accompany. We will put func_info2 into use in a later patch by reserving 5 of these bits for SFrame FDE types. With the addition of a new byte for additional func info (func_info2), add a new arg to allow usecases like textual dumper to get all data members in one API: sframe_decoder_get_funcdesc_v3. To keep the APIs symmetric looking, add new arg to sframe_encoder_add_funcdesc_v3 too. Since bfd uses these APIs, carry out the mechanical change in the respective APIs too. And of course, the testsuite which exercises these APIs. bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Get and set func_info2. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Pass 0 for func_info2 for SFrame FDE for PLT. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (output_sframe_funcdesc): Emit the uint8_t for func_info2. libsframe/ * sframe-dump.c (dump_sframe_func_with_fres): * sframe.c (sframe_fde_tbl_init): Handle the new additional member. (sframe_encoder_write_fde): Likewise. * sframe.c (sframe_decoder_get_funcdesc_v3): Update func_info2. libsframe/testsuite/ * libsframe.decode/DATA2: Update data file with SFrame section data. * libsframe.encode/encode-1.c: Pass 0 for func_info2 arg. * libsframe.find/findfre-1.c: Likewise. * libsframe.find/findfunc-1.c: Likewise. * libsframe.find/plt-findfre-1.c: Likewise. * libsframe.find/plt-findfre-2.c: Likewise. include/ * sframe.h: Add new uint8_t sfde_func_info2 to sframe_func_desc_entry_v3. * sframe-api.h (sframe_decoder_get_funcdesc_v3): New arg. (sframe_encoder_add_funcdesc_v3): Likewise.
2026-01-15 16:42:17 -08:00
------------------------------------------------------------
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
| Unused | FDE Type |
| | |
[SFrame-V3] include: gas: libsframe: add 8-bits of func_info2 for extensibility in FDE The existing field func_info (in the SFrame FDE) is used to convey important information around the encoding and interpretation of the rest of the stack trace data for the respective SFrame FDE: the SFrame FRE type, SFrame FDE PC type, etc. Currently there is 1 bit left for AArch64, and 2 bits for AMD64, s390x (and other future ABIs to be supported). Provision some additional space now (specifically an additional 8-bits) for future needs for V3 and beyond. Compared to V2, this now increases the size of SFrame FDE by 1 byte in V3. In this patch, the additional func_info2 byte is not used functionally yet. Hence, rather mechanical changes in libsframe, bfd and libsframe/testsuite accompany. We will put func_info2 into use in a later patch by reserving 5 of these bits for SFrame FDE types. With the addition of a new byte for additional func info (func_info2), add a new arg to allow usecases like textual dumper to get all data members in one API: sframe_decoder_get_funcdesc_v3. To keep the APIs symmetric looking, add new arg to sframe_encoder_add_funcdesc_v3 too. Since bfd uses these APIs, carry out the mechanical change in the respective APIs too. And of course, the testsuite which exercises these APIs. bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Get and set func_info2. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Pass 0 for func_info2 for SFrame FDE for PLT. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (output_sframe_funcdesc): Emit the uint8_t for func_info2. libsframe/ * sframe-dump.c (dump_sframe_func_with_fres): * sframe.c (sframe_fde_tbl_init): Handle the new additional member. (sframe_encoder_write_fde): Likewise. * sframe.c (sframe_decoder_get_funcdesc_v3): Update func_info2. libsframe/testsuite/ * libsframe.decode/DATA2: Update data file with SFrame section data. * libsframe.encode/encode-1.c: Pass 0 for func_info2 arg. * libsframe.find/findfre-1.c: Likewise. * libsframe.find/findfunc-1.c: Likewise. * libsframe.find/plt-findfre-1.c: Likewise. * libsframe.find/plt-findfre-2.c: Likewise. include/ * sframe.h: Add new uint8_t sfde_func_info2 to sframe_func_desc_entry_v3. * sframe-api.h (sframe_decoder_get_funcdesc_v3): New arg. (sframe_encoder_add_funcdesc_v3): Likewise.
2026-01-15 16:42:17 -08:00
------------------------------------------------------------
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
8 7 6 5 0 */
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
uint8_t sfda_func_info2;
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
/* Size of the block of repeating insns. Used for SFrame FDEs of type
SFRAME_V3_FDE_PCTYPE_MASK. */
[SFrame-V3] include: gas: libsframe: split FDE into idx and attr This patch introduces a structural change to the SFrame V3 format. It shifts the SFrame Function Descriptor Entry (FDE) (a physical entity in SFrame V2) into a conceptual one in SFrame V3, such that an FDE is now split into two distinct parts to optimize the binary search table and data organization: - FDE Index (sframe_func_desc_idx_v3): This structure contains the essential indexing information: the function start address offset, function size in bytes, and the offset to the SFrame FDE attribute/Frame Row Entries (FREs) area for the function. - FDE Attributes (sframe_func_desc_attr_v3): The metadata regarding the function (number and size of FREs, FDE type, and repetition block size etc.) is moved to a new structure. On-Disk Layout: In V3, the "Attributes" are now stored immediately preceding the SFrame FREs for that function. The sfde_func_start_fre_off now points to the attr structure, and the actual FREs follow immediately after. IOW, the "Attributes" are now moved to the FRE sub-section, located immediately preceding the FREs for the respective function. The above layout has the advantage that: a) its cleaner with separation between the index elements vs other data b) the index has better cache locality (by virtue of it being smaller than the layout in SFrame V2). c) As the format evolves, the guarantees of alignment for FDE index are easier to maintain. FDE attr, being in the SFrame FRE sub-section, carry no guarantees of alignment. This had been previously suggested and communicated in an earlier discussion on binutils mailling list https://inbox.sourceware.org/binutils/29b1f7b0-61ea-410c-8aca-d5dd6115e668@oracle.com/ The read/write paths in sframe.c are updated to account for this split. sframe_fde_tbl_init now requires access to the FRE buffer to populate the internal FDE table, as the attributes are no longer resident in the FDE section. flip_sframe is refactored into version-specific handlers (_v2 and _v3) because the endian-swapping logic now differs significantly. In V3, the iterator must jump from the FDE table to the FRE section to swap the attributes. Lastly, the two entities generating SFrame sections (GAS and GNU ld) both now must _not_ set the sfde_func_start_fre_off to zero, when the number of FREs is zero. This is because now there will be some valid attr data at that location. Backward Compatibility: Due to the need to support readelf/objdump for SFrame V2 sections, the patch explicitly maintains V2 support via separate code paths (e.g., flip_sframe_fdes_with_fres_v2) Note about alignment: Now that the sframe_func_desc_idx_v3 is refactored out of the conceptual SFrame FDE, SFrame FDE index member elements are at aligned boundaries again. The alignment property for SFrame FDE was broken from an ealier patch "[08/36] sframe: gas: libsframe: use uint16_t for num_fres of FDE" up until this one. include/ * sframe.h (sframe_func_desc_entry_v3): Remove sfde_func_num_fres, sfde_func_info, sfde_func_info2, and sfde_func_rep_size. Rename to sframe_func_desc_idx_v3. (sframe_func_desc_attr_v3): New SFrame FDE attribute structure. libsframe/ * sframe.c (sframe_fde_tbl_init): Add argument for FRE buffer. Read attributes from the FRE section for V3. (flip_fde_desc): Rename from flip_fde. Check size against sframe_func_desc_entry_v3. (flip_fde_attr_v3): New function. (sframe_decode_fde_desc_v2): New function extracted from sframe_decode_fde. (sframe_decode_fde_desc_v3): New function. (sframe_decode_fde_attr_v3): New function. (flip_sframe_fdes_with_fres_v2): New function for V2 flipping. (flip_sframe_fdes_with_fres_v3): New function for V3 flipping. (flip_sframe): Dispatch to version-specific flip functions. (sframe_decode): Pass FRE buffer to sframe_fde_tbl_init. (sframe_decoder_get_offsetof_fde_start_addr): Adjust for subset of sframe_func_desc_entry_v3 restructured into sframe_func_desc_idx_v3. (sframe_encoder_get_offsetof_fde_start_addr): Likewise. (sframe_find_fre): Skip attribute size to find FREs in V3. (sframe_decoder_get_fre): Likewise. (sframe_decoder_get_fres_buf): Likewise. (sframe_encoder_add_fre): Add attribute size to byte count. (sframe_encoder_add_fres_buf): Read attributes from buffer. (sframe_encoder_write_fde): Write only FDE index fields. (sframe_encoder_write_func_attr): New function. (sframe_encoder_write_sframe): Write FDE attributes before FREs. gas/ * gen-sframe.c (output_sframe_funcdesc): Do not reset sfde_func_start_fre_off to zero when zero num FREs. (output_sframe_func_desc_attr): New refactored out function. (output_sframe_internal): Invoke output_sframe_func_desc_attr. libsframe/testsuite/ * libsframe.decode/DATA2: Regenerate data file.
2026-01-15 16:43:23 -08:00
uint8_t sfda_func_rep_size;
} ATTRIBUTE_PACKED sframe_func_desc_attr_v3;
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
#define SFRAME_V3_FDE_FUNC_INFO(fde_pc_type, fre_type) \
(SFRAME_V2_FUNC_INFO (fde_pc_type, fre_type))
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
/* Mask for the ABI/arch specific FDE type (lower 5 bits). */
#define SFRAME_V3_FDE_TYPE_MASK 0x01f
/* Get the FDE type from the info2 byte. */
#define SFRAME_V3_FDE_TYPE(info2) \
((info2) & SFRAME_V3_FDE_TYPE_MASK)
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
#define SFRAME_V3_FDE_FRE_TYPE(info) (SFRAME_V2_FUNC_FRE_TYPE (info))
#define SFRAME_V3_FDE_PC_TYPE(info) (SFRAME_V2_FUNC_PC_TYPE (info))
#define SFRAME_V3_AARCH64_FDE_PAUTH_KEY(info) (SFRAME_V2_FUNC_PAUTH_KEY (info))
#define SFRAME_V3_FDE_SIGNAL_P(info) (((info) >> 7) & 0x1)
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
/* Set the FDE type in the info2 byte, preserving upper bits. */
#define SFRAME_V3_SET_FDE_TYPE(info2, fde_type) \
(((info2) & ~SFRAME_V3_FDE_TYPE_MASK) \
| ((fde_type) & SFRAME_V3_FDE_TYPE_MASK))
[SFrame-V3] sframe: gas: bfd: ld: format bump to version 3 Bump version to SFRAME_VERSION_3. Introduce a new definition of SFrame FDE for version 3, which is a duplicate of SFrame FDE in V2, for now. In other words, no changes to the format specification yet. GNU as emits SFrame V3 by default. SFrame encoder (ld) emits SFrame V3 sections. In a later commit, we will add a new command line option to gas: --gsframe-3 which will bind the implementation in gas to emit SFrame V3. Also, adjust the testcases for the new version string "SFRAME_VERSION_3". bfd/ * elf-sframe.c (_bfd_elf_merge_section_sframe): Linker emits the latest version by default. * elf64-s390.c (_bfd_s390_elf_create_sframe_plt): Linker emitted PLT sections are also SFRAME_VERSION_3. * elfxx-x86.c (_bfd_x86_elf_create_sframe_plt): Likewise. gas/ * gen-sframe.c (sframe_set_version): GAS emits SFrame V3 by default. (output_sframe): Likewise. libsframe/ * sframe-dump.c (dump_sframe): Enable dumping for both SFRAME_VERSION_2 and SFRAME_VERSION_3. include/ChangeLog: * sframe.h (SFRAME_VERSION_3): New definition. (SFRAME_VERSION): Current version is now SFRAME_VERSION_3. (SFRAME_V3_FDE_FUNC_INFO): New definition. (SFRAME_V3_FDE_FRE_TYPE): Likewise. (SFRAME_V3_FDE_PC_TYPE): Likewise. (SFRAME_V3_AARCH64_FDE_PAUTH_KEY): Likewise. (SFRAME_V3_FDE_UPDATE_PAUTH_KEY): Likewise. binutils/testsuite/ * all affected tests: Replace SFRAME_VERSION_2 with SFRAME_VERSION_3. gas/testsuite/ * all affected tests: Likewise. ld/testsuite/ * all affected tests: Likewise. libsframe/testsuite/ * all affected tests: Likewise.
2026-01-15 16:41:07 -08:00
#define SFRAME_V3_FDE_UPDATE_PAUTH_KEY(pauth_key, info) \
SFRAME_V2_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, info)
#define SFRAME_V3_FDE_UPDATE_SIGNAL_P(signal_p, info) \
((((signal_p) & 0x1) << 7) | ((info) & 0x7f))
#define SFRAME_V3_FLEX_FDE_CTRLWORD_ENCODE(reg, deref_p, reg_p) \
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
((((reg) << 0x3) | (0 << 0x2) | (((deref_p) & 0x1) << 0x1) | ((reg_p) & 0x1)))
#define SFRAME_V3_FLEX_FDE_CTRLWORD_REGNUM(data) ((data) >> 3)
#define SFRAME_V3_FLEX_FDE_CTRLWORD_DEREF_P(data) (((data) >> 1) & 0x1)
#define SFRAME_V3_FLEX_FDE_CTRLWORD_REG_P(data) ((data) & 0x1)
#define SFRAME_V3_FRE_RA_UNDEFINED_P(fre_info) \
(SFRAME_V2_FRE_RA_UNDEFINED_P (fre_info))
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
/* Size of stack frame offsets in an SFrame Frame Row Entry. A single
SFrame FRE has all offsets of the same size. Offset size may vary
across frame row entries. */
#define SFRAME_FRE_OFFSET_1B 0
#define SFRAME_FRE_OFFSET_2B 1
#define SFRAME_FRE_OFFSET_4B 2
/* In SFrame V3, with the addition of flexible FDE, usage of term "offsets"
(for the varlen data trailing the SFrame FRE) is inappropriate. Use the
terminology of "data word" instead. A single SFrame FRE has all data words
of the same size. Size of data words may vary across frame row entries. */
#define SFRAME_FRE_DATAWORD_1B SFRAME_FRE_OFFSET_1B
#define SFRAME_FRE_DATAWORD_2B SFRAME_FRE_OFFSET_2B
#define SFRAME_FRE_DATAWORD_4B SFRAME_FRE_OFFSET_4B
/* An SFrame Frame Row Entry can be SP or FP based. */
#define SFRAME_BASE_REG_FP 0
#define SFRAME_BASE_REG_SP 1
/* The index at which a specific offset is presented in the variable length
bytes of an FRE. */
#define SFRAME_FRE_CFA_OFFSET_IDX 0
/* The RA stack offset, if present, will always be at index 1 in the variable
length bytes of the FRE. */
#define SFRAME_FRE_RA_OFFSET_IDX 1
/* The FP stack offset may appear at offset 1 or 2, depending on the ABI as RA
may or may not be tracked. */
#define SFRAME_FRE_FP_OFFSET_IDX 2
s390: Represent FP without RA saved in SFrame If an architecture uses both SFrame RA and FP tracking SFrame assumes that the RA offset is the 2nd offset and the FP offset is the 3rd offset following a SFrame FRE. An architecture does not necessarily need to save both on the stack (or in register) at the same time or even at all. SFrame cannot represent FP without RA saved on stack (or in a register), since it cannot distinguish whether the 2nd offset is the RA or FP offset. For s390x use an invalid SFrame RA offset from CFA value of zero as padding to represent the FP being saved when the RA is not saved. This aligns with the existing invalid SFrame fixed RA offset from CFA value of zero. In a stack tracer this then also naturally falls into place, as it can skip restoring the RA in the topmost frame, if both the fixed RA offset (from SFrame header) and the RA offset (from FDE) are zero, without any need to test architecture-specific flags. include/ * sframe.h (SFRAME_FRE_RA_OFFSET_INVALID): New define. Used as padding offset. * sframe-api.h (sframe_fre_get_ra_offset): Add comment that for s390x an offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates that the RA is not saved. gas/ * gen-sframe.c (get_fre_num_offsets): For s390x account padding RA offset, if FP without RA saved. (sframe_get_fre_offset_size): Likewise. (output_sframe_row_entry): For s390x write a padding RA offset, if FP without RA needs to be represented. (sframe_do_fde): Enable FP without RA saved to be represented on s390x. libsframe/ * sframe.c (sframe_fre_get_ra_offset): Add comment that for s390x an offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates that the RA is not saved. * sframe-dump.c (dump_sframe_func_with_fres): Treat invalid RA offsets as if they were undefined. Display them as "U" to distinguish them. * doc/sframe-spec.texi (s390x): Document s390x-specific use of SFRAME_FRE_RA_OFFSET_INVALID to represent FP without RA saved. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Rename s390x-specific tests. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Rename to ... * cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.s: This. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.d: Likewise. Update test verification pattern accordingly. * cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s: Rename to ... * cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.s: This. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.d: Likewise. Update test verification pattern accordingly. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
/* Invalid RA offset. Currently used for s390x as padding to represent FP
without RA saved. */
#define SFRAME_FRE_RA_OFFSET_INVALID 0
typedef struct sframe_fre_info
{
/* Information about
- 1 bit: base reg for CFA
- 4 bits: Number of data words (N). Typically for default FDE type, a
value of upto 3 suffices to track all three of CFA, FP and RA (fixed
implicit order).
- 2 bits: information about size of the data words (S) in bytes.
Valid values are SFRAME_FRE_DATAWORD_1B, SFRAME_FRE_DATAWORD_2B,
SFRAME_FRE_DATAWORD_4B.
- 1 bit: Mangled RA state bit (aarch64 only).
----------------------------------------------------------------------------------
| Mangled-RA (aarch64) | Size of Data Words | Number of Data Words | base_reg |
s390: Initial support to generate .sframe from CFI directives in assembler This introduces initial support to generate .sframe from CFI directives in assembler on s390 64-bit (s390x). Due to SFrame V2 format limitations it has the following limitations, some of them getting addressed by subsequent patches, which cause generation of SFrame FDE to be skipped: - SFrame FP/RA tracking only supports register contents being saved on the stack (i.e. .cfi_offset). It does not support FP/RA register contents being saved in other registers (i.e. .cfi_register). GCC on s390x can be observed to save the FP/RA register contents in floating- point registers, but only in leaf functions. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP/RA saved in register in SFrame". - SFrame FP/RA tracking cannot represent FP without RA saved. This is because the format assumes SFrame FDE offset2 to be the RA offset, if there are two offsets, and offset3 to be the FP offset, if there are three offsets. There is no mean to distinguish whether offset2 is the RA or FP offset, if there are only two offsets. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP without RA saved in SFrame". - SFrame assumes a dedicated FP register number. The s390x ELF ABI [1] does only designate register 11 as preferred FP register number. In general GCC and Clang on s390x use register 11 as frame pointer. GCC on s390x can be observed to use register 14 as frame pointer in the stack clash protector in the function prologue. glibc on s390x contains hand-written assembler code that uses register 12 as frame pointer. This s390x support is largely based on the AArch64 support from commit b52c4ee46657 ("gas: generate .sframe from CFI directives"). The SFrame ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG is introduced for s390x and added to the SFrame format specification. The s390x ELF ABI [1] specifies the following C calling conventions for s390x architecture: - Register 15 is the stack pointer (SP). - Register 14 contains the return address (RA) at function entry. - There is no dedicated frame pointer register. Register 11 is the preferred frame pointer (FP). [2] GCC and Clang in general use register 11 as frame pointer. - The CFA is defined as SP at call site +160. [3] The SP at call site can therefore be derived from the CFA using a SP value offset from CFA of -160. The s390x ELF ABI [1] does not assign any standard save slot to each register in the register save area of a stack frame. Neither the return address (RA, r14) nor preferred frame pointer (FP, r11) necessarily need to be saved. Therefore SFrame RA and FP tracking is used. Support for SFrame on s390 is only enabled for the 64-bit s390x ELF ABI (z/Architecture with 64-bit addressing mode). It is disabled for the 32-bit s390 ELF ABI (ESA/390 or z/Architecture with 32-bit addressing mode). s390x-specific SFrame assembler and linker tests are added, including error tests for use of a non-preferred frame pointer (FP) register and specification of a non-default return address (RA) register. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit f00421825979 ("Add information about the frame pointer register"), https://github.com/IBM/s390x-abi/commit/f00421825979 [3]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h: Add reference to s390x architecture in comments. (SFRAME_ABI_S390X_ENDIAN_BIG): Define SFrame ABI/arch identifier for s390x. (SFRAME_S390X_SP_VAL_OFFSET): Define s390x-specific SP value offset from CFA. libsframe/ * sframe.c (need_swapping): Add SFRAME_ABI_S390X_ENDIAN_BIG. * doc/sframe-spec.texi (SFRAME_ABI_S390X_ENDIAN_BIG, s390x, SFRAME_S390X_SP_VAL_OFFSET): Document SFrame ABI/arch identifier for s390x, add references to s390x architecture, and document s390x-specifics, such as the SP value offset from CFA of -160. gas/ * config/tc-s390.h: s390x support to generate .sframe from CFI directives in assembler. (support_sframe_p): Define. (SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG): Define. (sframe_ra_tracking_p): Define. (sframe_cfa_ra_offset): Define. (sframe_get_abi_arch): Define. * config/tc-s390.c: s390x support to generate .sframe from CFI directives in assembler. (s390_sframe_cfa_sp_reg, s390_sframe_cfa_fp_reg, s390_sframe_cfa_ra_reg): New. Initialize to DWARF register numbers of stack pointer (SP, r15), preferred frame pointer (FP, r11), and return address (RA, r14) registers. (s390_support_sframe_p): New function. Return true if s390x. (s390_sframe_ra_tracking_p): New function. Return true. (s390_sframe_cfa_ra_offset): New function. Return SFRAME_CFA_FIXED_RA_INVALID. (s390_sframe_get_abi_arch): New function. Return SFRAME_ABI_S390X_ENDIAN_BIG if s390x, otherwise zero. * gen-sframe.c: Add reference to s390x architecture in comments. (sframe_xlate_do_val_offset): Add support for s390x-specific SFRAME_S390X_SP_VAL_OFFSET. * NEWS: Add news entry. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests for s390x. Add s390x-specific SFrame (error) tests. * gas/cfi-sframe/cfi-sframe-s390x-1.d: New s390x-specific SFrame test. * gas/cfi-sframe/cfi-sframe-s390x-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-1.d: New s390x-specific SFrame error test that uses a non-default frame-pointer register as CFA base register. * gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-3.d: New s390x-specific SFrame error test that uses a non-default return address register. * gas/cfi-sframe/cfi-sframe-s390x-err-3.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d: New s390x- specific SFrame test that saves RA and FP individually on the stack. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually, to trigger FP without RA saved. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: New s390x-specific SFrame error test that saves RA and FP individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s: Likewise. ld/testsuite/ * ld-s390/s390.exp: Add simple SFrame test. * ld-s390/sframe-simple-1.d: New simple SFrame test. * ld-s390/sframe-bar.s: Likewise. * ld-s390/sframe-foo.s: Likewise. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
| Unused (amd64, s390x)| | | |
----------------------------------------------------------------------------------
8 7 5 1 0
*/
uint8_t fre_info;
} sframe_fre_info;
/* Macros to compose and decompose FRE info. */
/* Note: Set mangled_ra_p to zero by default. */
#define SFRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \
(((0 & 0x1) << 7) | (((offset_size) & 0x3) << 5) | \
(((offset_num) & 0xf) << 1) | ((base_reg_id) & 0x1))
/* Set the mangled_ra_p bit as indicated. */
#define SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P(mangled_ra_p, fre_info) \
((((mangled_ra_p) & 0x1) << 7) | ((fre_info) & 0x7f))
#define SFRAME_V1_FRE_CFA_BASE_REG_ID(data) ((data) & 0x1)
#define SFRAME_V1_FRE_OFFSET_COUNT(data) (((data) >> 1) & 0xf)
#define SFRAME_V1_FRE_OFFSET_SIZE(data) (((data) >> 5) & 0x3)
#define SFRAME_V1_FRE_MANGLED_RA_P(data) (((data) >> 7) & 0x1)
gas: sframe: Represent .cfi_undefined RA as FRE without offsets In DWARF CFI an "undefined" register rule for the return address (RA) register indicates that there is no return address and the stack trace is complete. Represent DW_CFA_undefined as SFrame FRE without any offsets, so that a stack tracer implementation can use this as indication that an outermost frame has been reached and the stack trace is complete. This representation is backward compatible, as existing stack tracers should already deal with the case, that an SFrame FRE a so far invalid offset count of zero and stop the trace. include/ * sframe.h (SFRAME_V2_FRE_RA_UNDEFINED_P): New macro to test FRE info word for RA undefined (FRE without any offsets). binutils/ * NEWS: Mention SFrame can represent an undefined RA as FRE without any offsets. gas/ * gen-sframe.h (struct sframe_row_entry): Add ra_undefined_p flag. * gen-sframe.c (sframe_row_entry_new): Initialize ra_undefined_p flag to not set. (sframe_row_entry_initialize): Treat ra_undefined_p flag as sticky. (sframe_fre_set_ra_track): Reset ra_undefined_p flag. (sframe_xlate_do_restore): Reset ra_undefined_p flag to saved state. (sframe_xlate_do_same_value): Reset ra_undefined_p flag. (sframe_xlate_do_cfi_undefined): For RA set ra_undefined_p flag. (output_sframe_row_entry): Represent RA undefined as SFrame FRE without any offsets and FRE info word fields zeroed. * NEWS: Mention assembler represents .cfi_undefined RA in SFrame as FRE without any offsets. libsframe/ * doc/sframe-spec.texi (Changes from Version 1 to Version 2): Mention that a SFrame FRE without any offsets flag indicates an outermost frame with an undefined RA. (fre_offset_count): Document that a FRE offset count of zero indicates an outermost frame with an undefined RA. * sframe.c (sframe_get_fre_ra_undefined_p): Use macro SFRAME_V2_FRE_RA_UNDEFINED_P. (sframe_fre_get_fp_offset, sframe_fre_get_ra_offset): Do not return fixed FP/RA offset if RA undefined. * sframe-dump.c (dump_sframe_func_with_fres): Show FRE without any offsets as "RA undefined". gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Run tests for .cfi_undefined RA on AArch64, s390x, and x86-64. * gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.d: Add test for .cfi_undefined RA on AArch64. * gas/cfi-sframe/cfi-sframe-aarch64-ra-undefined-1.s: Likewise. * as/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.d: Add test for .cfi_undefined RA on s390x. * gas/cfi-sframe/cfi-sframe-s390x-ra-undefined-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.d: Add test for .cfi_undefined RA on x86-64. * gas/cfi-sframe/cfi-sframe-x86_64-ra-undefined-1.s: Likewise. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-10-15 17:45:48 +02:00
#define SFRAME_V2_FRE_RA_UNDEFINED_P(data) (SFRAME_V1_FRE_OFFSET_COUNT (data) == 0)
/* In SFrame V3, with the introduction of flexible FDE type
SFRAME_FDE_TYPE_FLEX, the variable-length data following SFrame FRE header
may contain unsigned Control Data Words or signed Offset Data Words. These
are referred to as 'Data Words'. Note that the usage of the term 'Word'
here is colloquial, the size of a data word is determined by applicable
bits. */
#define SFRAME_V3_FRE_DATAWORD_COUNT(data) \
SFRAME_V1_FRE_OFFSET_COUNT (data)
#define SFRAME_V3_FRE_DATAWORD_SIZE(data) \
SFRAME_V1_FRE_OFFSET_SIZE (data)
/* SFrame Frame Row Entry definitions.
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
Used for Default FDEs in AMD64, AARCH64, and s390x.
An SFrame Frame Row Entry is a self-sufficient record which contains
information on how to generate the stack trace for the specified range of
PCs. Each SFrame Frame Row Entry is followed by S*N bytes, where:
S is the size of the stack frame offset for the FRE, and
N is the number of stack frame offsets in the FRE
[SFrame-V3] include: sframe: reserve 5 bits for new FDE types In SFrame V2, the FDE representation caters to the most common cases of stack trace metadata: - CFA is SP/FP based, - FP/RA offsets, if present are CFA based (except some cases in s390x where reg can be encoded). Introduce an additional FDE type SFRAME_FDE_TYPE_FLEX, which can encode a more flexible set of CFA, FP and RA recovery rules. Some of the patterns supported include: - CFA may be non-SP/FP based. - CFA, FP may encode dereferencing of register after offset adjustment - RA may be in a non-default register. The important bit here is that since SFrame does not track all callee-saved registers, the above-mentioned recovery rules must only be done for topmost frames (by the stack tracer). Adding a new FDE type does have implications for a stack tracer in that it needs to: - Check the FDE type before interpreting the variable length bytes trailing the SFrame FRE header as stack offsets. - If the FDE type is SFRAME_FDE_TYPE_FLEX, and the recovery rules employ the use of any non-SP/FP based register, the stack tracer must proceed only if it is the topmost frame on stack. For CFA, RA, and FP, up to two "offsets" may be used. The two offsets represent the information as follows: - (minimum 8-bit) offset1 to encode register like: (regnum << 3) | unused << 2 | deref << 1 | reg_p (=1) - offset2 to encode offset: offset reg_p = 1 indicates a register, reg_p = 0 indicates CFA. The offsets are in the usual order: CFA, RA, FP if present. For example, for FP/RA tracking, a) If the reg is REG1 for FP/RA tracking, - Encoding: + offset1 to encode register: (REG1 << 3) | unused << 2 | deref << 1 | reg_p (=1) + offset2 to encode offset: offset - Action: + if deref, FP/RA = \*(REG1 + offset) (e.g., seen for FP recovery with certain DRAP patterns on x86_64) + if no deref, FP/RA = REG1 + offset b) If the reg is CFA for FP/RA tracking, - Encoding: + [=Effectively Padding] offset1 to encode register: (( 0 << 3 ) | unused << 2 | 0 << 1 | reg_p (=0)) + offset2 to encode offset: offset - Action: + if deref, FP/RA = *(CFA + offset) + if no deref, FP/RA = CFA + offset (pattern shouldnt be seen for RA) Next for CFA tracking, - Action: + if deref, CFA = *(reg + offset) (e.g., seen for CFA recovery in some stack realignment patterns on AMD64) + if no deref, CFA = reg + offset (e.g., for .cfi_def_cfa 2, 8, or .cfi_def_cfa 10, 0) Expected usage of this FDE type is quite low (DRAP on x86_64). NB: In SFrame V2, we did use the the term 'FDE Type' for the two designated 'PC Type' for the SFrame FDEs (SFRAME_FDE_TYPE_PCINC, SFRAME_FDE_TYPE_PCMASK). In hindsight, 'FDE Type' was inappropriate term. In a subsequent commit, we will fix this terminology for SFrame V3. include/ * sframe.h (SFRAME_FDE_TYPE_FLEX): New SFrame FDE type. (SFRAME_V3_FDE_TYPE_MASK): New constant definition. (SFRAME_V3_FDE_TYPE): New macro definition. (SFRAME_V3_SET_FDE_TYPE): Likewise. (SFRAME_V3_FLEX_FDE_REG_ENCODE): Macro to encode register in the SFrame offset data. (SFRAME_V3_FLEX_FDE_OFFSET_REG_NUM): New definition. (SFRAME_V3_FLEX_FDE_OFFSET_REG_DEREF_P): Likewise. (SFRAME_V3_FLEX_FDE_OFFSET_REG_P): Likewise.
2026-01-15 16:42:21 -08:00
The interpretation of FRE stack offsets for default FDEs is ABI-specific:
AMD64:
offset1 (interpreted as CFA = BASE_REG + offset1)
if FP is being tracked
offset2 (intrepreted as FP = CFA + offset2)
fi
AARCH64:
offset1 (interpreted as CFA = BASE_REG + offset1)
if FP is being tracked (in other words, if frame record created)
offset2 (interpreted as RA = CFA + offset2)
offset3 (intrepreted as FP = CFA + offset3)
fi
Note that in AAPCS64, a frame record, if created, will save both FP and
LR on stack.
s390: Represent FP without RA saved in SFrame If an architecture uses both SFrame RA and FP tracking SFrame assumes that the RA offset is the 2nd offset and the FP offset is the 3rd offset following a SFrame FRE. An architecture does not necessarily need to save both on the stack (or in register) at the same time or even at all. SFrame cannot represent FP without RA saved on stack (or in a register), since it cannot distinguish whether the 2nd offset is the RA or FP offset. For s390x use an invalid SFrame RA offset from CFA value of zero as padding to represent the FP being saved when the RA is not saved. This aligns with the existing invalid SFrame fixed RA offset from CFA value of zero. In a stack tracer this then also naturally falls into place, as it can skip restoring the RA in the topmost frame, if both the fixed RA offset (from SFrame header) and the RA offset (from FDE) are zero, without any need to test architecture-specific flags. include/ * sframe.h (SFRAME_FRE_RA_OFFSET_INVALID): New define. Used as padding offset. * sframe-api.h (sframe_fre_get_ra_offset): Add comment that for s390x an offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates that the RA is not saved. gas/ * gen-sframe.c (get_fre_num_offsets): For s390x account padding RA offset, if FP without RA saved. (sframe_get_fre_offset_size): Likewise. (output_sframe_row_entry): For s390x write a padding RA offset, if FP without RA needs to be represented. (sframe_do_fde): Enable FP without RA saved to be represented on s390x. libsframe/ * sframe.c (sframe_fre_get_ra_offset): Add comment that for s390x an offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates that the RA is not saved. * sframe-dump.c (dump_sframe_func_with_fres): Treat invalid RA offsets as if they were undefined. Display them as "U" to distinguish them. * doc/sframe-spec.texi (s390x): Document s390x-specific use of SFRAME_FRE_RA_OFFSET_INVALID to represent FP without RA saved. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Rename s390x-specific tests. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Rename to ... * cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.s: This. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-2.d: Likewise. Update test verification pattern accordingly. * cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s: Rename to ... * cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.s: This. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.d: Likewise. Update test verification pattern accordingly. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
s390x:
offset1 (interpreted as CFA = BASE_REG + offset1)
if RA is being tracked
offset2 (interpreted as RA = CFA + offset2; an offset value of
SFRAME_FRE_RA_OFFSET_INVALID indicates a dummy padding RA offset
to represent FP without RA saved on stack)
if FP is being tracked
offset3 (intrepreted as FP = CFA + offset3)
fi
else
if FP is being tracked
offset2 (intrepreted as FP = CFA + offset2)
fi
fi
[SFrame-V3] sframe: s390: gas: testsuite: enable flex FDE for s390x This commit amalgamates a patch set proposed by Jens Remus to enable the SFrame Version 3 Flexible FDE Type (SFRAME_FDE_TYPE_FLEX) generation for the s390x ABI. Previously, s390x relied on architecture-specific encoding (shifting register numbers into offset fields) to represent register recovery rules. This limited the complexity of CFI that could be supported. With Flex FDE enabled: - s390x can now represent .cfi_def_cfa using non-SP/FP registers. - The architecture-specific function s390_sframe_xlate_do_register () in GAS is replaced by the generic Flex FDE generation path. - The SFrame V3 specific macros for s390x register encoding are removed from libsframe/include, as the generic Flex FDE format handles explicit register columns natively. The testsuite is updated to replace negative tests (which asserted warnings or empty SFrame generation for these patterns) with positive tests verifying valid Flex FDE generation. Co-authored-by: Jens Remus <jremus@linux.ibm.com> gas/ * config/tc-s390.c (s390_support_flex_fde_p): Return true to enable Flex FDE generation. * gen-sframe.c (s390_sframe_xlate_do_register): Disable s390x specific implementation. (sframe_xlate_do_register): Invoke generic Flex FDE path now that flex FDE generation is supported. gas/testsuite/ * gas/cfi-sframe/cfi-sframe-s390x-err-1.d: Removed. * gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Moved to... * gas/cfi-sframe/cfi-sframe-s390x-non-spfp-cfa-1.s: ...here. * gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Removed. * gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Moved to... * gas/cfi-sframe/cfi-sframe-s390x-non-spfp-cfa-2.s: ...here. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d: Update to expect Flex FDE output. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-2.d: Likewise. * gas/cfi-sframe/cfi-sframe.exp: Run renamed tests. include/ * sframe.h (SFRAME_V3_S390X_OFFSET_IS_REGNUM): Remove. (SFRAME_V3_S390X_OFFSET_ENCODE_REGNUM): Remove. (SFRAME_V3_S390X_OFFSET_DECODE_REGNUM): Remove. libsframe/ * sframe-dump.c (sframe_s390x_offset_regnum_p): Return false for SFrame V3. (sframe_s390x_offset_decode_regnum): Remove V3 support.
2026-01-15 16:43:58 -08:00
Note that in s390x, if a FP/RA is to be restored from a register, flex FDEs
are used in SFrame V3. In SFrame V2, default FDEs were used: the
least-significant bit of the offset was set to indicate that the encoded
value is a DWARF register number shifted to the left by 1.
*/
/* Used when SFRAME_FRE_TYPE_ADDR1 is specified as FRE type. */
typedef struct sframe_frame_row_entry_addr1
{
/* Start address of the frame row entry. Encoded as an 1-byte unsigned
offset, relative to the start address of the function. */
uint8_t sfre_start_address;
sframe_fre_info sfre_info;
} ATTRIBUTE_PACKED sframe_frame_row_entry_addr1;
/* Upper limit of start address in sframe_frame_row_entry_addr1
is 0x100 (not inclusive). */
#define SFRAME_FRE_TYPE_ADDR1_LIMIT \
(1ULL << ((SFRAME_FRE_TYPE_ADDR1 + 1) * 8))
/* Used when SFRAME_FRE_TYPE_ADDR2 is specified as FRE type. */
typedef struct sframe_frame_row_entry_addr2
{
/* Start address of the frame row entry. Encoded as an 2-byte unsigned
offset, relative to the start address of the function. */
uint16_t sfre_start_address;
sframe_fre_info sfre_info;
} ATTRIBUTE_PACKED sframe_frame_row_entry_addr2;
/* Upper limit of start address in sframe_frame_row_entry_addr2
is 0x10000 (not inclusive). */
#define SFRAME_FRE_TYPE_ADDR2_LIMIT \
(1ULL << ((SFRAME_FRE_TYPE_ADDR2 * 2) * 8))
/* Used when SFRAME_FRE_TYPE_ADDR4 is specified as FRE type. */
typedef struct sframe_frame_row_entry_addr4
{
/* Start address of the frame row entry. Encoded as a 4-byte unsigned
offset, relative to the start address of the function. */
uint32_t sfre_start_address;
sframe_fre_info sfre_info;
} ATTRIBUTE_PACKED sframe_frame_row_entry_addr4;
/* Upper limit of start address in sframe_frame_row_entry_addr2
is 0x100000000 (not inclusive). */
#define SFRAME_FRE_TYPE_ADDR4_LIMIT \
(1ULL << ((SFRAME_FRE_TYPE_ADDR4 * 2) * 8))
s390: Store SFrame CFA offset adjusted In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI [1] defines the CFA as stack pointer (SP) at call site +160. [2] Therefore the minimum CFA offset from CFA base register on s390x is 160. This does not fit into a signed 8-bit integer and therefore effectively prevents any use of signed 8-bit SFrame offsets on s390x. For s390x store the CFA offset from CFA base register adjusted by -160 to enable the use of signed 8-bit SFrame offsets. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ADJUSTMENT): Define s390x-specific CFA offset adjustment. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): New s390x-specific macros. Use SFRAME_S390X_CFA_OFFSET_ADJUSTMENT to en-/decode CFA offset. bfd/ * elf64-s390.c (elf_s390x_sframe_plt_fre): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted and switch to 8-bit offsets. gas/ * gen-sframe.c (sframe_fre_set_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted. (sframe_fre_get_cfa_offset): New helper. For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. (sframe_xlate_do_def_cfa_register): Use new helper sframe_fre_get_cfa_offset. libsframe/ * sframe.c (sframe_fre_get_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ADJUSTMENT, SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Document s390x-specific adjustment of CFA offset. libsframe/testsuite/ * libsframe.find/plt-findfre-2.c (add_plt0_fde, add_pltn_fde): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE to enable use of 1-byte SFrame offsets. Suggested-by: Indu Bhagat <indu.bhagat@oracle.com> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
/* On s390x, the CFA offset from CFA base register is by definition a minimum
s390: Store SFrame CFA offset adjusted and scaled down In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI defines the stack pointer (SP) to be 8-byte aligned [1] and the CFA as SP at call site + 160 [2]. The CFA offset from CFA base register is therefore always a multiple of 8. On s390x store the SFrame CFA offset from CFA base register scaled down by the s390x-specific CFA alignment factor of 8, in addition to the adjustment by the s390x-specific CFA adjustment of -160, to further improve the use of signed 8-bit SFrame offsets. This is similar to the DWARF data alignment factor getting factored out from certain offsets stored in DWARF CFI. [1]: s390x ELF ABI, sections "Register Roles" and "Stack Frame Allocation", https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Define s390x-specific CFA offset alignment factor. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Scale down/up by SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR. libsframe/ * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Document s390x- specific CFA offset alignment factor. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
of 160. Store it adjusted by -160 to enable use of 8-bit SFrame offsets.
Additionally scale by an alignment factor of 8, as the SP and thus CFA
offset on s390x is always 8-byte aligned. */
s390: Store SFrame CFA offset adjusted In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI [1] defines the CFA as stack pointer (SP) at call site +160. [2] Therefore the minimum CFA offset from CFA base register on s390x is 160. This does not fit into a signed 8-bit integer and therefore effectively prevents any use of signed 8-bit SFrame offsets on s390x. For s390x store the CFA offset from CFA base register adjusted by -160 to enable the use of signed 8-bit SFrame offsets. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ADJUSTMENT): Define s390x-specific CFA offset adjustment. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): New s390x-specific macros. Use SFRAME_S390X_CFA_OFFSET_ADJUSTMENT to en-/decode CFA offset. bfd/ * elf64-s390.c (elf_s390x_sframe_plt_fre): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted and switch to 8-bit offsets. gas/ * gen-sframe.c (sframe_fre_set_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted. (sframe_fre_get_cfa_offset): New helper. For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. (sframe_xlate_do_def_cfa_register): Use new helper sframe_fre_get_cfa_offset. libsframe/ * sframe.c (sframe_fre_get_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ADJUSTMENT, SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Document s390x-specific adjustment of CFA offset. libsframe/testsuite/ * libsframe.find/plt-findfre-2.c (add_plt0_fde, add_pltn_fde): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE to enable use of 1-byte SFrame offsets. Suggested-by: Indu Bhagat <indu.bhagat@oracle.com> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
#define SFRAME_S390X_CFA_OFFSET_ADJUSTMENT SFRAME_S390X_SP_VAL_OFFSET
s390: Store SFrame CFA offset adjusted and scaled down In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI defines the stack pointer (SP) to be 8-byte aligned [1] and the CFA as SP at call site + 160 [2]. The CFA offset from CFA base register is therefore always a multiple of 8. On s390x store the SFrame CFA offset from CFA base register scaled down by the s390x-specific CFA alignment factor of 8, in addition to the adjustment by the s390x-specific CFA adjustment of -160, to further improve the use of signed 8-bit SFrame offsets. This is similar to the DWARF data alignment factor getting factored out from certain offsets stored in DWARF CFI. [1]: s390x ELF ABI, sections "Register Roles" and "Stack Frame Allocation", https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Define s390x-specific CFA offset alignment factor. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Scale down/up by SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR. libsframe/ * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Document s390x- specific CFA offset alignment factor. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
#define SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR 8
s390: Store SFrame CFA offset adjusted In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI [1] defines the CFA as stack pointer (SP) at call site +160. [2] Therefore the minimum CFA offset from CFA base register on s390x is 160. This does not fit into a signed 8-bit integer and therefore effectively prevents any use of signed 8-bit SFrame offsets on s390x. For s390x store the CFA offset from CFA base register adjusted by -160 to enable the use of signed 8-bit SFrame offsets. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ADJUSTMENT): Define s390x-specific CFA offset adjustment. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): New s390x-specific macros. Use SFRAME_S390X_CFA_OFFSET_ADJUSTMENT to en-/decode CFA offset. bfd/ * elf64-s390.c (elf_s390x_sframe_plt_fre): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted and switch to 8-bit offsets. gas/ * gen-sframe.c (sframe_fre_set_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted. (sframe_fre_get_cfa_offset): New helper. For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. (sframe_xlate_do_def_cfa_register): Use new helper sframe_fre_get_cfa_offset. libsframe/ * sframe.c (sframe_fre_get_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ADJUSTMENT, SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Document s390x-specific adjustment of CFA offset. libsframe/testsuite/ * libsframe.find/plt-findfre-2.c (add_plt0_fde, add_pltn_fde): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE to enable use of 1-byte SFrame offsets. Suggested-by: Indu Bhagat <indu.bhagat@oracle.com> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
#define SFRAME_V2_S390X_CFA_OFFSET_ENCODE(offset) \
s390: Store SFrame CFA offset adjusted and scaled down In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI defines the stack pointer (SP) to be 8-byte aligned [1] and the CFA as SP at call site + 160 [2]. The CFA offset from CFA base register is therefore always a multiple of 8. On s390x store the SFrame CFA offset from CFA base register scaled down by the s390x-specific CFA alignment factor of 8, in addition to the adjustment by the s390x-specific CFA adjustment of -160, to further improve the use of signed 8-bit SFrame offsets. This is similar to the DWARF data alignment factor getting factored out from certain offsets stored in DWARF CFI. [1]: s390x ELF ABI, sections "Register Roles" and "Stack Frame Allocation", https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Define s390x-specific CFA offset alignment factor. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Scale down/up by SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR. libsframe/ * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Document s390x- specific CFA offset alignment factor. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
(((offset) + SFRAME_S390X_CFA_OFFSET_ADJUSTMENT) \
/ SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR)
s390: Store SFrame CFA offset adjusted In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI [1] defines the CFA as stack pointer (SP) at call site +160. [2] Therefore the minimum CFA offset from CFA base register on s390x is 160. This does not fit into a signed 8-bit integer and therefore effectively prevents any use of signed 8-bit SFrame offsets on s390x. For s390x store the CFA offset from CFA base register adjusted by -160 to enable the use of signed 8-bit SFrame offsets. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ADJUSTMENT): Define s390x-specific CFA offset adjustment. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): New s390x-specific macros. Use SFRAME_S390X_CFA_OFFSET_ADJUSTMENT to en-/decode CFA offset. bfd/ * elf64-s390.c (elf_s390x_sframe_plt_fre): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted and switch to 8-bit offsets. gas/ * gen-sframe.c (sframe_fre_set_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted. (sframe_fre_get_cfa_offset): New helper. For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. (sframe_xlate_do_def_cfa_register): Use new helper sframe_fre_get_cfa_offset. libsframe/ * sframe.c (sframe_fre_get_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ADJUSTMENT, SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Document s390x-specific adjustment of CFA offset. libsframe/testsuite/ * libsframe.find/plt-findfre-2.c (add_plt0_fde, add_pltn_fde): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE to enable use of 1-byte SFrame offsets. Suggested-by: Indu Bhagat <indu.bhagat@oracle.com> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
#define SFRAME_V2_S390X_CFA_OFFSET_DECODE(offset) \
s390: Store SFrame CFA offset adjusted and scaled down In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI defines the stack pointer (SP) to be 8-byte aligned [1] and the CFA as SP at call site + 160 [2]. The CFA offset from CFA base register is therefore always a multiple of 8. On s390x store the SFrame CFA offset from CFA base register scaled down by the s390x-specific CFA alignment factor of 8, in addition to the adjustment by the s390x-specific CFA adjustment of -160, to further improve the use of signed 8-bit SFrame offsets. This is similar to the DWARF data alignment factor getting factored out from certain offsets stored in DWARF CFI. [1]: s390x ELF ABI, sections "Register Roles" and "Stack Frame Allocation", https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Define s390x-specific CFA offset alignment factor. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Scale down/up by SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR. libsframe/ * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR): Document s390x- specific CFA offset alignment factor. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
(((offset) * SFRAME_S390X_CFA_OFFSET_ALIGNMENT_FACTOR) \
- SFRAME_S390X_CFA_OFFSET_ADJUSTMENT)
s390: Store SFrame CFA offset adjusted In SFrame V2 the size of the offsets following an SFrame FRE can be either signed 8-bit, 16-bit, or 32-bit integer, with the largest offset determining their size: 1. CFA offset from CFA base register 2. RA (stack save slot) offset from CFA, usually -48 on s390x if saved 3. FP (stack save slot) offset from CFA, usually -72 on s390x if saved The FP and RA offsets from CFA, when FP/RA saved on the stack, usually have fixed values that fit into signed 8-bit SFrame offsets. Likewise the DWARF register numbers on s390x of general registers (GR; 0-15) and floating-point registers (FPR; 16-31), when FP/RA saved in registers. With that the CFA offset from CFA base register has the greatest impact on the signed SFrame offset size. The s390x ELF ABI [1] defines the CFA as stack pointer (SP) at call site +160. [2] Therefore the minimum CFA offset from CFA base register on s390x is 160. This does not fit into a signed 8-bit integer and therefore effectively prevents any use of signed 8-bit SFrame offsets on s390x. For s390x store the CFA offset from CFA base register adjusted by -160 to enable the use of signed 8-bit SFrame offsets. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h (SFRAME_S390X_CFA_OFFSET_ADJUSTMENT): Define s390x-specific CFA offset adjustment. (SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): New s390x-specific macros. Use SFRAME_S390X_CFA_OFFSET_ADJUSTMENT to en-/decode CFA offset. bfd/ * elf64-s390.c (elf_s390x_sframe_plt_fre): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted and switch to 8-bit offsets. gas/ * gen-sframe.c (sframe_fre_set_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_ENCODE on CFA offset to store it adjusted. (sframe_fre_get_cfa_offset): New helper. For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. (sframe_xlate_do_def_cfa_register): Use new helper sframe_fre_get_cfa_offset. libsframe/ * sframe.c (sframe_fre_get_cfa_offset): For s390x use SFRAME_V2_S390X_CFA_OFFSET_DECODE on CFA offset to undo its adjustment. * doc/sframe-spec.texi (s390x, SFRAME_S390X_CFA_OFFSET_ADJUSTMENT, SFRAME_V2_S390X_CFA_OFFSET_ENCODE, SFRAME_V2_S390X_CFA_OFFSET_DECODE): Document s390x-specific adjustment of CFA offset. libsframe/testsuite/ * libsframe.find/plt-findfre-2.c (add_plt0_fde, add_pltn_fde): Use SFRAME_V2_S390X_CFA_OFFSET_ENCODE to enable use of 1-byte SFrame offsets. Suggested-by: Indu Bhagat <indu.bhagat@oracle.com> Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
s390: Initial support to generate .sframe from CFI directives in assembler This introduces initial support to generate .sframe from CFI directives in assembler on s390 64-bit (s390x). Due to SFrame V2 format limitations it has the following limitations, some of them getting addressed by subsequent patches, which cause generation of SFrame FDE to be skipped: - SFrame FP/RA tracking only supports register contents being saved on the stack (i.e. .cfi_offset). It does not support FP/RA register contents being saved in other registers (i.e. .cfi_register). GCC on s390x can be observed to save the FP/RA register contents in floating- point registers, but only in leaf functions. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP/RA saved in register in SFrame". - SFrame FP/RA tracking cannot represent FP without RA saved. This is because the format assumes SFrame FDE offset2 to be the RA offset, if there are two offsets, and offset3 to be the FP offset, if there are three offsets. There is no mean to distinguish whether offset2 is the RA or FP offset, if there are only two offsets. This issue is detailed further and resolved in the subsequent commit "s390: Represent FP without RA saved in SFrame". - SFrame assumes a dedicated FP register number. The s390x ELF ABI [1] does only designate register 11 as preferred FP register number. In general GCC and Clang on s390x use register 11 as frame pointer. GCC on s390x can be observed to use register 14 as frame pointer in the stack clash protector in the function prologue. glibc on s390x contains hand-written assembler code that uses register 12 as frame pointer. This s390x support is largely based on the AArch64 support from commit b52c4ee46657 ("gas: generate .sframe from CFI directives"). The SFrame ABI/arch identifier SFRAME_ABI_S390X_ENDIAN_BIG is introduced for s390x and added to the SFrame format specification. The s390x ELF ABI [1] specifies the following C calling conventions for s390x architecture: - Register 15 is the stack pointer (SP). - Register 14 contains the return address (RA) at function entry. - There is no dedicated frame pointer register. Register 11 is the preferred frame pointer (FP). [2] GCC and Clang in general use register 11 as frame pointer. - The CFA is defined as SP at call site +160. [3] The SP at call site can therefore be derived from the CFA using a SP value offset from CFA of -160. The s390x ELF ABI [1] does not assign any standard save slot to each register in the register save area of a stack frame. Neither the return address (RA, r14) nor preferred frame pointer (FP, r11) necessarily need to be saved. Therefore SFrame RA and FP tracking is used. Support for SFrame on s390 is only enabled for the 64-bit s390x ELF ABI (z/Architecture with 64-bit addressing mode). It is disabled for the 32-bit s390 ELF ABI (ESA/390 or z/Architecture with 32-bit addressing mode). s390x-specific SFrame assembler and linker tests are added, including error tests for use of a non-preferred frame pointer (FP) register and specification of a non-default return address (RA) register. [1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit f00421825979 ("Add information about the frame pointer register"), https://github.com/IBM/s390x-abi/commit/f00421825979 [3]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 include/ * sframe.h: Add reference to s390x architecture in comments. (SFRAME_ABI_S390X_ENDIAN_BIG): Define SFrame ABI/arch identifier for s390x. (SFRAME_S390X_SP_VAL_OFFSET): Define s390x-specific SP value offset from CFA. libsframe/ * sframe.c (need_swapping): Add SFRAME_ABI_S390X_ENDIAN_BIG. * doc/sframe-spec.texi (SFRAME_ABI_S390X_ENDIAN_BIG, s390x, SFRAME_S390X_SP_VAL_OFFSET): Document SFrame ABI/arch identifier for s390x, add references to s390x architecture, and document s390x-specifics, such as the SP value offset from CFA of -160. gas/ * config/tc-s390.h: s390x support to generate .sframe from CFI directives in assembler. (support_sframe_p): Define. (SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG): Define. (sframe_ra_tracking_p): Define. (sframe_cfa_ra_offset): Define. (sframe_get_abi_arch): Define. * config/tc-s390.c: s390x support to generate .sframe from CFI directives in assembler. (s390_sframe_cfa_sp_reg, s390_sframe_cfa_fp_reg, s390_sframe_cfa_ra_reg): New. Initialize to DWARF register numbers of stack pointer (SP, r15), preferred frame pointer (FP, r11), and return address (RA, r14) registers. (s390_support_sframe_p): New function. Return true if s390x. (s390_sframe_ra_tracking_p): New function. Return true. (s390_sframe_cfa_ra_offset): New function. Return SFRAME_CFA_FIXED_RA_INVALID. (s390_sframe_get_abi_arch): New function. Return SFRAME_ABI_S390X_ENDIAN_BIG if s390x, otherwise zero. * gen-sframe.c: Add reference to s390x architecture in comments. (sframe_xlate_do_val_offset): Add support for s390x-specific SFRAME_S390X_SP_VAL_OFFSET. * NEWS: Add news entry. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests for s390x. Add s390x-specific SFrame (error) tests. * gas/cfi-sframe/cfi-sframe-s390x-1.d: New s390x-specific SFrame test. * gas/cfi-sframe/cfi-sframe-s390x-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-1.d: New s390x-specific SFrame error test that uses a non-default frame-pointer register as CFA base register. * gas/cfi-sframe/cfi-sframe-s390x-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-2.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-err-3.d: New s390x-specific SFrame error test that uses a non-default return address register. * gas/cfi-sframe/cfi-sframe-s390x-err-3.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.d: New s390x- specific SFrame test that saves RA and FP individually on the stack. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually, to trigger FP without RA saved. * gas/cfi-sframe/cfi-sframe-s390x-fpra-offset-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: New s390x-specific SFrame error test that saves FP and RA individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.s: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: New s390x-specific SFrame error test that saves RA and FP individually in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s: Likewise. ld/testsuite/ * ld-s390/s390.exp: Add simple SFrame test. * ld-s390/sframe-simple-1.d: New simple SFrame test. * ld-s390/sframe-bar.s: Likewise. * ld-s390/sframe-foo.s: Likewise. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
/* On s390x, the CFA is defined as SP at call site + 160. Therefore the
SP value offset from CFA is -160. */
#define SFRAME_S390X_SP_VAL_OFFSET (-160)
s390: Represent FP/RA saved in register in SFrame GCC on s390x, when in a leaf function, can be observed to save the frame pointer (FP) and/or return address (RA) register in a floating- point registers (FPR) instead of on the stack. This is declared using the following CFI directive: .cfi_register <fp/ra-regnum>, <fpr-regnum> SFrame cannot represent the FP and/or RA being saved in another register. It does only track the CFA base register (SP/FP), CFA offset from CFA base register, and FP and RA save area offsets from CFA. On s390x the FP and/or RA are only saved in another FPR when in a leaf function. That is a function that does not call any other function. Therefore it can ever only be the topmost function in a call chain. An unwinder by default has access to all registers of the function that is the topmost on the call stack. Therefore no further information is required to restore FP/RA from the FPR. Represent FP/RA saved in another register on s390x, by encoding the DWARF register number shifted by one to the left with the least- significant bit set in the offset as follows: offset = (regnum << 1) | 1 The use of the least-significant bit of the offset as indication is possible, as the stack pointer (SP), the CFA, and any register save area slots are 8-byte aligned according to the s390x ELF ABI: - The stack pointer (SP) "shall maintain an 8-byte alignment". [1] - The CFA is defined as SP at call site +160. [2] - Pointers and 8-byte integers, such as general register values, must be 8-byte aligned. [3] SFrame FP and RA stack offsets must therefore always be a multiple of 8 on s390x. Note that for the same reason the DWARF data alignment factor is -8 on s390x (see DWARF2_CIE_DATA_ALIGNMENT). Add s390x-specific SFrame (error) tests for FP/RA saved in FPRs in leaf function. [1]: s390x ELF ABI, sections "Register Roles" and "Stack Frame Allocation", https://github.com/IBM/s390x-abi/releases [2]: s390x ELF ABI, commit 4e38ad9c8a88 ("Document the CFA"), https://github.com/IBM/s390x-abi/commit/4e38ad9c8a88 [3]: s390x ELF ABI, section "Fundamental Types", table "Scalar types", https://github.com/IBM/s390x-abi/releases include/ * sframe.h (SFRAME_V2_S390X_OFFSET_IS_REGNUM): New s390x- specific macro to test whether an SFrame FP/RA offset is a DWARF register number. (SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM): New s390x-specific macro to encode a DWARF register number into an SFrame FP/RA offset. (SFRAME_V2_S390X_OFFSET_DECODE_REGNUM): New s390x-specific macro to decode an SFrame FP/RA offset into a DWARF register number. * sframe-api.h (sframe_fre_get_fp_offset, sframe_fre_get_fp_offset): Add comment that for s390x the offset may be an encoded register number. gas/ * gen-sframe.c (s390_sframe_xlate_do_register): New S390- specific function. Uses SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM to represent FP/RA saved in another register on s390x. (sframe_xlate_do_register): Invoke s390_sframe_xlate_do_register on s390x. libsframe/ * sframe.c (sframe_fre_get_fp_offset, sframe_fre_get_fp_offset): Add comment that for s390x the offset may be an encoded register number. * sframe-dump.c (is_sframe_abi_arch_s390x): New helper to test whether ABI/arch is s390x. (dump_sframe_func_with_fres): Use SFRAME_V2_S390X_OFFSET_IS_REGNUM and SFRAME_V2_S390X_OFFSET_DECODE_REGNUM to dump FP/RA saved in another register on s390x. * doc/sframe-spec.texi (s390x): Document s390x-specific representation of FP/RA saved in another register. gas/testsuite/ * gas/cfi-sframe/cfi-sframe.exp: Update s390x-specific SFrame (error) tests. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.s: Rename to ... * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-2.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.s: This. Test no longer triggers a warning, as SFrame can represent FP and RA saved in registers. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-1.d: Likewise. * gas/cfi-sframe/cfi-sframe-s390x-fpra-register-err-1.d: Test now triggers a different warning, as SFrame can represent FP and RA saved in registers, but not FP without RA saved in register. Signed-off-by: Jens Remus <jremus@linux.ibm.com>
2025-07-11 10:29:40 +02:00
/* On s390x, the FP and RA registers can be saved either on the stack or,
in case of leaf functions, in registers. Store DWARF register numbers
encoded as offset by using the least-significant bit (LSB) as indicator:
- LSB=0: Stack offset. The s390x ELF ABI mandates that stack register
slots must be 8-byte aligned.
- LSB=1: DWARF register number shifted to the left by one. */
#define SFRAME_V2_S390X_OFFSET_IS_REGNUM(offset) \
((offset) & 1)
#define SFRAME_V2_S390X_OFFSET_ENCODE_REGNUM(regnum) \
(((regnum) << 1) | 1)
#define SFRAME_V2_S390X_OFFSET_DECODE_REGNUM(offset) \
((offset) >> 1)
#ifdef __cplusplus
}
#endif
#endif /* _SFRAME_H */