[binutils-gdb] [SFrame-V3] sframe: gas: bfd: add support for signal frames

Indu Bhagat ibhagat@sourceware.org
Fri Jan 16 01:04:11 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0bdf18b8a5363459ee7874f34ede3f6db589b727

commit 0bdf18b8a5363459ee7874f34ede3f6db589b727
Author: Indu Bhagat <indu.bhagat@oracle.com>
Date:   Thu Jan 15 16:42:09 2026 -0800

    [SFrame-V3] sframe: gas: bfd: add support for signal frames
    
    Reserve a bit in function info byte in the SFrame FDE to designate
    signal frames.
    
    Also update the SFrame opt code in GAS and dumping routines in libsframe
    to handle signal frame bit.
    
    include/
            * sframe.h (SFRAME_V3_FDE_SIGNAL_P): Extract signal frame bit.
            (SFRAME_V3_FDE_UPDATE_SIGNAL_P): Set signal frame bit.
    gas/
            * gen-sframe.c (get_dw_fde_signal_p): New function to retrieve signal
            frame state from DWARF FDE.
            (sframe_v3_set_func_info): Renamed from sframe_v1_set_func_info.
            Accept signal_p argument and encode it.
            (sframe_set_version): Update ops to use sframe_v3_set_func_info.
            (sframe_set_func_info): Pass signal_p to the ops hook.
            (output_sframe_funcdesc): Retrieve signal frame marker and pass to
            sframe_set_func_info.
            * gen-sframe.h (struct sframe_version_ops): Update set_func_info
            signature.
            * sframe-opt.c (sframe_convert_frag): Preserve signal_p bit during
            fragment conversion.  While at it, use SFRAME_V3_* macros where
            applicable.
    libsframe/testsuite/
            * gas/cfi-sframe/cfi-sframe-common-13.d: New test.
            * gas/cfi-sframe/cfi-sframe-common-13.s: New test.
            * gas/cfi-sframe/cfi-sframe.exp: Run new test.
    libsframe/
            * sframe-dump.c (dump_sframe_func_with_fres): Decode signal frame bit
            and print "S" attribute in the dump output.

Diff:
---
 gas/gen-sframe.c                                   | 30 +++++++++++++++-------
 gas/gen-sframe.h                                   |  3 ++-
 gas/sframe-opt.c                                   | 11 +++++---
 .../gas/cfi-sframe/cfi-sframe-common-13.d          | 19 ++++++++++++++
 .../gas/cfi-sframe/cfi-sframe-common-13.s          |  3 +++
 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp        |  1 +
 include/sframe.h                                   | 17 +++++++-----
 libsframe/sframe-dump.c                            | 23 +++++++++++------
 8 files changed, 79 insertions(+), 28 deletions(-)

diff --git a/gas/gen-sframe.c b/gas/gen-sframe.c
index 3d87143eb0a..f79f5cdd97f 100644
--- a/gas/gen-sframe.c
+++ b/gas/gen-sframe.c
@@ -116,6 +116,13 @@ get_dw_fde_pauth_b_key_p (const struct fde_entry *dw_fde ATTRIBUTE_UNUSED)
 #endif
 }
 
+/* Get whether signal frame.  */
+static bool
+get_dw_fde_signal_p (const struct fde_entry *dw_fde)
+{
+  return (dw_fde->signal_frame == 1);
+}
+
 /* SFrame Frame Row Entry (FRE) related functions.  */
 
 static void
@@ -284,14 +291,16 @@ sframe_v1_set_fre_info (unsigned int cfa_base_reg, unsigned int num_offsets,
   return fre_info;
 }
 
-/* SFrame (SFRAME_VERSION_1) set function info.  */
+/* SFrame (SFRAME_VERSION_3) set function info.  */
+
 static unsigned char
-sframe_v1_set_func_info (unsigned int fde_type, unsigned int fre_type,
-			 unsigned int pauth_key)
+sframe_v3_set_func_info (unsigned int fde_pc_type, unsigned int fre_type,
+			 unsigned int pauth_key, bool signal_p)
 {
   unsigned char func_info;
-  func_info = SFRAME_V1_FUNC_INFO (fde_type, fre_type);
-  func_info = SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, func_info);
+  func_info = SFRAME_V3_FDE_FUNC_INFO (fde_pc_type, fre_type);
+  func_info = SFRAME_V3_FDE_UPDATE_PAUTH_KEY (pauth_key, func_info);
+  func_info = SFRAME_V3_FDE_UPDATE_SIGNAL_P (signal_p, func_info);
   return func_info;
 }
 
@@ -307,7 +316,7 @@ sframe_set_version (uint32_t sframe_version ATTRIBUTE_UNUSED)
 
   sframe_ver_ops.set_fre_info = sframe_v1_set_fre_info;
 
-  sframe_ver_ops.set_func_info = sframe_v1_set_func_info;
+  sframe_ver_ops.set_func_info = sframe_v3_set_func_info;
 }
 
 /* SFrame set FRE info.  */
@@ -324,9 +333,10 @@ sframe_set_fre_info (unsigned int cfa_base_reg, unsigned int num_offsets,
 
 static unsigned char
 sframe_set_func_info (unsigned int fde_type, unsigned int fre_type,
-		      unsigned int pauth_key)
+		      unsigned int pauth_key, bool signal_p)
 {
-  return sframe_ver_ops.set_func_info (fde_type, fre_type, pauth_key);
+  return sframe_ver_ops.set_func_info (fde_type, fre_type, pauth_key,
+				       signal_p);
 }
 
 /* Get the number of SFrame FDEs for the current file.  */
@@ -680,6 +690,7 @@ output_sframe_funcdesc (symbolS *start_of_fre_section,
   expressionS exp;
   symbolS *dw_fde_start_addrS, *dw_fde_end_addrS;
   unsigned int pauth_key;
+  bool signal_p;
 
   dw_fde_start_addrS = get_dw_fde_start_addrS (sframe_fde->dw_fde);
   dw_fde_end_addrS = get_dw_fde_end_addrS (sframe_fde->dw_fde);
@@ -723,9 +734,10 @@ output_sframe_funcdesc (symbolS *start_of_fre_section,
   unsigned char func_info;
   pauth_key = (get_dw_fde_pauth_b_key_p (sframe_fde->dw_fde)
 	       ? SFRAME_AARCH64_PAUTH_KEY_B : SFRAME_AARCH64_PAUTH_KEY_A);
+  signal_p = get_dw_fde_signal_p (sframe_fde->dw_fde);
   func_info = sframe_set_func_info (SFRAME_FDE_TYPE_PCINC,
 				    SFRAME_FRE_TYPE_ADDR4,
-				    pauth_key);
+				    pauth_key, signal_p);
   if (SFRAME_FRE_TYPE_SELECTION_OPT)
     {
       expressionS cexp;
diff --git a/gas/gen-sframe.h b/gas/gen-sframe.h
index 78d4f1bd6c1..eff089f6a24 100644
--- a/gas/gen-sframe.h
+++ b/gas/gen-sframe.h
@@ -157,7 +157,8 @@ struct sframe_version_ops
   unsigned char (*set_fre_info) (unsigned int, unsigned int, unsigned int,
 				 bool);
   /* set SFrame Func info.  */
-  unsigned char (*set_func_info) (unsigned int, unsigned int, unsigned int);
+  unsigned char (*set_func_info) (unsigned int, unsigned int, unsigned int,
+				  bool);
 };
 
 /* Generate SFrame stack trace info and prepare contents for the output.
diff --git a/gas/sframe-opt.c b/gas/sframe-opt.c
index 9ce56ed27e2..e13726d4bc6 100644
--- a/gas/sframe-opt.c
+++ b/gas/sframe-opt.c
@@ -106,6 +106,7 @@ sframe_convert_frag (fragS *frag)
   offsetT rest_of_data;
   uint8_t fde_pc_type, fre_type;
   uint8_t pauth_key;
+  bool signal_p;
 
   expressionS *exp;
   symbolS *dataS;
@@ -128,8 +129,9 @@ sframe_convert_frag (fragS *frag)
 	 the fre_type.  */
       dataS = exp->X_add_symbol;
       rest_of_data = (symbol_get_value_expression(dataS))->X_add_number;
-      fde_pc_type = SFRAME_V2_FUNC_PC_TYPE (rest_of_data);
-      pauth_key = SFRAME_V2_FUNC_PAUTH_KEY (rest_of_data);
+      fde_pc_type = SFRAME_V3_FDE_PC_TYPE (rest_of_data);
+      pauth_key = SFRAME_V3_AARCH64_FDE_PAUTH_KEY (rest_of_data);
+      signal_p = SFRAME_V3_FDE_SIGNAL_P (rest_of_data);
       gas_assert (fde_pc_type == SFRAME_FDE_TYPE_PCINC);
 
       /* Calculate the applicable fre_type.  */
@@ -143,8 +145,9 @@ sframe_convert_frag (fragS *frag)
 	fre_type = SFRAME_FRE_TYPE_ADDR4;
 
       /* Create the new function info.  */
-      value = SFRAME_V2_FUNC_INFO (fde_pc_type, fre_type);
-      value = SFRAME_V2_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, value);
+      value = SFRAME_V3_FDE_FUNC_INFO (fde_pc_type, fre_type);
+      value = SFRAME_V3_FDE_UPDATE_PAUTH_KEY (pauth_key, value);
+      value = SFRAME_V3_FDE_UPDATE_SIGNAL_P (signal_p, value);
 
       frag->fr_literal[frag->fr_fix] = value;
     }
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-13.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-13.d
new file mode 100644
index 00000000000..5864fa67616
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-13.d
@@ -0,0 +1,19 @@
+#as: --gsframe
+#objdump: --sframe=.sframe
+#name: Signal Frame
+#...
+Contents of the SFrame section .sframe:
+
+  Header :
+
+    Version: SFRAME_VERSION_3
+    Flags: SFRAME_F_FDE_FUNC_START_PCREL
+#?    CFA fixed FP offset: \-?\d+
+#?    CFA fixed RA offset: \-?\d+
+    Num FDEs: 1
+    Num FREs: 1
+
+  Function Index :
+    func idx \[0\]: pc = 0x0, size = 0 bytes, attr = \"S\"
+    STARTPC + CFA + FP + RA +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-13.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-13.s
new file mode 100644
index 00000000000..0009281d059
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-common-13.s
@@ -0,0 +1,3 @@
+	.cfi_startproc
+	.cfi_signal_frame
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
index 4dbe69bc097..f7c5abf01b2 100644
--- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
@@ -48,6 +48,7 @@ if  { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]
     run_dump_test "cfi-sframe-common-10"
     run_dump_test "cfi-sframe-common-11"
     run_dump_test "cfi-sframe-common-12"
