diff --git a/debug/backtrace.c b/debug/backtrace.c
index 969d699bd1..32490b35bb 100644
--- a/debug/backtrace.c
+++ b/debug/backtrace.c
@@ -1,5 +1,5 @@
 /* Return backtrace of current program state.
-   Copyright (C) 2003-2024 Free Software Foundation, Inc.
+   Copyright (C) 2003-2025 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <unwind.h>
 #include <unwind-link.h>
+#include <sframe.h>
 
 struct trace_arg
 {
@@ -30,6 +31,38 @@ struct trace_arg
   int size;
 };
 
+/* Initialize the SFrame backtrace routine, and try to backtrace the
+   current stack using SFrame info.  The return value of SFrame stack
+   tracer must be larger than one to consider the SFrame backtrace
+   valid. Otherwise, there may be the case that glibc is compiled
+   using SFrame but the application not.   */
+
+#define DO_SFRAME_BACKTRACE(ARRAY, SIZE)			\
+  do								\
+    {								\
+      int cnt;							\
+      frame frame;						\
+      frame.pc = getPC();					\
+      frame.sp = getSP();					\
+      frame.fp = (_Unwind_Ptr) __builtin_frame_address (0);	\
+      cnt = stacktrace_sframe (ARRAY, SIZE, &frame);		\
+      if (cnt > 1)						\
+	return cnt;						\
+    }								\
+  while(0)
+
+static _Unwind_Ptr  __attribute__ ((noinline))
+getPC (void)
+{
+  return (_Unwind_Ptr) __builtin_return_address (0);
+}
+
+static _Unwind_Ptr  __attribute__ ((noinline))
+getSP (void)
+{
+  return (_Unwind_Ptr) __builtin_dwarf_cfa();
+}
+
 static _Unwind_Reason_Code
 backtrace_helper (struct _Unwind_Context *ctx, void *a)
 {
@@ -72,7 +105,13 @@ __backtrace (void **array, int size)
      .cnt = -1
     };
 
-  if (size <= 0 || arg.unwind_link == NULL)
+  if (size <= 0)
+    return 0;
+
+  DO_SFRAME_BACKTRACE (array, size);
+
+  /* Try the dwarf unwinder.  */
+  if (arg.unwind_link == NULL)
     return 0;
 
   UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace)
diff --git a/sysdeps/generic/Makefile b/sysdeps/generic/Makefile
index 72522d1f0e..c551eb5ab1 100644
--- a/sysdeps/generic/Makefile
+++ b/sysdeps/generic/Makefile
@@ -21,6 +21,7 @@ CFLAGS-wordcopy.c += -Wno-uninitialized
 endif
 
 ifeq ($(subdir),elf)
+sysdep_routines += sframe-read sframe
 ifeq (yes:yes,$(build-shared):$(unwind-find-fde))
 # This is needed to support g++ v2 and v3.
 sysdep_routines += framestate unwind-pe
diff --git a/sysdeps/generic/sframe-read.c b/sysdeps/generic/sframe-read.c
new file mode 100644
index 0000000000..e988ad3299
--- /dev/null
+++ b/sysdeps/generic/sframe-read.c
@@ -0,0 +1,577 @@
+/* Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <sframe-read.h>
+
+#define sframe_assert(expr) (assert (expr))
+
+/* Get the SFrame header size.  */
+
+static inline uint32_t
+sframe_get_hdr_size (sframe_header *sfh)
+{
+  return SFRAME_V1_HDR_SIZE (*sfh);
+}
+
+/* Access functions for frame row entry data.  */
+
+static inline uint8_t
+sframe_fre_get_offset_count (uint8_t fre_info)
+{
+  return SFRAME_V1_FRE_OFFSET_COUNT (fre_info);
+}
+
+static inline uint8_t
+sframe_fre_get_offset_size (uint8_t fre_info)
+{
+  return SFRAME_V1_FRE_OFFSET_SIZE (fre_info);
+}
+
+static inline bool
+sframe_get_fre_ra_mangled_p (uint8_t fre_info)
+{
+  return SFRAME_V1_FRE_MANGLED_RA_P (fre_info);
+}
+
+/* Access functions for info from function descriptor entry.  */
+
+static uint32_t
+sframe_get_fre_type (sframe_func_desc_entry *fdep)
+{
+  uint32_t fre_type = 0;
+  if (fdep)
+    fre_type = SFRAME_V1_FUNC_FRE_TYPE (fdep->sfde_func_info);
+  return fre_type;
+}
+
+static uint32_t
+sframe_get_fde_type (sframe_func_desc_entry *fdep)
+{
+  uint32_t fde_type = 0;
+  if (fdep)
+    fde_type = SFRAME_V1_FUNC_FDE_TYPE (fdep->sfde_func_info);
+  return fde_type;
+}
+
+/* Check if SFrame header has valid data.  Only consider SFrame type
+   2.  */
+
+static bool
+sframe_header_sanity_check_p (sframe_header *hp)
+{
+  unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER;
+  /* Check preamble is valid.  */
+  if ((hp->sfh_preamble.sfp_magic != SFRAME_MAGIC)
+      || (hp->sfh_preamble.sfp_version != SFRAME_VERSION_2)
+      || ((hp->sfh_preamble.sfp_flags | all_flags) != all_flags))
+    return false;
+
+  /* Check offsets are valid.  */
+  if (hp->sfh_fdeoff > hp->sfh_freoff)
+    return false;
+
+  return true;
+}
+
+/* Get the FRE start address size.  */
+
+static size_t
+sframe_fre_start_addr_size (uint32_t fre_type)
+{
+  size_t addr_size = 0;
+  switch (fre_type)
+    {
+    case SFRAME_FRE_TYPE_ADDR1:
+      addr_size = 1;
+      break;
+    case SFRAME_FRE_TYPE_ADDR2:
+      addr_size = 2;
+      break;
+    case SFRAME_FRE_TYPE_ADDR4:
+      addr_size = 4;
+      break;
+    default:
+      /* No other value is expected.  */
+      sframe_assert (0);
+      break;
+    }
+  return addr_size;
+}
+
+/* Check if the FREP has valid data.  */
+
+static bool
+sframe_fre_sanity_check_p (sframe_frame_row_entry *frep)
+{
+  uint8_t offset_size, offset_cnt;
+  uint8_t fre_info;
+
+  if (frep == NULL)
+    return false;
+
+  fre_info = frep->fre_info;
+  offset_size = sframe_fre_get_offset_size (fre_info);
+
+  if (offset_size != SFRAME_FRE_OFFSET_1B
+      && offset_size != SFRAME_FRE_OFFSET_2B
+      && offset_size != SFRAME_FRE_OFFSET_4B)
+    return false;
+
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+  if (offset_cnt > MAX_NUM_STACK_OFFSETS)
+    return false;
+
+  return true;
+}
+
+/* Get FRE_INFO's offset size in bytes.  */
+
+static size_t
+sframe_fre_offset_bytes_size (uint8_t fre_info)
+{
+  uint8_t offset_size, offset_cnt;
+
+  offset_size = sframe_fre_get_offset_size (fre_info);
+
+  offset_cnt = sframe_fre_get_offset_count (fre_info);
+
+  if (offset_size == SFRAME_FRE_OFFSET_2B
+      || offset_size == SFRAME_FRE_OFFSET_4B)	/* 2 or 4 bytes.  */
+    return (offset_cnt * (offset_size * 2));
+
+  return (offset_cnt);
+}
+
+/* Get total size in bytes to represent FREP in the binary format.  This
+   includes the starting address, FRE info, and all the offsets.  */
+
+static size_t
+sframe_fre_entry_size (sframe_frame_row_entry *frep, uint32_t fre_type)
+{
+  if (frep == NULL)
+    return 0;
+
+  uint8_t fre_info = frep->fre_info;
+  size_t addr_size = sframe_fre_start_addr_size (fre_type);
+
+  return (addr_size + sizeof (frep->fre_info)
+	  + sframe_fre_offset_bytes_size (fre_info));
+}
+
+/* Check whether for the given FDEP, the SFrame Frame Row Entry identified via
+   the START_IP_OFFSET and the END_IP_OFFSET, provides the stack trace
+   information for the PC.  */
+
+static bool
+sframe_fre_check_range_p (sframe_func_desc_entry *fdep,
+			  int32_t start_ip_offset, int32_t end_ip_offset,
+			  int32_t pc)
+{
+  int32_t start_ip, end_ip;
+  int32_t func_start_addr;
+  uint8_t rep_block_size;
+  uint32_t fde_type;
+  int32_t masked_pc;
+  bool mask_p;
+  bool ret;
+
+  ret = false;
+
+  if (!fdep)
+    return ret;
+
+  func_start_addr = fdep->sfde_func_start_address;
+  fde_type = sframe_get_fde_type (fdep);
+  mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
+  rep_block_size = fdep->sfde_func_rep_size;
+
+  if (!mask_p)
+    {
+      start_ip = start_ip_offset + func_start_addr;
+      end_ip = end_ip_offset + func_start_addr;
+      ret = ((start_ip <= pc) && (end_ip >= pc));
+    }
+  else
+    {
+      /* For FDEs for repetitive pattern of insns, we need to return the FRE
+	 where pc % rep_block_size is between start_ip_offset and
+	 end_ip_offset.  */
+      masked_pc = pc % rep_block_size;
+      ret = ((start_ip_offset <= masked_pc) && (end_ip_offset >= masked_pc));
+    }
+
+  return ret;
+}
+
+/* The SFrame Decoder.  */
+
+/* Get SFrame header from the given decoder context DCTX.  */
+
+static inline sframe_header *
+sframe_decoder_get_header (sframe_decoder_ctx *dctx)
+{
+  sframe_header *hp = NULL;
+  if (dctx != NULL)
+    hp = &dctx->sfd_header;
+  return hp;
+}
+
+/* Get IDX'th offset from FRE.  Set ERRP as applicable.  */
+
+static int32_t
+sframe_get_fre_offset (sframe_frame_row_entry *fre,
+		       int idx,
+		       _Unwind_Reason_Code *errp)
+{
+  uint8_t offset_cnt, offset_size;
+
+  if (!sframe_fre_sanity_check_p (fre))
+    {
+      *errp = _URC_END_OF_STACK;
+      return 0;
+    }
+
+  offset_cnt = sframe_fre_get_offset_count (fre->fre_info);
+  offset_size = sframe_fre_get_offset_size (fre->fre_info);
+
+  if (offset_cnt < (idx + 1))
+    {
+      *errp = _URC_END_OF_STACK;
+      return 0;
+    }
+  *errp = _URC_NO_REASON;
+
+  if (offset_size == SFRAME_FRE_OFFSET_1B)
+    {
+      int8_t *sp = (int8_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else if (offset_size == SFRAME_FRE_OFFSET_2B)
+    {
+      int16_t *sp = (int16_t *)fre->fre_offsets;
+      return sp[idx];
+    }
+  else
+    {
+      int32_t *ip = (int32_t *)fre->fre_offsets;
+      return ip[idx];
+    }
+}
+
+/* Decode the SFrame FRE start address offset value from FRE_BUF in on-disk
+   binary format, given the FRE_TYPE.  Updates the FRE_START_ADDR.  */
+
+static void
+sframe_decode_fre_start_address (const char *fre_buf,
+				 uint32_t *fre_start_addr,
+				 uint32_t fre_type)
+{
+  uint32_t saddr = 0;
+
+  if (fre_type == SFRAME_FRE_TYPE_ADDR1)
+    {
+      uint8_t *uc = (uint8_t *)fre_buf;
+      saddr = (uint32_t)*uc;
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR2)
+    {
+      uint16_t *ust = (uint16_t *)fre_buf;
+      saddr = (uint32_t)*ust;
+    }
+  else if (fre_type == SFRAME_FRE_TYPE_ADDR4)
+    {
+      uint32_t *uit = (uint32_t *)fre_buf;
+      saddr = (uint32_t)*uit;
+    }
+  else
+    return;
+
+  *fre_start_addr = saddr;
+}
+
+/* Find the function descriptor entry starting which contains the specified
+   address ADDR.  */
+
+static sframe_func_desc_entry *
+sframe_get_funcdesc_with_addr_internal (sframe_decoder_ctx *ctx, int32_t addr,
+					int *errp)
+{
+  sframe_header *dhp;
+  sframe_func_desc_entry *fdp;
+  int low, high, cnt;
+
+  if (ctx == NULL)
+    return NULL;
+
+  dhp = sframe_decoder_get_header (ctx);
+
+  if (dhp == NULL || dhp->sfh_num_fdes == 0 || ctx->sfd_funcdesc == NULL)
+    return NULL;
+  /* If the FDE sub-section is not sorted on PCs, skip the lookup because
+     binary search cannot be used.  */
+  if ((dhp->sfh_preamble.sfp_flags & SFRAME_F_FDE_SORTED) == 0)
+    return NULL;
+
+  /* Do the binary search.  */
+  fdp = (sframe_func_desc_entry *) ctx->sfd_funcdesc;
+  low = 0;
+  high = dhp->sfh_num_fdes;
+  cnt = high;
+  while (low <= high)
+    {
+      int mid = low + (high - low) / 2;
+
+      if (fdp[mid].sfde_func_start_address == addr)
+	return fdp + mid;
+
+      if (fdp[mid].sfde_func_start_address < addr)
+	{
+	  if (mid == (cnt - 1)) 	/* Check if it's the last one.  */
+	    return fdp + (cnt - 1);
+	  else if (fdp[mid+1].sfde_func_start_address > addr)
+	    return fdp + mid;
+	  low = mid + 1;
+	}
+      else
+	high = mid - 1;
+    }
+
+  return NULL;
+}
+
+/* Get the end IP offset for the FRE at index i in the FDEP.  The buffer FRES
+   is the starting location for the FRE.  */
+
+static uint32_t
+sframe_fre_get_end_ip_offset (sframe_func_desc_entry *fdep, unsigned int i,
+			      const char *fres)
+{
+  uint32_t end_ip_offset = 0;
+  uint32_t fre_type;
+
+  fre_type = sframe_get_fre_type (fdep);
+
+  /* Get the start address of the next FRE in sequence.  */
+  if (i < fdep->sfde_func_num_fres - 1)
+    {
+      sframe_decode_fre_start_address (fres, &end_ip_offset, fre_type);
+      end_ip_offset -= 1;
+    }
+  else
+    /* The end IP offset for the FRE needs to be deduced from the function
+       size.  */
+    end_ip_offset = fdep->sfde_func_size - 1;
+
+  return end_ip_offset;
+}
+
+/* Get the SFrame's fixed FP offset given the decoder context CTX.  */
+
+static int8_t
+sframe_decoder_get_fixed_fp_offset (sframe_decoder_ctx *ctx)
+{
+  sframe_header *dhp;
+  dhp = sframe_decoder_get_header (ctx);
+  return dhp->sfh_cfa_fixed_fp_offset;
+}
+
+/* Get the SFrame's fixed RA offset given the decoder context CTX.  */
+
+static int8_t
+sframe_decoder_get_fixed_ra_offset (sframe_decoder_ctx *ctx)
+{
+  sframe_header *dhp;
+  dhp = sframe_decoder_get_header (ctx);
+  return dhp->sfh_cfa_fixed_ra_offset;
+}
+
+/* Get the base reg id from the FRE info.  Set errp if failure.  */
+
+uint8_t
+sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre)
+{
+  uint8_t fre_info = fre->fre_info;
+  return SFRAME_V1_FRE_CFA_BASE_REG_ID (fre_info);
+}
+
+/* Get the CFA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_cfa_offset (sframe_decoder_ctx *dctx __attribute__ ((__unused__)),
+			   sframe_frame_row_entry *fre)
+{
+  _Unwind_Reason_Code err;
+  return sframe_get_fre_offset (fre, SFRAME_FRE_CFA_OFFSET_IDX, &err);
+}
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
+			  sframe_frame_row_entry *fre,
+			  _Unwind_Reason_Code *errp)
+{
+  uint32_t fp_offset_idx = 0;
+  int8_t fp_offset = sframe_decoder_get_fixed_fp_offset (dctx);
+
+  *errp = _URC_NO_REASON;
+  /* If the FP offset is not being tracked, return the fixed FP offset
+     from the SFrame header.  */
+  if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID)
+    return fp_offset;
+
+  /* In some ABIs, the stack offset to recover RA (using the CFA) from is
+     fixed (like AMD64).  In such cases, the stack offset to recover FP will
+     appear at the second index.  */
+  fp_offset_idx = ((sframe_decoder_get_fixed_ra_offset (dctx)
+		    != SFRAME_CFA_FIXED_RA_INVALID)
+		   ? SFRAME_FRE_RA_OFFSET_IDX
+		   : SFRAME_FRE_FP_OFFSET_IDX);
+  return sframe_get_fre_offset (fre, fp_offset_idx, errp);
+}
+
+/* Get the RA offset from the FRE.  If the offset is invalid, sets errp.  */
+
+int32_t
+sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
+			  sframe_frame_row_entry *fre)
+{
+  _Unwind_Reason_Code err;
+  int8_t ra_offset = sframe_decoder_get_fixed_ra_offset (dctx);
+  /* If the RA offset was not being tracked, return the fixed RA offset
+     from the SFrame header.  */
+  if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID)
+    return ra_offset;
+
+  /* Otherwise, get the RA offset from the FRE.  */
+  return sframe_get_fre_offset (fre, SFRAME_FRE_RA_OFFSET_IDX, &err);
+}
+
+/* Decode the specified SFrame buffer SF_BUF and return the new SFrame
+   decoder context.  */
+
+_Unwind_Reason_Code
+sframe_decode (sframe_decoder_ctx *dctx, const char *sf_buf)
+{
+  const sframe_preamble *sfp;
+  size_t hdrsz;
+  sframe_header *sfheaderp;
+  char *frame_buf;
+
+  int fidx_size;
+  uint32_t fre_bytes;
+
+  if (sf_buf == NULL)
+    return _URC_END_OF_STACK;
+
+  sfp = (const sframe_preamble *) sf_buf;
+
+  /* Check for foreign endianness.  */
+  if (sfp->sfp_magic != SFRAME_MAGIC)
+    return _URC_END_OF_STACK;
+
+  frame_buf = (char *)sf_buf;
+
+  /* Handle the SFrame header.  */
+  dctx->sfd_header = *(sframe_header *) frame_buf;
+
+  /* Validate the contents of SFrame header.  */
+  sfheaderp = &dctx->sfd_header;
+  if (!sframe_header_sanity_check_p (sfheaderp))
+    return _URC_END_OF_STACK;
+
+  hdrsz = sframe_get_hdr_size (sfheaderp);
+  frame_buf += hdrsz;
+
+  /* Handle the SFrame Function Descriptor Entry section.  */
+  fidx_size
+    = sfheaderp->sfh_num_fdes * sizeof (sframe_func_desc_entry);
+  dctx->sfd_funcdesc = (sframe_func_desc_entry *)frame_buf;
+  frame_buf += (fidx_size);
+
+  dctx->sfd_fres = frame_buf;
+  fre_bytes = sfheaderp->sfh_fre_len;
+  dctx->sfd_fre_nbytes = fre_bytes;
+
+  return _URC_NO_REASON;
+}
+
+/* Find the SFrame Row Entry which contains the PC.  Returns
+   _URC_END_OF_STACK if failure.  */
+
+_Unwind_Reason_Code
+sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
+		 sframe_frame_row_entry *frep)
+{
+  sframe_func_desc_entry *fdep;
+  uint32_t fre_type, fde_type, i;
+  int32_t start_ip_offset;
+  int32_t func_start_addr;
+  int32_t end_ip_offset;
+  const char *fres;
+  size_t size = 0;
+  int err = 0;
+  bool mask_p;
+
+  if ((ctx == NULL) || (frep == NULL))
+    return _URC_END_OF_STACK;
+
+  /* Find the FDE which contains the PC, then scan its fre entries.  */
+  fdep = sframe_get_funcdesc_with_addr_internal (ctx, pc, &err);
+  if (fdep == NULL || ctx->sfd_fres == NULL)
+    return _URC_END_OF_STACK;
+
+  fre_type = sframe_get_fre_type (fdep);
+  fde_type = sframe_get_fde_type (fdep);
+  mask_p = (fde_type == SFRAME_FDE_TYPE_PCMASK);
+
+  fres = ctx->sfd_fres + fdep->sfde_func_start_fre_off;
+  func_start_addr = fdep->sfde_func_start_address;
+
+  for (i = 0; i < fdep->sfde_func_num_fres; i++)
+    {
+      size_t addr_size;
+
+      /* Partially decode the FRE.  */
+      sframe_decode_fre_start_address (fres, &frep->fre_start_addr, fre_type);
+      addr_size = sframe_fre_start_addr_size (fre_type);
+      frep->fre_info = *(uint8_t *)(fres + addr_size);
+      size = sframe_fre_entry_size (frep, fre_type);
+
+      start_ip_offset = frep->fre_start_addr;
+      end_ip_offset = sframe_fre_get_end_ip_offset (fdep, i, fres + size);
+
+      /* First FRE's start_ip must be more than pc for regular SFrame FDEs.  */
+      if (i == 0 && !mask_p && (start_ip_offset + func_start_addr) > pc)
+	return _URC_END_OF_STACK;
+
+      if (sframe_fre_check_range_p (fdep, start_ip_offset, end_ip_offset, pc))
+	{
+	  /* Decode last FRE bits: offsets size.  */
+	  frep->fre_offsets = fres + addr_size + sizeof (frep->fre_info);
+
+	  return _URC_NO_REASON;
+	}
+
+      fres += size;
+    }
+  return _URC_END_OF_STACK;
+}
diff --git a/sysdeps/generic/sframe-read.h b/sysdeps/generic/sframe-read.h
new file mode 100644
index 0000000000..6d4e72a17f
--- /dev/null
+++ b/sysdeps/generic/sframe-read.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _SFRAME_API_H
+#define _SFRAME_API_H
+
+#include <sframe.h>
+#include <stdbool.h>
+#include <unwind.h>
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+typedef struct sframe_decoder_ctx
+{
+
+  sframe_header sfd_header;
+
+  sframe_func_desc_entry *sfd_funcdesc;
+  /* SFrame FRE table.  */
+  char *sfd_fres;
+  /* Number of bytes needed for SFrame FREs.  */
+  int sfd_fre_nbytes;
+} sframe_decoder_ctx;
+
+#define MAX_NUM_STACK_OFFSETS	3
+
+/* User interfacing SFrame Row Entry.
+   An abstraction provided by libsframe so the consumer is decoupled from
+   the binary format representation of the same.
+
+   The members are best ordered such that they are aligned at their natural
+   boundaries.  This helps avoid usage of undesirable misaligned memory
+   accesses.  See PR libsframe/29856.  */
+
+typedef struct sframe_frame_row_entry
+{
+  uint32_t fre_start_addr;
+  const char *fre_offsets;
+  unsigned char fre_info;
+} sframe_frame_row_entry;
+
+/* The SFrame Decoder.  */
+
+/* Decode the specified SFrame buffer CF_BUF and return the new SFrame
+   decoder context.  */
+
+extern _Unwind_Reason_Code
+sframe_decode (sframe_decoder_ctx *dctx, const char *cf_buf);
+
+/* Find the SFrame Frame Row Entry which contains the PC.  Returns
+   _URC_END_OF_STACK if failure.  */
+
+extern _Unwind_Reason_Code
+sframe_find_fre (sframe_decoder_ctx *ctx, int32_t pc,
+		 sframe_frame_row_entry *frep);
+
+/* Get the base reg id from the FRE info.  */
+
+extern uint8_t
+sframe_fre_get_base_reg_id (sframe_frame_row_entry *fre);
+
+/* Get the CFA offset from the FRE.  */
+
+extern int32_t
+sframe_fre_get_cfa_offset (sframe_decoder_ctx *dtcx,
+			   sframe_frame_row_entry *fre);
+
+/* Get the FP offset from the FRE.  If the offset is invalid, sets errp.  */
+
+extern int32_t
+sframe_fre_get_fp_offset (sframe_decoder_ctx *dctx,
+			  sframe_frame_row_entry *fre,
+			  _Unwind_Reason_Code *errp);
+
+/* Get the RA offset from the FRE.  */
+
+extern int32_t
+sframe_fre_get_ra_offset (sframe_decoder_ctx *dctx,
+			  sframe_frame_row_entry *fre);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _SFRAME_API_H */
diff --git a/sysdeps/generic/sframe.c b/sysdeps/generic/sframe.c
new file mode 100644
index 0000000000..5f5dbe4f93
--- /dev/null
+++ b/sysdeps/generic/sframe.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <sframe-read.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <unwind.h>
+#include <uw-sigframe.h>
+
+#if DLFO_STRUCT_HAS_SFRAME
+
+static inline uint64_t
+read_stack_value (uint64_t loc)
+{
+  uint64_t value = *((uint64_t *) loc);
+  return value;
+}
+
+/* Backtrace the stack and collect the stacktrace given SFrame info.
+   If successful, store the return addresses in RA_LST. The SIZE
+   argument specifies the maximum number of return addresses that can
+   be stored in RA_LST and contains the number of the addresses
+   collected.  */
+
+int
+stacktrace_sframe (void **ra_lst, int count, frame *frame)
+{
+  _Unwind_Ptr sframe_vma, cfa, return_addr, ra_stack_loc, rfp_stack_loc, pc;
+  int cfa_offset, rfp_offset, ra_offset, i;
+  sframe_frame_row_entry fred, *frep = &fred;
+
+  if (!ra_lst || !count)
+    return 0;
+
+  for (i = 0; i < count; i++)
+    {
+      _Unwind_Reason_Code err;
+      struct dl_find_object data;
+      sframe_decoder_ctx decoder_context, *dctx = &decoder_context;
+
+      /* Clean decoder context.  */
+      memset (dctx, 0, sizeof (sframe_decoder_ctx));
+
+      /* Load and set up the SFrame stack trace info for pc.  */
+      if (_dl_find_object ((void *) frame->pc, &data) < 0)
+	return i;
+
+      sframe_vma = (_Unwind_Ptr) data.dlfo_sframe;
+      if (!sframe_vma)
+	{
+#ifdef MD_DECODE_SIGNAL_FRAME
+	  /* I cannot find a valid SFrame section. Check if it is a
+	     signal frame.  */
+	  if (MD_DECODE_SIGNAL_FRAME (frame) == _URC_NO_REASON)
+	    {
+	      ra_lst[i] = (void *) frame->pc;
+	      continue;
+	    }
+#endif
+	  return i;
+	}
+
+      /* Decode the specified SFrame buffer populate sframe's decoder
+	 context.  */
+      if (sframe_decode (dctx, (char *) data.dlfo_sframe) == _URC_END_OF_STACK)
+	return i;
+
+      pc = frame->pc - sframe_vma;
+      /* Find the SFrame Row Entry which contains the PC.  */
+      if (sframe_find_fre (dctx, pc, frep) == _URC_END_OF_STACK)
+	{
+#ifdef MD_DECODE_SIGNAL_FRAME
+	  /* I cannot find any FREs, try to see if it is a signal
+	     frame, and if so decode it.  */
+	  if (MD_DECODE_SIGNAL_FRAME (frame) == _URC_NO_REASON)
+	    {
+	      ra_lst[i] = (void *) frame->pc;
+	      continue;
+	    }
+#endif
+	  return i;
+	}
+
+      /* Get the CFA offset from the FRE.  */
+      cfa_offset = sframe_fre_get_cfa_offset (dctx, frep);
+
+      /* Get the base reg id from the FRE info.  */
+      cfa = ((sframe_fre_get_base_reg_id (frep)
+	      == SFRAME_BASE_REG_SP) ? frame->sp : frame->fp) + cfa_offset;
+
+      /* Get the RA offset from the FRE.  */
+      ra_offset = sframe_fre_get_ra_offset (dctx, frep);
+
+      ra_stack_loc = cfa + ra_offset;
+      return_addr = read_stack_value (ra_stack_loc);
+
+      ra_lst[i] = (void *)return_addr;
+
+      /* Set up for the next frame.  */
+      /* Get the FP offset from the FRE.  If the offset is invalid,
+	 sets errp.  */
+      rfp_offset = sframe_fre_get_fp_offset (dctx, frep, &err);
+      if (err == _URC_NO_REASON)
+	{
+	  /* Frame is valid, get the value stored in the stack
+	     location.  */
+	  rfp_stack_loc = cfa + rfp_offset;
+	  frame->fp = read_stack_value (rfp_stack_loc);
+	}
+
+      frame->sp = cfa;
+      frame->pc = return_addr;
+    }
+  return i;
+}
+#else
+/* Dummy function called when SFrame is not available for a target.  */
+int
+stacktrace_sframe (void **ra_lst __attribute__ ((__unused__)),
+		   int count __attribute__ ((__unused__)),
+		   frame *frame __attribute__ ((__unused__)))
+{
+  return 0;
+}
+#endif /* DLFO_STRUCT_HAS_SFRAME  */
+
+libc_hidden_def (stacktrace_sframe)
diff --git a/sysdeps/generic/sframe.h b/sysdeps/generic/sframe.h
new file mode 100644
index 0000000000..81f1a5ac8b
--- /dev/null
+++ b/sysdeps/generic/sframe.h
@@ -0,0 +1,359 @@
+/* SFrame format description.
+   Copyright (C) 2022-2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef	_SFRAME_H
+#define	_SFRAME_H
+
+#include <sys/types.h>
+#include <limits.h>
+#include <stdint.h>
+#include <unwind.h>
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* SFrame format.
+
+   SFrame format is a simple format to represent the information needed
+   for generating vanilla backtraces.  SFrame format keeps track of the
+   minimal necessary information needed for stack tracing:
+     - Canonical Frame Address (CFA)
+     - Frame Pointer (FP)
+     - Return Address (RA)
+
+   The SFrame section itself has the following structure:
+
+       +--------+------------+---------+
+       |  file  |  function  | frame   |
+       | header | descriptor |  row    |
+       |        |   entries  | entries |
+       +--------+------------+---------+
+
+   The file header stores a magic number and version information, flags, and
+   the byte offset of each of the sections relative to the end of the header
+   itself.  The file header also specifies the total number of Function
+   Descriptor Entries, Frame Row Entries and length of the FRE sub-section.
+
+   Following the header is a list of Function Descriptor Entries (FDEs).
+   This list may be sorted if the flags in the file header indicate it to be
+   so.  The sort order, if applicable, is the order of functions in the
+   .text.* sections in the resulting binary artifact.  Each Function
+   Descriptor Entry specifies the start PC of a function, the size in bytes
+   of the function and an offset to its first Frame Row Entry (FRE).  Each FDE
+   additionally also specifies the type of FRE it uses to encode the stack
+   trace information.
+
+   Next, the SFrame Frame Row Entry sub-section is a list of variable size
+   records.  Each entry represents stack trace information for a set of PCs
+   of the function.  A singular Frame Row Entry is a self-sufficient record
+   which contains information on how to generate stack trace from the
+   applicable set of PCs.
+
+   */
+
+
+/* SFrame format versions.  */
+#define SFRAME_VERSION_1	1
+#define SFRAME_VERSION_2	2
+/* SFrame magic number.  */
+#define SFRAME_MAGIC		0xdee2
+/* Current version of SFrame format.  */
+#define SFRAME_VERSION	SFRAME_VERSION_2
+
+/* Various flags for SFrame.  */
+
+/* Function Descriptor Entries are sorted on PC.  */
+#define SFRAME_F_FDE_SORTED	0x1
+/* Functions preserve frame pointer.  */
+#define SFRAME_F_FRAME_POINTER 0x2
+
+#define SFRAME_CFA_FIXED_FP_INVALID 0
+#define SFRAME_CFA_FIXED_RA_INVALID 0
+
+/* Supported ABIs/Arch.  */
+#define SFRAME_ABI_AARCH64_ENDIAN_BIG      1 /* AARCH64 big endian.  */
+#define SFRAME_ABI_AARCH64_ENDIAN_LITTLE   2 /* AARCH64 little endian.  */
+#define SFRAME_ABI_AMD64_ENDIAN_LITTLE     3 /* AMD64 little endian.  */
+
+/* SFrame FRE types.  */
+#define SFRAME_FRE_TYPE_ADDR1	0
+#define SFRAME_FRE_TYPE_ADDR2	1
+#define SFRAME_FRE_TYPE_ADDR4	2
+
+/* SFrame Function Descriptor Entry types.
+
+   The SFrame format has two possible representations for functions.  The
+   choice of which type to use is made according to the instruction patterns
+   in the relevant program stub.
+
+   An SFrame FDE of type SFRAME_FDE_TYPE_PCINC is an indication
+   that the PCs in the FREs should be treated as increments in bytes.  This is
+   used for a bulk of the executable code of a program, which contains
+   instructions with no specific pattern.
+
+   An SFrame FDE of type SFRAME_FDE_TYPE_PCMASK is an indication
+   that the PCs in the FREs should be treated as masks.  This type is useful
+   for the cases when a small pattern of instructions in a program stub is
+   repeatedly to cover a specific functionality.  Typical usescases are pltN
+   entries, trampolines etc.  */
+
+/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE.  */
+#define SFRAME_FDE_TYPE_PCINC   0
+/* Unwinders perform a (PC % REP_BLOCK_SIZE >= FRE_START_ADDR) to look up a
+   matching FRE.  */
+#define SFRAME_FDE_TYPE_PCMASK  1
+
+typedef struct sframe_preamble
+{
+  uint16_t sfp_magic;	/* Magic number (SFRAME_MAGIC).  */
+  uint8_t sfp_version;	/* Data format version number (SFRAME_VERSION).  */
+  uint8_t sfp_flags;	/* Flags.  */
+} __attribute__ ((packed)) sframe_preamble;
+
+typedef struct sframe_header
+{
+  sframe_preamble sfh_preamble;
+  /* Information about the arch (endianness) and ABI.  */
+  uint8_t sfh_abi_arch;
+  /* Offset for the Frame Pointer (FP) from CFA may be fixed for some
+     ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used).  When fixed,
+     this field specifies the fixed stack frame offset and the individual
+     FREs do not need to track it.  When not fixed, it is set to
+     SFRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide
+     the applicable stack frame offset, if any.  */
+  int8_t sfh_cfa_fixed_fp_offset;
+  /* Offset for the Return Address from CFA is fixed for some ABIs
+     (e.g., AMD64 has it as CFA-8).  When fixed, the header specifies the
+     fixed stack frame offset and the individual FREs do not track it.  When
+     not fixed, it is set to SFRAME_CFA_FIXED_RA_INVALID, and individual
+     FREs provide the applicable stack frame offset, if any.  */
+  int8_t sfh_cfa_fixed_ra_offset;
+  /* Number of bytes making up the auxiliary header, if any.
+     Some ABI/arch, in the future, may use this space for extending the
+     information in SFrame header.  Auxiliary header is contained in
+     bytes sequentially following the sframe_header.  */
+  uint8_t sfh_auxhdr_len;
+  /* Number of SFrame FDEs in this SFrame section.  */
+  uint32_t sfh_num_fdes;
+  /* Number of SFrame Frame Row Entries.  */
+  uint32_t sfh_num_fres;
+  /* Number of bytes in the SFrame Frame Row Entry section. */
+  uint32_t sfh_fre_len;
+  /* Offset of SFrame Function Descriptor Entry section.  */
+  uint32_t sfh_fdeoff;
+  /* Offset of SFrame Frame Row Entry section.  */
+  uint32_t sfh_freoff;
+} __attribute__ ((packed)) sframe_header;
+
+#define SFRAME_V1_HDR_SIZE(sframe_hdr)	\
+  ((sizeof (sframe_header) + (sframe_hdr).sfh_auxhdr_len))
+
+/* Two possible keys for executable (instruction) pointers signing.  */
+#define SFRAME_AARCH64_PAUTH_KEY_A    0 /* Key A.  */
+#define SFRAME_AARCH64_PAUTH_KEY_B    1 /* Key B.  */
+
+typedef struct sframe_func_desc_entry
+{
+  /* Function start address.  Encoded as a signed offset, relative to the
+     beginning of the current FDE.  */
+  int32_t sfde_func_start_address;
+  /* Size of the function in bytes.  */
+  uint32_t sfde_func_size;
+  /* Offset of the first SFrame Frame Row Entry of the function, relative to the
+     beginning of the SFrame Frame Row Entry sub-section.  */
+  uint32_t sfde_func_start_fre_off;
+  /* Number of frame row entries for the function.  */
+  uint32_t sfde_func_num_fres;
+  /* Additional information for stack tracing from the function:
+     - 4-bits: Identify the FRE type used for the function.
+     - 1-bit: Identify the FDE type of the function - mask or inc.
+     - 1-bit: PAC authorization A/B key (aarch64).
+     - 2-bits: Unused.
+     ------------------------------------------------------------------------
+     |     Unused    |  PAC auth A/B key (aarch64) |  FDE type |   FRE type   |
+     |               |        Unused (amd64)       |           |              |
+     ------------------------------------------------------------------------
+     8               6                             5           4              0     */
+  uint8_t sfde_func_info;
+  /* Size of the block of repeating insns.  Used for SFrame FDEs of type
+     SFRAME_FDE_TYPE_PCMASK.  */
+  uint8_t sfde_func_rep_size;
+  uint16_t sfde_func_padding2;
+} __attribute__ ((packed)) sframe_func_desc_entry;
+
+/* Macros to compose and decompose function info in FDE.  */
+
+/* Note: Set PAC auth key to SFRAME_AARCH64_PAUTH_KEY_A by default.  */
+#define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \
+  (((SFRAME_AARCH64_PAUTH_KEY_A & 0x1) << 5) | \
+   (((fde_type) & 0x1) << 4) | ((fre_enc_type) & 0xf))
+
+#define SFRAME_V1_FUNC_FRE_TYPE(data)	  ((data) & 0xf)
+#define SFRAME_V1_FUNC_FDE_TYPE(data)	  (((data) >> 4) & 0x1)
+#define SFRAME_V1_FUNC_PAUTH_KEY(data)	  (((data) >> 5) & 0x1)
+
+/* Set the pauth key as indicated.  */
+#define SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY(pauth_key, fde_info) \
+  ((((pauth_key) & 0x1) << 5) | ((fde_info) & 0xdf))
+
+/* Size of stack frame offsets in an SFrame Frame Row Entry.  A single
+   SFrame FRE has all offsets of the same size.  Offset size may vary
+   across frame row entries.  */
+#define SFRAME_FRE_OFFSET_1B	  0
+#define SFRAME_FRE_OFFSET_2B	  1
+#define SFRAME_FRE_OFFSET_4B	  2
+
+/* An SFrame Frame Row Entry can be SP or FP based.  */
+#define SFRAME_BASE_REG_FP	0
+#define SFRAME_BASE_REG_SP	1
+
+/* The index at which a specific offset is presented in the variable length
+   bytes of an FRE.  */
+#define SFRAME_FRE_CFA_OFFSET_IDX   0
+/* The RA stack offset, if present, will always be at index 1 in the variable
+   length bytes of the FRE.  */
+#define SFRAME_FRE_RA_OFFSET_IDX    1
+/* The FP stack offset may appear at offset 1 or 2, depending on the ABI as RA
+   may or may not be tracked.  */
+#define SFRAME_FRE_FP_OFFSET_IDX    2
+
+typedef struct sframe_fre_info
+{
+  /* Information about
+     - 1 bit: base reg for CFA
+     - 4 bits: Number of offsets (N).  A value of upto 3 is allowed to track
+     all three of CFA, FP and RA (fixed implicit order).
+     - 2 bits: information about size of the offsets (S) in bytes.
+     Valid values are SFRAME_FRE_OFFSET_1B, SFRAME_FRE_OFFSET_2B,
+     SFRAME_FRE_OFFSET_4B
+     - 1 bit: Mangled RA state bit (aarch64 only).
+     ----------------------------------------------------------------------------------
+     | Mangled-RA (aarch64) |  Size of offsets   |   Number of offsets    |   base_reg |
+     |  Unused (amd64)      |                    |                        |            |
+     ----------------------------------------------------------------------------------
+     8                     7                    5                        1            0
+
+     */
+  uint8_t fre_info;
+} sframe_fre_info;
+
+/* Macros to compose and decompose FRE info.  */
+
+/* Note: Set mangled_ra_p to zero by default.  */
+#define SFRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \
+  (((0 & 0x1) << 7) | (((offset_size) & 0x3) << 5) | \
+   (((offset_num) & 0xf) << 1) | ((base_reg_id) & 0x1))
+
+/* Set the mangled_ra_p bit as indicated.  */
+#define SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P(mangled_ra_p, fre_info) \
+  ((((mangled_ra_p) & 0x1) << 7) | ((fre_info) & 0x7f))
+
+#define SFRAME_V1_FRE_CFA_BASE_REG_ID(data)	  ((data) & 0x1)
+#define SFRAME_V1_FRE_OFFSET_COUNT(data)	  (((data) >> 1) & 0xf)
+#define SFRAME_V1_FRE_OFFSET_SIZE(data)		  (((data) >> 5) & 0x3)
+#define SFRAME_V1_FRE_MANGLED_RA_P(data)	  (((data) >> 7) & 0x1)
+
+/* SFrame Frame Row Entry definitions.
+
+   Used for both AMD64 and AARCH64.
+
+   An SFrame Frame Row Entry is a self-sufficient record which contains
+   information on how to generate the stack trace for the specified range of
+   PCs.  Each SFrame Frame Row Entry is followed by S*N bytes, where:
+     S is the size of the stack frame offset for the FRE, and
+     N is the number of stack frame offsets in the FRE
+
+   The interpretation of FRE stack offsets is ABI-specific:
+
+   AMD64:
+     offset1 (interpreted as CFA = BASE_REG + offset1)
+      if FP is being tracked
+	offset2 (intrepreted as FP = CFA + offset2)
+      fi
+
+    AARCH64:
+     offset1 (interpreted as CFA = BASE_REG + offset1)
+     if FP is being tracked (in other words, if frame record created)
+       offset2 (interpreted as RA = CFA + offset2)
+       offset3 (intrepreted as FP = CFA + offset3)
+     fi
+     Note that in AAPCS64, a frame record, if created, will save both FP and
+     LR on stack.
+*/
+
+/* Used when SFRAME_FRE_TYPE_ADDR1 is specified as FRE type.  */
+typedef struct sframe_frame_row_entry_addr1
+{
+  /* Start address of the frame row entry.  Encoded as an 1-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint8_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} __attribute__ ((packed)) sframe_frame_row_entry_addr1;
+
+/* Upper limit of start address in sframe_frame_row_entry_addr1
+   is 0x100 (not inclusive).  */
+#define SFRAME_FRE_TYPE_ADDR1_LIMIT   \
+  (1ULL << ((SFRAME_FRE_TYPE_ADDR1 + 1) * 8))
+
+/* Used when SFRAME_FRE_TYPE_ADDR2 is specified as FRE type.  */
+typedef struct sframe_frame_row_entry_addr2
+{
+  /* Start address of the frame row entry.  Encoded as an 2-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint16_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} __attribute__ ((packed)) sframe_frame_row_entry_addr2;
+
+/* Upper limit of start address in sframe_frame_row_entry_addr2
+   is 0x10000 (not inclusive).  */
+#define SFRAME_FRE_TYPE_ADDR2_LIMIT   \
+  (1ULL << ((SFRAME_FRE_TYPE_ADDR2 * 2) * 8))
+
+/* Used when SFRAME_FRE_TYPE_ADDR4 is specified as FRE type.  */
+typedef struct sframe_frame_row_entry_addr4
+{
+  /* Start address of the frame row entry.  Encoded as a 4-byte unsigned
+     offset, relative to the start address of the function.  */
+  uint32_t sfre_start_address;
+  sframe_fre_info sfre_info;
+} __attribute__ ((packed)) sframe_frame_row_entry_addr4;
+
+/* Upper limit of start address in sframe_frame_row_entry_addr2
+   is 0x100000000 (not inclusive).  */
+#define SFRAME_FRE_TYPE_ADDR4_LIMIT   \
+  (1ULL << ((SFRAME_FRE_TYPE_ADDR4 * 2) * 8))
+
+/* Used to pass frame information to stack trace routine.  */
+typedef struct cframe
+{
+  _Unwind_Ptr pc;
+  _Unwind_Ptr sp;
+  _Unwind_Ptr fp;
+} frame;
+
+/* SFrame stack traching support */
+int stacktrace_sframe (void **, int, frame *);
+libc_hidden_proto (stacktrace_sframe)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _SFRAME_H */
diff --git a/sysdeps/generic/uw-sigframe.h b/sysdeps/generic/uw-sigframe.h
new file mode 100644
index 0000000000..77dbff78b6
--- /dev/null
+++ b/sysdeps/generic/uw-sigframe.h
@@ -0,0 +1,17 @@
+/* Internal header file for handling signal frames.  Generic version.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
