[binutils-gdb] libsframe: fix issue finding FRE in PCMASK type SFrame FDEs

Indu Bhagat ibhagat@sourceware.org
Mon May 26 18:08:53 GMT 2025


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

commit 4e94f00756694ff3aa2ea9433bd4ef114964aa48
Author: Indu Bhagat <indu.bhagat@oracle.com>
Date:   Mon May 26 10:54:06 2025 -0700

    libsframe: fix issue finding FRE in PCMASK type SFrame FDEs
    
    SFrame FDEs of type SFRAME_FDE_TYPE_PCMASK are used for repetitive code
    patterns, e.g., pltN entries.  For SFrame FDEs of type
    SFRAME_FDE_TYPE_PCMASK, sframe_fre_check_range_p erroneously tested the
    given PC instead of the masked PC offset from function start address.
    Therefore it only worked correctly by chance, e.g., if the function start
    address was aligned on the repetition block size.
    
    For regular SFrame FDEs the PC offset from function start address must
    be within a SFrame FRE's start IP offset and end IP offset.  For SFrame
    FDEs of type SFRAME_FDE_TYPE_PCMASK, the masked PC offset must be within
    that range.
    
    SFrame FRE start/end IP offsets are relative to the SFrame FDE function
    start address. For regular SFrame FDEs, the PC offset from function
    start address must be within a SFrame FRE's start IP offset and end IP
    offset.  For SFRAME_FDE_TYPE_PCMASK type FDEs, the masked PC offset must
    be within that range.
    
    Exercise the testcase for a variety of placements; without the fix some
    of these tests will fail.  Also, make the testcase itself easier to
    follow by adding appropriate vars where applicable.
    
    libsframe/
            * sframe.c (sframe_fre_check_range_p): Fix logic for
            SFRAME_FDE_TYPE_PCMASK type FDE.
    libsframe/testsuite/
            * libsframe.find/plt-findfre-1.c: Adjust the test for a variety
            of placements of .sframe and .plt.
    
    Co-Authored-by: Jens Remus <jremus@linux.ibm.com>

Diff:
---
 libsframe/sframe.c                                 | 29 +++-----
 libsframe/testsuite/libsframe.find/plt-findfre-1.c | 79 ++++++++++++++--------
 2 files changed, 58 insertions(+), 50 deletions(-)

diff --git a/libsframe/sframe.c b/libsframe/sframe.c
index c2693b978ec..c1bc692829a 100644
--- a/libsframe/sframe.c
+++ b/libsframe/sframe.c
@@ -372,40 +372,27 @@ 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;
+  int32_t pc_offset;
   bool mask_p;
-  bool ret;
-
-  ret = false;
 
   if (!fdep)
-    return ret;
+    return false;
 
   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));
-    }
+  pc_offset = pc - func_start_addr;
+  /* For SFrame FDEs encoding information for repetitive pattern of insns,
+     masking with the rep_block_size is necessary to find the matching FRE.  */
+  if (mask_p)
+    pc_offset = pc_offset % rep_block_size;
 
-  return ret;
+  return (start_ip_offset <= pc_offset) && (end_ip_offset >= pc_offset);
 }
 
 static int
diff --git a/libsframe/testsuite/libsframe.find/plt-findfre-1.c b/libsframe/testsuite/libsframe.find/plt-findfre-1.c
index c84b46f4d35..60037fd67ea 100644
--- a/libsframe/testsuite/libsframe.find/plt-findfre-1.c
+++ b/libsframe/testsuite/libsframe.find/plt-findfre-1.c
@@ -28,12 +28,13 @@
 #include <dejagnu.h>
 
 static int
