@@ -15698,11 +15698,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
wrel->r_addend = 0;
/* For ld -r, remove relocations in debug sections against
- symbols defined in discarded sections. Not done for
- non-debug to preserve relocs in .eh_frame which the
- eh_frame editing code expects to be present. */
+ sections defined in discarded sections, including sframe
+ sections. Not done for non-debug to preserve relocs in
+ .eh_frame which the eh_frame editing code expects to be
+ present. NB: Since sframe code keeps R_PPC64_NONE reloc
+ as is, its r_offset is wrong, we must not generate
+ R_PPC64_NONE reloc in sframe section. */
if (bfd_link_relocatable (info)
- && (input_section->flags & SEC_DEBUGGING))
+ && ((input_section->flags & SEC_DEBUGGING)
+ || elf_section_type (input_section) == SHT_GNU_SFRAME))
wrel--;
continue;
@@ -1,5 +1,8 @@
-*- text -*-
+* Add support to generate SFrame stack trace information (.sframe)
+ from CFI directives on PowerPC 64-bit (powerpc64).
+
Changes in 2.46:
* Add support for AMD Zen6 processor.
@@ -29,6 +29,7 @@
#include "elf/ppc.h"
#include "elf/ppc64.h"
#include "dwarf2dbg.h"
+#include "sframe.h"
#endif
#ifdef OBJ_XCOFF
@@ -7795,3 +7796,35 @@ tc_ppc_regname_to_dw2regnum (char *regname)
}
return regnum;
}
+
+#ifdef OBJ_ELF
+
+/* Whether SFrame stack trace info is supported. */
+
+bool
+ppc_support_sframe_p (void)
+{
+ /* At this time, SFrame is supported for PPC64 only. */
+ return ppc_obj64;
+}
+
+/* Get the abi/arch identifier for SFrame. */
+
+unsigned char
+ppc_sframe_get_abi_arch (void)
+{
+ unsigned char sframe_abi_arch = 0;
+
+ if (ppc_support_sframe_p ())
+ {
+ gas_assert (set_target_endian != 0);
+ if (target_big_endian)
+ sframe_abi_arch = SFRAME_ABI_PPC64_ENDIAN_BIG;
+ else
+ sframe_abi_arch = SFRAME_ABI_PPC64_ENDIAN_LITTLE;
+ }
+
+ return sframe_abi_arch;
+}
+
+#endif /* OBJ_ELF */
@@ -370,8 +370,39 @@ extern int ppc_dwarf2_line_min_insn_length;
#define EH_FRAME_ALIGNMENT 2
#ifdef OBJ_ELF
+
/* The target supports Object Attributes v1. */
#define TC_OBJ_ATTR_v1 1
+
+/* SFrame. */
+
+/* Whether SFrame stack trace info is supported. */
+extern bool ppc_support_sframe_p (void);
+#define support_sframe_p ppc_support_sframe_p
+
+/* The stack pointer DWARF register number for SFrame CFA tracking. */
+#define SFRAME_CFA_SP_REG 1 /* ABI-designated SP register. */
+
+/* The frame pointer DWARF register number for SFrame CFA and FP tracking. */
+#define SFRAME_CFA_FP_REG 31 /* Conventionally used FP register. */
+
+/* The return address DWARF register number for SFrame RA tracking. */
+#define SFRAME_CFA_RA_REG DWARF2_DEFAULT_RETURN_COLUMN
+
+/* Whether SFrame return address tracking is needed. */
+#define sframe_ra_tracking_p() true
+
+/* The fixed offset from CFA for SFrame to recover the return address.
+ (useful only when SFrame RA tracking is not needed). */
+#define sframe_cfa_ra_offset() ((offsetT) SFRAME_CFA_FIXED_RA_INVALID)
+
+/* The abi/arch identifier for SFrame. */
+unsigned char ppc_sframe_get_abi_arch (void);
+#define sframe_get_abi_arch ppc_sframe_get_abi_arch
+
+/* Whether SFrame FDE of type SFRAME_FDE_TYPE_FLEX be generated. */
+#define sframe_support_flex_fde_p() true
+
#endif /* OBJ_ELF */
#endif /* TC_PPC */
@@ -409,9 +409,11 @@ get_fre_dataword_count (const struct sframe_row_entry *sframe_fre, bool flex_p)
}
else if (sframe_ra_tracking_p ()
&& (sframe_fre->ra_loc != SFRAME_FRE_ELEM_LOC_NONE
- /* For s390x account padding RA data word, if FP without RA
- saved. */
- || (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
+ /* For PPC64 and s390x account padding RA data word,
+ if FP without RA saved. */
+ || ((sframe_get_abi_arch () == SFRAME_ABI_PPC64_ENDIAN_BIG
+ || sframe_get_abi_arch () == SFRAME_ABI_PPC64_ENDIAN_LITTLE
+ || sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
&& sframe_fre->fp_loc != SFRAME_FRE_ELEM_LOC_NONE)))
fre_dataword_count++;
@@ -443,8 +445,10 @@ sframe_get_fre_dataword_size (const struct sframe_row_entry *sframe_fre,
{
if (sframe_fre->ra_loc == SFRAME_FRE_ELEM_LOC_STACK)
ra_offset_size = get_offset_size_in_bytes (sframe_fre->ra_offset);
- /* For s390x account padding RA offset, if FP without RA saved. */
- else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
+ /* For PPC64 and s390x account padding RA offset, if FP without RA saved. */
+ else if ((sframe_get_abi_arch () == SFRAME_ABI_PPC64_ENDIAN_BIG
+ || sframe_get_abi_arch () == SFRAME_ABI_PPC64_ENDIAN_LITTLE
+ || sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
&& sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK)
ra_offset_size = get_offset_size_in_bytes (SFRAME_FRE_RA_OFFSET_INVALID);
}
@@ -720,8 +724,10 @@ output_sframe_row_entry_datawords (const struct sframe_func_entry *sframe_fde,
dataword_func_map[idx].out_func (sframe_fre->ra_offset);
fre_write_datawords++;
}
- /* For s390x write padding RA offset, if FP without RA saved. */
- else if (sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG
+ /* For PPC64 and s390x write padding RA offset, if FP without RA saved. */
+ else if ((sframe_get_abi_arch () == SFRAME_ABI_PPC64_ENDIAN_BIG
+ || sframe_get_abi_arch () == SFRAME_ABI_PPC64_ENDIAN_LITTLE
+ || sframe_get_abi_arch () == SFRAME_ABI_S390X_ENDIAN_BIG)
&& sframe_fre->fp_loc == SFRAME_FRE_ELEM_LOC_STACK)
{
dataword_func_map[idx].out_func (SFRAME_FRE_RA_OFFSET_INVALID);
@@ -2436,9 +2442,11 @@ sframe_do_fde (struct sframe_xlate_ctx *xlate_ctx,
return SFRAME_XLATE_ERR_NOTREPRESENTED;
}
- /* ABI/arch except s390x cannot represent FP without RA saved. */
+ /* ABI/arch except PPC64 and s390x cannot represent FP without RA saved. */
if (sframe_ra_tracking_p ()
- && sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG)
+ && (sframe_get_abi_arch () != SFRAME_ABI_PPC64_ENDIAN_BIG
+ && sframe_get_abi_arch () != SFRAME_ABI_PPC64_ENDIAN_LITTLE
+ && sframe_get_abi_arch () != SFRAME_ABI_S390X_ENDIAN_BIG))
{
struct sframe_row_entry *fre;
@@ -6,7 +6,7 @@
.cfi_startproc
.long 0
.cfi_def_cfa_offset 16
- .cfi_undefined 1
.cfi_undefined 2
+ .cfi_undefined 3
.long 0
.cfi_endproc
@@ -6,7 +6,7 @@
.cfi_startproc
.long 0
.cfi_def_cfa_offset 16
- .cfi_val_offset 1, 8
- .cfi_val_offset 2, -32
+ .cfi_val_offset 2, 8
+ .cfi_val_offset 3, -32
.long 0
.cfi_endproc
new file mode 100644
@@ -0,0 +1,24 @@
+#name: SFrame generation on ppc64 - basic prologue/epilogue
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 6
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = 44 bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+000c +sp\+0 +c\-8 +c\+16 +
+ 0+0010 +sp\+176 +c\-8 +c\+16 +
+ 0+0014 +fp\+176 +c\-8 +c\+16 +
+ 0+001c +sp\+0 +c\-8 +c\+16 +
+ 0+0028 +sp\+0 +u +u +
+#pass
new file mode 100644
@@ -0,0 +1,27 @@
+ .cfi_sections .sframe
+ .cfi_startproc
+ # Save all registers FIRST
+ mflr 0
+ std 0,16(1)
+ std 31,-8(1)
+ # All .cfi_offset directives together
+ .cfi_offset 65, 16
+ .cfi_offset 31, -8
+ # THEN adjust stack
+ stdu 1,-176(1)
+ .cfi_def_cfa_offset 176
+ # Set frame pointer
+ mr 31,1
+ .cfi_def_cfa_register 31
+ nop
+ # Epilogue
+ addi 1,31,176
+ .cfi_def_cfa 1, 0
+ ld 0,16(1)
+ ld 31,-8(1)
+ mtlr 0
+ # All .cfi_restore directives together
+ .cfi_restore 65
+ .cfi_restore 31
+ blr
+ .cfi_endproc
new file mode 100644
@@ -0,0 +1,19 @@
+#name: SFrame generation on ppc64 - .cfi_def_cfa_register with no previous offset
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 1
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = 0 bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +fp\+0 +u +u +
+#pass
new file mode 100644
@@ -0,0 +1,4 @@
+# Although not a useful construct by itself, ensure graceful handling.
+ .cfi_startproc
+ .cfi_def_cfa_register 31
+ .cfi_endproc
new file mode 100644
@@ -0,0 +1,15 @@
+#name: SFrame generation on ppc64 - non-default RA register
+#as: --gsframe
+#warning: no SFrame FDE emitted; non-default RA register 3
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 0
+ Num FREs: 0
+
+#pass
new file mode 100644
@@ -0,0 +1,5 @@
+ .cfi_sections .sframe
+ .cfi_startproc
+ .cfi_return_column 3
+ blr
+ .cfi_endproc
new file mode 100644
@@ -0,0 +1,23 @@
+#name: SFrame generation on ppc64 - RA and then FP saved on stack
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 5
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = [0-9]+ bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+0008 +sp\+0 +u +c\+16 +
+ 0+000c +sp\+0 +c\-8 +c\+16 +
+ 0+0018 +sp\+0 +u +c\+16 +
+ 0+0020 +sp\+0 +u +u +
+#pass
new file mode 100644
@@ -0,0 +1,17 @@
+ .cfi_sections .sframe
+ .cfi_startproc
+ mflr 0
+ std 0,16(1)
+ .cfi_offset 65, 16
+ std 31,-8(1)
+ .cfi_offset 31, -8
+ li 31,0
+ li 0,0
+.Lreturn:
+ ld 31,-8(1)
+ .cfi_restore 31
+ ld 0,16(1)
+ mtlr 0
+ .cfi_restore 65
+ blr
+ .cfi_endproc
new file mode 100644
@@ -0,0 +1,23 @@
+#name: SFrame generation on ppc64 - FP and then RA saved on stack
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 5
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = [0-9]+ bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+0004 +sp\+0 +c\-8 +U +
+ 0+000c +sp\+0 +c\-8 +c\+16 +
+ 0+001c +sp\+0 +c\-8 +U +
+ 0+0020 +sp\+0 +u +u +
+#pass
new file mode 100644
@@ -0,0 +1,18 @@
+ .cfi_sections .sframe
+ .cfi_startproc
+ # No stack allocation, CFA = SP+0 implicitly
+ std 31,-8(1) # Save FP at SP-8
+ .cfi_offset 31, -8 # FP at CFA-8
+ mflr 0 # Get LR
+ std 0,16(1) # Save RA at SP+16
+ .cfi_offset 65, 16 # RA at CFA+16
+ li 31,0 # Clear registers
+ li 0,0
+.Lreturn:
+ ld 0,16(1) # Restore RA
+ mtlr 0
+ .cfi_restore 65
+ ld 31,-8(1) # Restore FP
+ .cfi_restore 31
+ blr
+ .cfi_endproc
new file mode 100644
@@ -0,0 +1,23 @@
+#name: SFrame generation on ppc64 - FP and then RA saved in FPR registers
+#as:
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 5
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = 28 bytes, attr = "F"
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+0004 +sp\+0 +r2\+0 +U +
+ 0+0008 +sp\+0 +r2\+0 +r0\+0 +
+ 0+0014 +sp\+0 +r2\+0 +U +
+ 0+0018 +sp\+0 +u +u +
+#pass
new file mode 100644
@@ -0,0 +1,17 @@
+ .cfi_sections .sframe
+ .cfi_startproc
+ mr 2,31 # Move r31 (FP) to r2
+ .cfi_register 31, 2 # FP is now in r2
+ mflr 0 # Get LR into r0
+ .cfi_register 65, 0 # RA is now in r0
+ li 31,0
+ li 0,0
+.Lreturn:
+ # Restore RA from r0
+ mtlr 0
+ .cfi_restore 65
+ # Restore FP from r2
+ mr 31,2
+ .cfi_restore 31
+ blr
+ .cfi_endproc
new file mode 100644
@@ -0,0 +1,26 @@
+#name: SFrame generation on ppc64 - .cfi_def_cfa with non-SP/FP register
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 8
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = 188 bytes, attr = "F"
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+0008 +sp\+0 +u +c\+16 +
+ 0+0050 +sp\+0 +c\-8 +c\+16 +
+ 0+0054 +sp\+288 +c\-8 +c\+16 +
+ 0+0058 +r30\+288 +c\-8 +c\+16 +
+ 0+0060 +sp\+288 +c\-8 +c\+16 +
+ 0+00b0 +sp\+0 +u +u +
+ 0+00b4 +r30\+288 +c\-8 +c\+16 +
+#pass
new file mode 100644
@@ -0,0 +1,100 @@
+# Test SFrame generation with non-FP CFA base register
+#
+# This test uses r30 (instead of conventional FP r31) as the CFA
+# base register to verify that SFrame flexible FDE correctly handles
+# arbitrary CFA base registers for topmost frames.
+ .cfi_sections .sframe
+ .cfi_startproc
+ mflr 0
+ std 0,16(1)
+ .cfi_offset 65, 16
+ std 14,-144(1)
+ std 15,-136(1)
+ std 16,-128(1)
+ std 17,-120(1)
+ std 18,-112(1)
+ std 19,-104(1)
+ std 20,-96(1)
+ std 21,-88(1)
+ std 22,-80(1)
+ std 23,-72(1)
+ std 24,-64(1)
+ std 25,-56(1)
+ std 26,-48(1)
+ std 27,-40(1)
+ std 28,-32(1)
+ std 29,-24(1)
+ std 30,-16(1)
+ std 31,-8(1)
+ .cfi_offset 14, -144
+ .cfi_offset 15, -136
+ .cfi_offset 16, -128
+ .cfi_offset 17, -120
+ .cfi_offset 18, -112
+ .cfi_offset 19, -104
+ .cfi_offset 20, -96
+ .cfi_offset 21, -88
+ .cfi_offset 22, -80
+ .cfi_offset 23, -72
+ .cfi_offset 24, -64
+ .cfi_offset 25, -56
+ .cfi_offset 26, -48
+ .cfi_offset 27, -40
+ .cfi_offset 28, -32
+ .cfi_offset 29, -24
+ .cfi_offset 30, -16
+ .cfi_offset 31, -8
+ stdu 1,-288(1)
+ .cfi_def_cfa_offset 288
+ mr 30,1
+ .cfi_def_cfa 30, 288
+ addi 1,1,-64
+.Lreturn:
+ addi 1,30,288
+ .cfi_remember_state
+ .cfi_def_cfa 1, 288
+ ld 0,16(1)
+ ld 14,-144(1)
+ ld 15,-136(1)
+ ld 16,-128(1)
+ ld 17,-120(1)
+ ld 18,-112(1)
+ ld 19,-104(1)
+ ld 20,-96(1)
+ ld 21,-88(1)
+ ld 22,-80(1)
+ ld 23,-72(1)
+ ld 24,-64(1)
+ ld 25,-56(1)
+ ld 26,-48(1)
+ ld 27,-40(1)
+ ld 28,-32(1)
+ ld 29,-24(1)
+ ld 30,-16(1)
+ ld 31,-8(1)
+ mtlr 0
+ .cfi_restore 65
+ .cfi_restore 14
+ .cfi_restore 15
+ .cfi_restore 16
+ .cfi_restore 17
+ .cfi_restore 18
+ .cfi_restore 19
+ .cfi_restore 20
+ .cfi_restore 21
+ .cfi_restore 22
+ .cfi_restore 23
+ .cfi_restore 24
+ .cfi_restore 25
+ .cfi_restore 26
+ .cfi_restore 27
+ .cfi_restore 28
+ .cfi_restore 29
+ .cfi_restore 30
+ .cfi_restore 31
+ .cfi_def_cfa_offset 0
+ blr
+ .cfi_restore_state
+ addi 1,1,-64
+ b .Lreturn
+ .cfi_endproc
new file mode 100644
@@ -0,0 +1,24 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: SFrame generation on ppc64 - .cfi_remember_state after .cfi_startproc PR gas/33756
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 5
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = 36 bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+0008 +sp\+0 +u +c\+16 +
+ 0+000c +sp\+0 +c\-8 +c\+16 +
+ 0+0010 +sp\+176 +c\-8 +c\+16 +
+ 0+0020 +sp\+0 +u +u +
+
+#pass
new file mode 100644
@@ -0,0 +1,20 @@
+ .text
+ .type foo, @function
+foo:
+ .cfi_startproc
+ .cfi_remember_state
+ mflr 0 # Move LR to r0
+ std 0,16(1) # Save RA (LR)
+ .cfi_offset 65, 16 # Track RA sp+16
+ std 31,-8(1) # Save FP
+ .cfi_offset 31, -8 # Track RA at sp-8
+ addi 1,1,-176
+ .cfi_adjust_cfa_offset 176
+ addi 1,1,176
+ ld 31,-8(1) # Restore FP
+ ld 0,16(1) # Restore RA
+ mtlr 0
+ .cfi_restore_state
+ blr
+ .cfi_endproc
+ .size foo, .-foo
new file mode 100644
@@ -0,0 +1,24 @@
+#name: SFrame generation on ppc64 - .cfi_undefined RA
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+Contents of the SFrame section .sframe:
+
+ Header :
+
+ Version: SFRAME_VERSION_3
+ Flags: SFRAME_F_FDE_FUNC_START_PCREL
+ Num FDEs: 1
+ Num FREs: 5
+
+ Function Index :
+
+ func idx \[0\]: pc = 0x0, size = [0-9]+ bytes
+ STARTPC +CFA +FP +RA +
+ 0+0000 +sp\+0 +u +u +
+ 0+0008 +sp\+0 +u +c\+16 +
+ 0+000c +sp\+0 +c\-8 +c\+16 +
+ 0+0010 +RA undefined
+ 0+001c +sp\+0 +u +u +
+
+#pass
new file mode 100644
@@ -0,0 +1,15 @@
+ .cfi_startproc
+ mflr 0
+ std 0,16(1) # Save LR at SP+16
+ .cfi_offset 65, 16
+ std 31,-8(1) # Save FP at SP-8
+ .cfi_offset 31, -8
+ nop
+ .cfi_undefined 65
+ ld 31,-8(1)
+ ld 0,16(1)
+ mtlr 0
+ .cfi_restore 65
+ .cfi_restore 31
+ blr
+ .cfi_endproc
@@ -28,7 +28,7 @@ proc gas_x86_64_check { } {
# common tests
if { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]
- || [istarget "s390x-*-*"]) \
+ || [istarget "s390x-*-*"] || [istarget "powerpc64*-*-*"]) \
&& [gas_sframe_check] } then {
global ASFLAGS
@@ -112,3 +112,16 @@ if { [istarget "s390x*-*-*"] && [gas_sframe_check] } then {
run_dump_test "cfi-sframe-s390x-non-spfp-cfa-1"
run_dump_test "cfi-sframe-s390x-non-spfp-cfa-2"
}
+
+# ppc64 specific tests
+if { [istarget "powerpc64*-*-*"] && [gas_sframe_check] } then {
+ run_dump_test "cfi-sframe-ppc64-1"
+ run_dump_test "cfi-sframe-ppc64-ra-undefined-1"
+ run_dump_test "cfi-sframe-ppc64-fpra-offset-1"
+ run_dump_test "cfi-sframe-ppc64-fpra-offset-2"
+ run_dump_test "cfi-sframe-ppc64-fpra-register-2"
+ run_dump_test "cfi-sframe-ppc64-non-spfp-cfa-2"
+ run_dump_test "cfi-sframe-ppc64-3"
+ run_dump_test "cfi-sframe-ppc64-err-3"
+ run_dump_test "cfi-sframe-ppc64-pr33756"
+}
@@ -239,10 +239,10 @@ sframe_fre_get_fp_offset (const sframe_decoder_ctx *dctx,
/* Get the RA offset from the FRE. If the offset is invalid, sets errp.
- For s390x an RA offset value of SFRAME_FRE_RA_OFFSET_INVALID indicates
- that the RA is not saved, which is only valid in the topmost frame.
- For s390x the offset may be an encoded register number, indicated by
- LSB set to one, which is only valid in the topmost frame. */
+ For PPC64 and s390x an RA offset value of SFRAME_FRE_RA_OFFSET_INVALID
+ indicates that the RA is not saved, which is only valid in the topmost frame.
+ For s390x the offset may be an encoded register number, indicated
+ by LSB set to one, which is only valid in the topmost frame. */
extern int32_t
sframe_fre_get_ra_offset (const sframe_decoder_ctx *dctx,
const sframe_frame_row_entry *fre,
@@ -110,6 +110,8 @@ extern "C"
#define SFRAME_ABI_AARCH64_ENDIAN_LITTLE 2 /* AARCH64 little endian. */
#define SFRAME_ABI_AMD64_ENDIAN_LITTLE 3 /* AMD64 little endian. */
#define SFRAME_ABI_S390X_ENDIAN_BIG 4 /* s390x big endian. */
+#define SFRAME_ABI_PPC64_ENDIAN_BIG 5 /* PPC64 big endian. */
+#define SFRAME_ABI_PPC64_ENDIAN_LITTLE 6 /* PPC64 little endian. */
/* SFrame FRE types. */
#define SFRAME_FRE_TYPE_ADDR1 0
@@ -88,7 +88,7 @@ of type @code{PT_GNU_SFRAME}. An ELF SFrame section will have the type
@code{SHT_GNU_SFRAME}.
The SFrame format is currently supported only for select ABIs, namely, AMD64,
-AAPCS64, and s390x.
+AAPCS64, PPC64, and s390x.
A portion of the SFrame format follows an unaligned on-disk representation.
Some data structures, however, (namely the SFrame header and the SFrame
@@ -169,6 +169,9 @@ indicate an outermost frame.
@item On s390x, use FDE type @code{SFRAME_FDE_TYPE_FLEX} to encode FP/RA
recovery from REG, instead of encoding DWARF register number in the SFrame FRE
variable-length data of FDE type @code{SFRAME_FDE_TYPE_DEFAULT}.
+@item
+[Errata 1] Add new ABI/arch identifiers SFRAME_ABI_PPC64_ENDIAN_BIG and
+SFRAME_ABI_PPC64_ENDIAN_LITTLE for the 64-bit PowerPC ELF ABI.
@end itemize
@node Changes from Version 1 to Version 2
@@ -522,6 +525,14 @@ in the format.
@item @code{SFRAME_ABI_S390X_ENDIAN_BIG}
@tab 4 @tab s390x big-endian
+@tindex SFRAME_ABI_PPC64_ENDIAN_BIG
+@item @code{SFRAME_ABI_PPC64_ENDIAN_BIG}
+@tab 5 @tab PPC64 big-endian
+
+@tindex SFRAME_ABI_PPC64_ENDIAN_LITTLE
+@item @code{SFRAME_ABI_PPC64_ENDIAN_LITTLE}
+@tab 6 @tab PPC64 little-endian
+
@end multitable
The presence of an explicit identification of ABI/arch in SFrame may allow
@@ -690,7 +701,7 @@ From MSB to LSB:
in the SFrame FDE. Two possible values: @*
@code{SFRAME_AARCH64_PAUTH_KEY_A} (0), or @*
@code{SFRAME_AARCH64_PAUTH_KEY_B} (1). @*
-Unsed in AMD64, s390x
+Unsed in AMD64, PPC64, s390x
@item 4
@tab @code{fde_pctype}
@@ -1026,6 +1037,7 @@ supported architectures.
@menu
* AMD64::
* AArch64::
+* PPC64::
* s390x::
@end menu
@@ -1083,6 +1095,33 @@ Hence, in summary:
@item 3 @tab FP = CFA + offset3
@end multitable
+@node PPC64
+@subsection PPC64
+
+Irrespective of the ABI, the first stack offset is always used to locate the
+CFA, by interpreting it as: CFA = @code{BASE_REG} + offset1. The
+identification of the @code{BASE_REG} is done by using the
+@code{fre_cfa_base_reg_id} field in the SFrame FRE info byte.
+
+In PPC64, the 64-bit PowerPC ELF ABI does not mandate the precise location in
+a function where the return address (RA) and frame pointer (FP) are saved, if
+at all. Hence the need to track RA in the SFrame stack trace format. As RA
+is being tracked in this ABI, the second stack offset is always used to locate
+the RA, by interpreting it as: RA = CFA + offset2. The third stack offset is
+used to locate the FP, by interpreting it as: FP = CFA + offset3.
+
+Given the nature of things, the number of stack offsets seen on PPC64 per
+SFrame FRE is either 1 or 3.
+
+Hence, in summary:
+
+@multitable {Offset ID} {Interpretation in PPC64 in X}
+@headitem Offset ID @tab Interpretation in PPC64
+@item 1 @tab CFA = @code{BASE_REG} + offset1
+@item 2 @tab RA = CFA + offset2
+@item 3 @tab FP = CFA + offset3
+@end multitable
+
@node s390x
@subsection s390x
@@ -52,6 +52,7 @@ typedef struct
stack pointer and frame pointer. */
SFRAME_ABI_REG_MAP (amd64, SFRAME_SP (7), SFRAME_FP (6));
SFRAME_ABI_REG_MAP (aarch64, SFRAME_SP (31), SFRAME_FP (29));
+SFRAME_ABI_REG_MAP (ppc64, SFRAME_SP (1), SFRAME_FP (31));
SFRAME_ABI_REG_MAP (s390x, SFRAME_SP (15), SFRAME_FP (11));
static const char *
@@ -70,6 +71,10 @@ sframe_get_reg_name (uint8_t abi_arch, unsigned int reg_num, char *buf,
case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
abi_reg_map = &amd64_sframe_abi_reg_map;
break;
+ case SFRAME_ABI_PPC64_ENDIAN_BIG:
+ case SFRAME_ABI_PPC64_ENDIAN_LITTLE:
+ abi_reg_map = &ppc64_sframe_abi_reg_map;
+ break;
case SFRAME_ABI_S390X_ENDIAN_BIG:
abi_reg_map = &s390x_sframe_abi_reg_map;
break;
@@ -287,8 +292,8 @@ dump_sframe_func_fres_simple (const sframe_decoder_ctx *sfd_ctx,
if (sframe_decoder_get_fixed_ra_offset (sfd_ctx)
!= SFRAME_CFA_FIXED_RA_INVALID)
strcpy (temp, "f");
- /* If an ABI does track RA offset, e.g. s390x, it can be a padding
- to represent FP without RA being saved on stack. */
+ /* If an ABI does track RA offset, e.g. PPC64 and s390x, it can be a
+ padding to represent FP without RA being saved on stack. */
else if (err[2] == 0 && ra_offset == SFRAME_FRE_RA_OFFSET_INVALID)
sprintf (temp, "U");
else if (err[2] == 0)
@@ -262,8 +262,10 @@ need_swapping (int endian)
{
case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
+ case SFRAME_ABI_PPC64_ENDIAN_LITTLE:
return !is_little;
case SFRAME_ABI_AARCH64_ENDIAN_BIG:
+ case SFRAME_ABI_PPC64_ENDIAN_BIG:
case SFRAME_ABI_S390X_ENDIAN_BIG:
return is_little;
default: