Commit Graph

16 Commits

Author SHA1 Message Date
Jens Remus
d27d82f560 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
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>
2025-07-11 10:29:40 +02:00
Indu Bhagat
dcb0cf7bb2 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:53:03 -07:00
Alan Modra
e8e7cf2abe Update year range in copyright notice of binutils files 2025-01-01 18:29:57 +10:30
Indu Bhagat
4de9a5ccd6 include: sframe: update code comments around SFrame FRE stack offsets
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.
2024-07-09 10:23:31 -07:00
Alan Modra
fd67aa1129 Update year range in copyright notice of binutils files
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.
2024-01-04 22:58:12 +10:30
Indu Bhagat
ce9a87252c 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:31:58 -07:00
Indu Bhagat
3169b734cf 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
Indu Bhagat
8bb878b777 sframe: correct some typos
include/
	* sframe.h: Correct a typo.

libsframe/
	* sframe.c: Likewise.
2023-04-19 14:37:59 -07:00
Indu Bhagat
91def06c4d sframe: use "stack trace" instead of "unwind" for SFrame
SFrame format is meant for generating stack traces only.

include/
	* sframe.h: Fix comments in the header file.
2023-02-02 00:47:38 -08:00
Indu Bhagat
725a19bfd1 sframe: fix the defined SFRAME_FRE_TYPE_*_LIMIT constants
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.
2023-01-06 09:30:56 -08:00
Alan Modra
d87bef3a7b Update year range in copyright notice of binutils files
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.
2023-01-01 21:50:11 +10:30
Indu Bhagat
41eed6e187 sframe.h: add support for .cfi_b_key_frame
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.
2022-12-22 09:57:02 -08:00
Indu Bhagat
4604c72941 sframe.h: add support for .cfi_negate_ra_state
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.
2022-12-16 22:01:40 -08:00
Indu Bhagat
3f107464e3 sframe: gas: libsframe: define constants and remove magic numbers
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.
2022-12-09 10:23:07 -08:00
Indu Bhagat
70cfae61f4 sframe.h: make some macros more precise
include/ChangeLog:

	* sframe.h (SFRAME_V1_FUNC_INFO): Use specific bits only.
	(SFRAME_V1_FRE_INFO): Likewise.
2022-12-09 10:22:31 -08:00
Indu Bhagat
972d23ddbd sframe.h: Add SFrame format definition
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.
2022-11-15 15:23:44 -08:00