[v2] PowerPC: Initial SFrame support for 64-bit PowerPC ELF ABI

Message ID 20260325150411.1922791-1-abhay@linux.ibm.com
State New
Headers
Series [v2] PowerPC: Initial SFrame support for 64-bit PowerPC ELF ABI |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Abhay Kandpal March 25, 2026, 3:04 p.m. UTC
  Inspired by s390 commit d27d82f560a8 ("s390: Initial support to generate
.sframe from CFI directives in assembler").

Support for SFrame on PowerPC 64 is only enabled for the 64-bit PowerPC
ELF ABI.

The SFrame ABI/arch identifiers SFRAME_ABI_PPC64_ENDIAN_BIG and
SFRAME_ABI_PPC64_ENDIAN_LITTLE are introduced for PowerPC 64 big/little
endian and added to the SFrame format specification.

Port x86-64 commit d7f343eaad3f ("x86-64: Remove sframe relocs against
discarded sections").

Based on s390 64-bit (s390x) commit 955570f0973d ("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 PPC64 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_ABI_PPC64_ENDIAN_BIG,
	SFRAME_ABI_PPC64_ENDIAN_LITTLE): Define.
	* sframe-api.h (sframe_fre_get_ra_offset): Add PPC64 to comment
	for RA offset value of SFRAME_FRE_RA_OFFSET_INVALID indicating
	that the RA is not saved.

libsframe/
	* sframe.c (need_swapping): Handle SFRAME_ABI_PPC64_ENDIAN_BIG
	and SFRAME_ABI_PPC64_ENDIAN_LITTLE.
	* doc/sframe-spec.texi (SFRAME_ABI_PPC64_ENDIAN_BIG,
	SFRAME_ABI_PPC64_ENDIAN_LITTLE, PPC64): Document SFrame ABI/arch
	identifier for PPC64, add references to 64-bit PowerPC
	architecture, and document PPC64-specifics.
	* sframe-dump.c (ppc64_sframe_abi_reg_map): Define register map
	for PPC64.
	(sframe_get_reg_name): Use PPC64 register map for PPC64.
	(dump_sframe_func_fres_simple): Update comment to mention PPC64
	for RA offset padding.

gas/
	* NEWS: Mention powerpc64 support to generate SFrame from CFI
	directives.
	* config/tc-ppc.h (support_sframe_p, SFRAME_CFA_SP_REG,
	SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG, sframe_ra_tracking_p,
	sframe_cfa_ra_offset, sframe_get_abi_arch,
	sframe_support_flex_fde_p): Define.
	* config/tc-ppc.c (ppc_support_sframe_p,
	ppc_sframe_get_abi_arch): New functions.  Return whether SFrame
	is supported and the SFrame ABI/arch identifier.
	gen-sframe.c (get_fre_dataword_count): For PPC64 account padding
	RA offset, if FP without RA saved.
	(sframe_get_fre_dataword_size): Likewise.
	(output_sframe_row_entry_datawords): For PPC64 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 PPC64.

gas/testsuite/
	* gas/cfi-sframe/cfi-sframe.exp: Enable common SFrame tests
	on PPC64.
	* gas/cfi-sframe/cfi-sframe-common-8.s: Use registers 2 and 3,
	as register 1 is SP on PPC64.
	* gas/cfi-sframe/cfi-sframe-common-10.s: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-1.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-1.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-3.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-3.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-err-3.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-err-3.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-pr33756.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-pr33756.d: Likewise.
	* gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.s: New test.
	* gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.d: Likewise.

bfd/
	* elf64-ppc.c (ppc64_elf_relocate_section): Remove sframe relocs
	against discarded sections.

Co-authored-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Abhay Kandpal <abhay@linux.ibm.com>
---
This patch is reg tested.
Changes from v1 to v2
<Modifed the test case to use offset as per PPC ABI>
<Modified NEWS>
<Modified commit log>

 bfd/elf64-ppc.c                               |  12 ++-
 gas/NEWS                                      |   3 +
 gas/config/tc-ppc.c                           |  33 ++++++
 gas/config/tc-ppc.h                           |  31 ++++++
 gas/gen-sframe.c                              |  26 +++--
 .../gas/cfi-sframe/cfi-sframe-common-10.s     |   2 +-
 .../gas/cfi-sframe/cfi-sframe-common-8.s      |   4 +-
 .../gas/cfi-sframe/cfi-sframe-ppc64-1.d       |  24 +++++
 .../gas/cfi-sframe/cfi-sframe-ppc64-1.s       |  27 +++++
 .../gas/cfi-sframe/cfi-sframe-ppc64-3.d       |  19 ++++
 .../gas/cfi-sframe/cfi-sframe-ppc64-3.s       |   4 +
 .../gas/cfi-sframe/cfi-sframe-ppc64-err-3.d   |  15 +++
 .../gas/cfi-sframe/cfi-sframe-ppc64-err-3.s   |   5 +
 .../cfi-sframe-ppc64-fpra-offset-1.d          |  23 ++++
 .../cfi-sframe-ppc64-fpra-offset-1.s          |  17 +++
 .../cfi-sframe-ppc64-fpra-offset-2.d          |  23 ++++
 .../cfi-sframe-ppc64-fpra-offset-2.s          |  18 ++++
 .../cfi-sframe-ppc64-fpra-register-2.d        |  23 ++++
 .../cfi-sframe-ppc64-fpra-register-2.s        |  17 +++
 .../cfi-sframe-ppc64-non-spfp-cfa-2.d         |  26 +++++
 .../cfi-sframe-ppc64-non-spfp-cfa-2.s         | 100 ++++++++++++++++++
 .../gas/cfi-sframe/cfi-sframe-ppc64-pr33756.d |  24 +++++
 .../gas/cfi-sframe/cfi-sframe-ppc64-pr33756.s |  20 ++++
 .../cfi-sframe-ppc64-ra-undefined-1.d         |  24 +++++
 .../cfi-sframe-ppc64-ra-undefined-1.s         |  15 +++
 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |  15 ++-
 include/sframe-api.h                          |   8 +-
 include/sframe.h                              |   2 +
 libsframe/doc/sframe-spec.texi                |  43 +++++++-
 libsframe/sframe-dump.c                       |   9 +-
 libsframe/sframe.c                            |   2 +
 31 files changed, 589 insertions(+), 25 deletions(-)
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.s
  

Patch

diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 7e41085ed91..41aa3b82e41 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -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;
diff --git a/gas/NEWS b/gas/NEWS
index e384d1135c0..9231b72b980 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -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.
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 78e5941484c..625d1a490ee 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -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  */
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index fd1ea410213..200fab8af3c 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -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 */
diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index 7c1b7be93bb..1315d2f5f6c 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -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;
 
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-10.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-10.s
index 7761edaf2b7..8af0997be72 100644
--- a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-10.s
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-10.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s
index 50c57c9611e..f7fea786d4c 100644
--- a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-8.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.d
new file mode 100644
index 00000000000..6845063aba7
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.s
new file mode 100644
index 00000000000..012465b47eb
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-1.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.d
new file mode 100644
index 00000000000..eabd828bb0a
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.s
new file mode 100644
index 00000000000..eecf4b8fcfd
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-3.s
@@ -0,0 +1,4 @@ 
+# Although not a useful construct by itself, ensure graceful handling.
+	.cfi_startproc
+	.cfi_def_cfa_register 31
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.d
new file mode 100644
index 00000000000..804714b07be
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.s
new file mode 100644
index 00000000000..6dfdfcbe92b
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-err-3.s
@@ -0,0 +1,5 @@ 
+	.cfi_sections .sframe
+	.cfi_startproc
+	.cfi_return_column 3
+	blr
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.d
new file mode 100644
index 00000000000..54c1213e7ea
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.s
new file mode 100644
index 00000000000..46406c19290
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-1.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.d
new file mode 100644
index 00000000000..c46acdbb9e6
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.s
new file mode 100644
index 00000000000..e41a696c1ae
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-offset-2.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.d
new file mode 100644
index 00000000000..1b1aa874eea
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.s
new file mode 100644
index 00000000000..6ebe90befc9
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-fpra-register-2.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.d
new file mode 100644
index 00000000000..5718986badd
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.s
new file mode 100644
index 00000000000..70ec5031021
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-non-spfp-cfa-2.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.d
new file mode 100644
index 00000000000..359f963aab4
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.s
new file mode 100644
index 00000000000..e4852b1c7c2
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-pr33756.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.d
new file mode 100644
index 00000000000..0807ab48128
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.d
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.s
new file mode 100644
index 00000000000..bffbf3658c9
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-ppc64-ra-undefined-1.s
@@ -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
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
index a73e5c84033..d1758ab8214 100644
--- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
@@ -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"
+}
diff --git a/include/sframe-api.h b/include/sframe-api.h
index bd297a65395..0f45bb811ae 100644
--- a/include/sframe-api.h
+++ b/include/sframe-api.h
@@ -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,
diff --git a/include/sframe.h b/include/sframe.h
index 2c9019cb64d..89211e1099e 100644
--- a/include/sframe.h
+++ b/include/sframe.h
@@ -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
diff --git a/libsframe/doc/sframe-spec.texi b/libsframe/doc/sframe-spec.texi
index cd76bf9f8e3..3c5fa021927 100644
--- a/libsframe/doc/sframe-spec.texi
+++ b/libsframe/doc/sframe-spec.texi
@@ -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
 
diff --git a/libsframe/sframe-dump.c b/libsframe/sframe-dump.c
index 56cf963566e..3fe74008ac6 100644
--- a/libsframe/sframe-dump.c
+++ b/libsframe/sframe-dump.c
@@ -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)
diff --git a/libsframe/sframe.c b/libsframe/sframe.c
index cd6bb3022db..d275ef3d02e 100644
--- a/libsframe/sframe.c
+++ b/libsframe/sframe.c
@@ -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: