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>
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>
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>
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>
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
b52c4ee466 ("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>
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.
This also amends the incorrect comment:
offset3 (intrepreted as FP = CFA + offset2)
If RA tracking is enabled, the offset to recover FP is at the third
index. The SFrame format (V2) has assumption that if FP is saved on
stack, RA must have been saved as well. This is true for the currently
supported arch Aarch64. For AMD64, RA tracking per SFrame FRE is not
necessary.
In future, when extending support for more architectures, this will
likely need to be revisited.
include/
* sframe.h: Make the comments clearer by enumerating what
happens per-ABI.
Adds two new external authors to etc/update-copyright.py to cover
bfd/ax_tls.m4, and adds gprofng to dirs handled automatically, then
updates copyright messages as follows:
1) Update cgen/utils.scm emitted copyrights.
2) Run "etc/update-copyright.py --this-year" with an extra external
author I haven't committed, 'Kalray SA.', to cover gas testsuite
files (which should have their copyright message removed).
3) Build with --enable-maintainer-mode --enable-cgen-maint=yes.
4) Check out */po/*.pot which we don't update frequently.
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.
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.
An earlier commit 3f107464 defined the SFRAME_FRE_TYPE_*_LIMIT
constants. These constants are used (by gas and libsframe) to pick an
SFrame FRE type based on the function size. Those constants, however,
were buggy, causing the generated SFrame sections to be bloated as
SFRAME_FRE_TYPE_ADDR2/SFRAME_FRE_TYPE_ADDR4 got chosen more often than
necessary.
gas/
* sframe-opt.c (sframe_estimate_size_before_relax): Use
typecast.
(sframe_convert_frag): Likewise.
libsframe/
* sframe.c (sframe_calc_fre_type): Use a more appropriate type
for argument. Adjust the check for SFRAME_FRE_TYPE_ADDR4_LIMIT
to keep it warning-free but meaningful.
include/
* sframe-api.h (sframe_calc_fre_type): Use a more appropriate
type for the argument.
* sframe.h (SFRAME_FRE_TYPE_ADDR1_LIMIT): Correct the constant.
(SFRAME_FRE_TYPE_ADDR2_LIMIT): Likewise.
(SFRAME_FRE_TYPE_ADDR4_LIMIT): Likewise.
The newer update-copyright.py fixes file encoding too, removing cr/lf
on binutils/bfdtest2.c and ld/testsuite/ld-cygwin/exe-export.exp, and
embedded cr in binutils/testsuite/binutils-all/ar.exp string match.
ARM 8.3 provides five separate keys that can be used to authenticate
pointers. There are two key for executable (instruction) pointers. The
enum pointer_auth_key in gas/config/tc-aarch64.h currently holds two keys:
enum pointer_auth_key {
AARCH64_PAUTH_KEY_A,
AARCH64_PAUTH_KEY_B
};
Analogous to the above, in SFrame format V1, a bit is reserved in the SFrame
FDE to indicate which key is used for signing the frame's return addresses:
- SFRAME_AARCH64_PAUTH_KEY_A has a value of 0
- SFRAME_AARCH64_PAUTH_KEY_B has a value of 1
Note that the information in this bit will always be used along with the
mangled_ra_p bit, the latter indicates whether the return addresses are
mangled/contain PAC auth bits.
include/ChangeLog:
* sframe.h (SFRAME_AARCH64_PAUTH_KEY_A): New definition.
(SFRAME_AARCH64_PAUTH_KEY_B): Likewise.
(SFRAME_V1_FUNC_INFO): Adjust to accommodate pauth_key.
(SFRAME_V1_FUNC_PAUTH_KEY): New macro.
(SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY): Likewise.
Use the last remaining bit in the 'SFrame FRE info' word to store whether
the RA is signed/unsigned with PAC authorization code: this bit is named
as the "mangled RA" bit. This bit is still unused for x86-64.
The behaviour of the mangled-RA info bit in SFrame format closely
follows the behaviour of DW_CFA_AARCH64_negate_ra_state in DWARF. During
unwinding, whenever an SFrame FRE with non-zero "mangled RA" bit is
encountered, it means the upper bits of the return address contain Pointer
Authentication code. The unwinder, hence, must use appropriate means to
restore LR correctly in such cases.
include/ChangeLog:
* sframe.h (SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P): New macro.
(SFRAME_V1_FRE_MANGLED_RA_P): Likewise.
Define constants in sframe.h for the various limits associated with the
range of offsets that can be encoded in the start address of an SFrame
FRE. E.g., sframe_frame_row_entry_addr1 is used when start address
offset can be encoded as 1-byte unsigned value.
Update the code in gas to use these defined constants as it checks for
these limits, and remove the usage of magic numbers.
ChangeLog:
* gas/sframe-opt.c (sframe_estimate_size_before_relax):
(sframe_convert_frag): Do not use magic numbers.
* libsframe/sframe.c (sframe_calc_fre_type): Likewise.
include/ChangeLog:
* sframe.h (SFRAME_FRE_TYPE_ADDR1_LIMIT): New constant.
(SFRAME_FRE_TYPE_ADDR2_LIMIT): Likewise.
(SFRAME_FRE_TYPE_ADDR4_LIMIT): Likewise.
The header sframe.h defines the SFrame format.
The SFrame format is the Simple Frame format. It can be used to
represent the minimal necessary unwind information required for
backtracing. The current version supports AMD64 and AARCH64.
More details of the SFrame format are included in the documentation
of the header file in this patch.
include/ChangeLog:
* sframe.h: New file.