-add_plt_fde1 (sframe_encoder_ctx *ectx, int idx)
+add_plt_fde1 (sframe_encoder_ctx *ectx, uint32_t plt_vaddr,
+	      uint32_t sframe_vaddr, int idx)
 {
-  int i, err;
   /* A contiguous block containing 3 FREs.  The start_ip_offset must remain
      less than 16 bytes.  */
-  sframe_frame_row_entry fres[]
+#define PLT1_NUM_FRES    3
+  sframe_frame_row_entry fres[PLT1_NUM_FRES]
     = { {0x0, {0x1, 0, 0}, 0x3},
 	{0x6, {0x2, 0xf0, 0}, 0x5},
 	{0xc, {0x3, 0xf0, 0}, 0x4}
@@ -41,19 +42,26 @@ add_plt_fde1 (sframe_encoder_ctx *ectx, int idx)
 
   unsigned char finfo = sframe_fde_create_func_info (SFRAME_FRE_TYPE_ADDR1,
 						     SFRAME_FDE_TYPE_PCMASK);
+  int32_t func_start_addr = plt_vaddr - sframe_vaddr;
+
   /* 5 pltN entries of 16 bytes each.  */
-  err = sframe_encoder_add_funcdesc_v2 (ectx, 0x1000, 16*5, finfo, 16, 3);
+  int err = sframe_encoder_add_funcdesc_v2 (ectx, func_start_addr,
+					    16 * 5 /* func size in bytes.  */,
+					    finfo,
+					    16 /* rep block size in bytes.  */,
+					    PLT1_NUM_FRES);
   if (err == -1)
     return err;
 
-  for (i = 0; i < 3; i++)
-    if (sframe_encoder_add_fre (ectx, idx, fres+i) == SFRAME_ERR)
+  for (unsigned i = 0; i < PLT1_NUM_FRES; i++)
+    if (sframe_encoder_add_fre (ectx, idx, fres + i) == SFRAME_ERR)
       return -1;
 
   return 0;
 }
 
-int main (void)
+static
+void test_plt_findfre (uint32_t plt_vaddr, uint32_t sframe_vaddr)
 {
   sframe_encoder_ctx *ectx;
   sframe_decoder_ctx *dctx;
@@ -61,7 +69,7 @@ int main (void)
   char *sframe_buf;
   size_t sf_size;
   int err = 0;
-  unsigned int fde_cnt = 0;
+  uint32_t fde_cnt = 0;
 
 #define TEST(name, cond)                                                      \
   do                                                                          \
@@ -78,7 +86,7 @@ int main (void)
 			-8, /* Fixed RA offset for AMD64.  */
 			&err);
 
-  err = add_plt_fde1 (ectx, 0);
+  err = add_plt_fde1 (ectx, plt_vaddr, sframe_vaddr, 0);
   TEST ("plt-findfre-1: Adding FDE1 for plt", err == 0);
 
   fde_cnt = sframe_encoder_get_num_fidx (ectx);
@@ -88,40 +96,53 @@ int main (void)
   TEST ("plt-findfre-1: Encoder write", err == 0);
 
   dctx = sframe_decode (sframe_buf, sf_size, &err);
-  TEST("plt-findfre-1: Decoder setup", dctx != NULL);
+  TEST ("plt-findfre-1: Decoder setup", dctx != NULL);
 
   /* Find the first FRE in PLT1.  */
-  err = sframe_find_fre (dctx, (0x1000 + 0x0), &frep);
-  TEST("plt-findfre-1: Find first FRE in PLT1",
-       ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1)));
+  err = sframe_find_fre (dctx, (plt_vaddr + 0x0 - sframe_vaddr), &frep);
+  TEST ("plt-findfre-1: Find first FRE in PLT1",
+	(err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1));
 
   /* Find the second FRE.  */
-  err = sframe_find_fre (dctx, (0x1000 + 0x6), &frep);
-  TEST("plt-findfre-1: Find second FRE in PLT1",
-       ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2)));
+  err = sframe_find_fre (dctx, (plt_vaddr + 0x6 - sframe_vaddr), &frep);
+  TEST ("plt-findfre-1: Find second FRE in PLT1",
+	(err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2));
 
   /* Find the last FRE.  */
-  err = sframe_find_fre (dctx, (0x1000 + 0xc), &frep);
-  TEST("plt-findfre-1: Find last FRE in PLT1",
-       ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3)));
+  err = sframe_find_fre (dctx, (plt_vaddr + 0xc - sframe_vaddr), &frep);
+  TEST ("plt-findfre-1: Find last FRE in PLT1",
+	(err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3));
 
   /* Find the first FRE in PLT4.  */
-  err = sframe_find_fre (dctx, (0x1000 + 16*3 + 0x0), &frep);
-  TEST("plt-findfre-1: Find first FRE in PLT4",
-       ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1)));
+  err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0x0 - sframe_vaddr), &frep);
+  TEST ("plt-findfre-1: Find first FRE in PLT4",
+	(err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x1));
 
   /* Find the second FRE in PLT4.  */
-  err = sframe_find_fre (dctx, (0x1000 + 16*3 + 0x6), &frep);
-  TEST("plt-findfre-1: Find second FRE in PLT4",
-       ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2)));
+  err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0x6 - sframe_vaddr), &frep);
+  TEST ("plt-findfre-1: Find second FRE in PLT4",
+	(err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x2));
 
   /* Find the last FRE in PLT4.  */
-  err = sframe_find_fre (dctx, (0x1000 + 16*3 + 0xc), &frep);
-  TEST("plt-findfre-1: Find last FRE in PLT4",
-       ((err == 0) && (sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3)));
+  err = sframe_find_fre (dctx, (plt_vaddr + 16*3 + 0xc - sframe_vaddr), &frep);
+  TEST ("plt-findfre-1: Find last FRE in PLT4",
+	(err == 0 && sframe_fre_get_cfa_offset (dctx, &frep, &err) == 0x3));
 
   sframe_encoder_free (&ectx);
   sframe_decoder_free (&dctx);
+}
 
-  return 0;
+int main (void)
+{
+  uint32_t sframe_vaddr = 0x402220;
+  uint32_t plt_vaddr = 0x401020;
+  printf ("Testing with plt_vaddr = %#x; sframe_vaddr = %#x\n", plt_vaddr,
+	  sframe_vaddr);
+  test_plt_findfre (plt_vaddr, sframe_vaddr);
+
+  sframe_vaddr = 0x401020;
+  plt_vaddr = 0x402220;
+  printf ("Testing with plt_vaddr = %#x; sframe_vaddr = %#x\n", plt_vaddr,
+	  sframe_vaddr);
+  test_plt_findfre (plt_vaddr, sframe_vaddr);
 }


More information about the Binutils-cvs mailing list