--- /dev/null
+#as:
+#objdump: --sframe=.sframe
+#name: SFrame generation on aarch64
+#...
+Contents of the SFrame section .sframe:
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 3
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = 80 bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+0004 +sp\+144 +u +u +
+ 0+004c +sp\+0 +u +u +
+#pass
--- /dev/null
+ .cfi_sections .sframe
+ .cfi_startproc
+ stp x19, x20, [sp, -144]!
+ .cfi_def_cfa_offset 144
+ .cfi_offset 19, -144
+ .cfi_offset 20, -136
+ stp x21, x22, [sp, 16]
+ stp x23, x24, [sp, 32]
+ stp x25, x26, [sp, 48]
+ stp x27, x28, [sp, 64]
+ stp d8, d9, [sp, 80]
+ stp d10, d11, [sp, 96]
+ stp d12, d13, [sp, 112]
+ stp d14, d15, [sp, 128]
+ .cfi_offset 21, -128
+ .cfi_offset 22, -120
+ .cfi_offset 23, -112
+ .cfi_offset 24, -104
+ .cfi_offset 25, -96
+ .cfi_offset 26, -88
+ .cfi_offset 27, -80
+ .cfi_offset 28, -72
+ .cfi_offset 72, -64
+ .cfi_offset 73, -56
+ .cfi_offset 74, -48
+ .cfi_offset 75, -40
+ .cfi_offset 76, -32
+ .cfi_offset 77, -24
+ .cfi_offset 78, -16
+ .cfi_offset 79, -8
+ nop
+ ldp x21, x22, [sp, 16]
+ ldp x23, x24, [sp, 32]
+ ldp x25, x26, [sp, 48]
+ ldp x27, x28, [sp, 64]
+ ldp d8, d9, [sp, 80]
+ ldp d10, d11, [sp, 96]
+ ldp d12, d13, [sp, 112]
+ ldp d14, d15, [sp, 128]
+ ldp x19, x20, [sp], 144
+ .cfi_restore 20
+ .cfi_restore 19
+ .cfi_restore 78
+ .cfi_restore 79
+ .cfi_restore 76
+ .cfi_restore 77
+ .cfi_restore 74
+ .cfi_restore 75
+ .cfi_restore 72
+ .cfi_restore 73
+ .cfi_restore 27
+ .cfi_restore 28
+ .cfi_restore 25
+ .cfi_restore 26
+ .cfi_restore 23
+ .cfi_restore 24
+ .cfi_restore 21
+ .cfi_restore 22
+ .cfi_def_cfa_offset 0
+ ret
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame generation using CFI directive .cfi_sections
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 1
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 0 bytes
+ STARTPC + CFA + FP + RA +
+#pass
--- /dev/null
+ .cfi_sections .sframe
+ .cfi_startproc
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: Command line option for generating SFrame
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 1
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 0 bytes
+ STARTPC + CFA + FP + RA +
+#pass
--- /dev/null
+ .cfi_startproc
+ .cfi_endproc
--- /dev/null
+#as:
+#objdump: --sframe=.sframe
+#name: SFrame can co-exist with EH Frame
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 1
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 0 bytes
+ STARTPC + CFA + FP + RA +
+#pass
--- /dev/null
+ .cfi_sections .eh_frame
+ .cfi_sections .sframe
+ .cfi_startproc
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_def_cfa_offset test
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 3
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 12 bytes
+ STARTPC + CFA + FP + RA +
+#...
+ 0+0004 +sp\+16 +u +u +
+ 0+0008 +sp\+32 +u +u +
+
+#pass
--- /dev/null
+## Testcase for cfi_def_cfa_offset
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 16
+ .long 0
+ .cfi_def_cfa_offset 32
+ .long 0
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_adjust_cfa_offset test
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 3
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 12 bytes
+ STARTPC + CFA + FP + RA +
+#...
+ 0+0004 +sp\+16 +u +u +
+ 0+0008 +sp\+24 +u +u +
+
+#pass
--- /dev/null
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 16
+ .long 0
+ .cfi_adjust_cfa_offset 8
+ .long 0
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_offset test
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 3
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 12 bytes
+ STARTPC + CFA + FP + RA +
+#...
+ 0+0004 +sp\+8 +u +u +
+ 0+0008 +sp\+8 +u +u +
+
+#pass
--- /dev/null
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 8
+ .long 0
+ .cfi_offset 0, 8
+ .long 0
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_rel_offset test
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 3
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 12 bytes
+ STARTPC + CFA + FP + RA +
+#...
+ 0+0004 +sp\+8 +u +u +
+ 0+0008 +sp\+8 +u +u +
+
+#pass
--- /dev/null
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 8
+ .long 0
+ .cfi_rel_offset 1, 8
+ .long 0
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame cfi_val_offset test
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 2
+
+ Function Index :
+ func idx \[0\]: pc = 0x0, size = 8 bytes
+ STARTPC + CFA + FP + RA +
+#...
+ 0+0004 +sp\+16 +u +u +
+
+#pass
--- /dev/null
+## cfi_val_offset when used with "not interesting" registers (from the
+## perspective of SFrame section, non FP/RA registers are not
+## interesting) does not affect the asynchronicity of the SFrame
+## unwind information. Such CFI directives can be skipped for SFrame
+## unwind info generation.
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 16
+ .cfi_val_offset 1, 8
+ .cfi_val_offset 2, -32
+ .long 0
+ .cfi_endproc
--- /dev/null
+#as: -O0
+#objdump: --sframe=.sframe
+#name: SFrame generation on x86_64
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 1
+ Num FREs: 4
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = 25 bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+8 +u +u +
+ 0+0001 +sp\+16 +c\-16 +u +
+ 0+0004 +fp\+16 +c\-16 +u +
+ 0+0018 +sp\+8 +c\-16 +u +
+#pass
--- /dev/null
+ .cfi_sections .sframe
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ pushq %r15
+ pushq %r14
+ pushq %r13
+ pushq %r12
+ pushq %rbx
+ ## These CFI opcodes are not interesting
+ ## for SFrame generation and will be
+ ## skipped.
+ .cfi_offset 15, -24
+ .cfi_offset 14, -32
+ .cfi_offset 13, -40
+ .cfi_offset 12, -48
+ .cfi_offset 3, -56
+ nop
+ popq %rbx
+ popq %r12
+ popq %r13
+ popq %r14
+ popq %r15
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
--- /dev/null
+# Copyright (C) 2022 Free Software Foundation, Inc.
+
+# This program 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 of the License, 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+if { ![is_elf_format] } then {
+ return
+}
+
+proc gas_sframe_check { } {
+ global check_as_sframe_result
+ global AS
+ global ASFLAGS
+ if [info exists check_as_sframe_result] {
+ return $check_as_sframe_result
+ }
+
+ set as_file "tmpdir/check_as_sframe.s"
+ set as_fh [open $as_file w 0666]
+ puts $as_fh "# Generated file. DO NOT EDIT"
+ puts $as_fh "\t.cfi_startproc"
+ puts $as_fh "\t.cfi_endproc"
+ close $as_fh
+ remote_download host $as_file
+ verbose -log "Checking SFrame support in AS:"
+
+ set old_ASFLAGS "$ASFLAGS"
+ set ASFLAGS "$ASFLAGS --gsframe"
+
+ global comp_output
+
+ set output_file "tmpdir/check_as_sframe.out"
+ set status [gas_host_run "$AS $ASFLAGS $as_file" "2>$output_file"]
+ set comp_output [file_contents "$output_file"]
+ set ASFLAGS "$old_ASFLAGS"
+
+ if { ![string match "" $comp_output]
+ || [string match "*sframe not supported for target*" $comp_output] } then {
+ verbose -log "SFrame not supported in AS"
+ return 0
+ } else {
+ verbose -log "SFrame supported in AS"
+ return 1
+ }
+}
+
+proc gas_x86_64_check { } {
+ global NM
+ global NMFLAGS
+
+ set status [gas_host_run "$NM $NMFLAGS --help" ""]
+ return [regexp "targets:.*x86-64" [lindex $status 1]];
+}
+
+# common tests
+if { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]) \
+ && [gas_sframe_check] } then {
+
+ global ASFLAGS
+ set old_ASFLAGS "$ASFLAGS"
+
+ run_dump_test "cfi-sframe-common-1"
+ run_dump_test "cfi-sframe-common-2"
+ run_dump_test "cfi-sframe-common-3"
+ run_dump_test "cfi-sframe-common-4"
+ run_dump_test "cfi-sframe-common-5"
+ run_dump_test "cfi-sframe-common-6"
+ run_dump_test "cfi-sframe-common-7"
+ run_dump_test "cfi-sframe-common-8"
+
+ run_dump_test "common-empty-1"
+ run_dump_test "common-empty-2"
+ run_dump_test "common-empty-3"
+ run_dump_test "common-empty-4"
+}
+
+# x86-64 specific tests
+if { [istarget "x86_64-*-*"] && [gas_sframe_check] } then {
+ if { [gas_x86_64_check] } then {
+ set ASFLAGS "$ASFLAGS --64"
+ run_dump_test "cfi-sframe-x86_64-1"
+ set ASFLAGS "$old_ASFLAGS"
+ }
+}
+
+# aarch64 specific tests
+if { [istarget "aarch64*-*-*"] && [gas_sframe_check] } then {
+ run_dump_test "cfi-sframe-aarch64-1"
+}
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: Uninteresting cfi directives generate an empty SFrame section
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 0
+ Num FREs: 0
+
+#pass
--- /dev/null
+ .cfi_sections .sframe
+ .cfi_startproc
+ .cfi_remember_state
+ .cfi_restore_state
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame supports only FP/SP based CFA
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 0
+ Num FREs: 0
+
+#pass
--- /dev/null
+## CFA register is not defined to be SP/FP.
+## No SFrame unwind info for this function will be generated.
+ .cfi_startproc simple
+ .long 0
+ .long 0
+ .cfi_adjust_cfa_offset 16
+ .long 0
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame supports only default return column
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 0
+ Num FREs: 0
+
+#pass
--- /dev/null
+## The return column is not the default value.
+## No SFrame unwind info for this function will be generated.
+ .cfi_startproc
+ .cfi_return_column 0
+ .long 0
+ .long 0
+ .cfi_adjust_cfa_offset 16
+ .long 0
+ .cfi_endproc
--- /dev/null
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame supports only default return column
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_1
+ Flags: NONE
+ Num FDEs: 0
+ Num FREs: 0
+
+#pass
--- /dev/null
+## ARMv8.3 addded support a new security feature named Pointer Authentication. The
+## main idea behind this is to use the unused bits in the pointer values.
+## Each pointer is patched with a PAC before writing to memory, and is verified
+## before using it.
+## When the pointers are mangled, the unwinder needs to know so it can mask off
+## the PAC from the pointer value to recover the return address, and
+## conversely, skip doing so if the pointers are not mangled.
+##
+## .cfi_negate_ra_state CFI directive is used to convey this information.
+##
+## SFrame does not have any means to represent this information at this time.
+ .cfi_startproc
+ .long 0
+ .cfi_def_cfa_offset 16
+ .cfi_negate_ra_state
+ .long 0
+ .cfi_endproc