+    run_dump_test "cfi-sframe-common-13"
 
     run_dump_test "common-empty-2"
     run_dump_test "common-empty-3"
diff --git a/include/sframe.h b/include/sframe.h
index bda96e8be5b..8e3510fdd86 100644
--- a/include/sframe.h
+++ b/include/sframe.h
@@ -261,12 +261,13 @@ typedef struct sframe_func_desc_entry_v3
      - 4-bits: Identify the FRE type used for the function.
      - 1-bit: Identify the PC 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   |   FRE Type   |
-     |               |     Unused (amd64, s390x)   | PC Type |              |
-     ------------------------------------------------------------------------
-     8               6                             5         4              0     */
+     - 1-bits: Unused.
+     - 1-bit: Signal frame.
+     -------------------------------------------------------------------------------
+     | Signal |   Unused    |  PAC auth A/B key (aarch64) |   FDE   |   FRE Type   |
+     | frame  |             |        Unused (amd64)       | PC Type |              |
+     -------------------------------------------------------------------------------
+     8        7             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.  */
@@ -279,10 +280,14 @@ typedef struct sframe_func_desc_entry_v3
 #define SFRAME_V3_FDE_FRE_TYPE(info)          (SFRAME_V2_FUNC_FRE_TYPE (info))
 #define SFRAME_V3_FDE_PC_TYPE(info)           (SFRAME_V2_FUNC_PC_TYPE (info))
 #define SFRAME_V3_AARCH64_FDE_PAUTH_KEY(info) (SFRAME_V2_FUNC_PAUTH_KEY (info))
+#define SFRAME_V3_FDE_SIGNAL_P(info)           (((info) >> 7) & 0x1)
 
 #define SFRAME_V3_FDE_UPDATE_PAUTH_KEY(pauth_key, info) \
   SFRAME_V2_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, info)
 
+#define SFRAME_V3_FDE_UPDATE_SIGNAL_P(signal_p, info)  \
+  ((((signal_p) & 0x1) << 7) | ((info) & 0x7f))
+
 /* 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.  */
diff --git a/libsframe/sframe-dump.c b/libsframe/sframe-dump.c
index 757997608b9..394dbdc9158 100644
--- a/libsframe/sframe-dump.c
+++ b/libsframe/sframe-dump.c
@@ -169,25 +169,32 @@ dump_sframe_func_with_fres (const sframe_decoder_ctx *sfd_ctx,
 								     funcidx,
 								     NULL);
 
-  /* Mark FDEs with [m] where the FRE start address is interpreted as a
-     mask.  */
-  int pc_mask_p
-    = (SFRAME_V2_FUNC_PC_TYPE (func_info) == SFRAME_FDE_TYPE_PCMASK);
-  const char *fde_type_marker = (pc_mask_p ? "[m]" : "   ");
+  /* Gather all FDE attributes.  */
+  char attrs[16] = {0};
+  bool fde_signal_p = SFRAME_V3_FDE_SIGNAL_P (func_info);
+  sprintf (attrs, fde_signal_p ? "S" : "");
 
   printf ("\n    func idx [%d]: pc = 0x%"PRIx64 ", size = %d bytes",
 	  funcidx,
 	  func_start_pc_vma,
 	  func_size);
+  /* Print attributes if they exist.  */
+  if (attrs[0])
+    printf (", attr = \"%s\"", attrs);
 
   if (is_sframe_abi_arch_aarch64 (sfd_ctx)
       && (SFRAME_V2_FUNC_PAUTH_KEY (func_info) == SFRAME_AARCH64_PAUTH_KEY_B))
     printf (", pauth = B key");
 
-  char temp[100];
-
+  /* Mark FDEs with [m] where the FRE start address is interpreted as a
+     mask.  */
+  int pc_mask_p
+    = (SFRAME_V2_FUNC_PC_TYPE (func_info) == SFRAME_FDE_TYPE_PCMASK);
+  const char *pc_mask_marker = (pc_mask_p ? "[m]" : "   ");
   printf ("\n    %-7s%-8s %-10s%-10s%-13s",
-	  "STARTPC", fde_type_marker, "CFA", "FP", "RA");
+	  "STARTPC", pc_mask_marker, "CFA", "FP", "RA");
+
+  char temp[100] = {0};
   for (j = 0; j < num_fres; j++)
     {
       sframe_decoder_get_fre (sfd_ctx, funcidx, j, &fre);


More information about the Binutils-cvs mailing list