[PATCH v6 1/5] elf: Add SFrame support to _dl_find_object function

claudiu.zissulescu-ianculescu@oracle.com claudiu.zissulescu-ianculescu@oracle.com
Tue Jun 10 07:33:49 GMT 2025


From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>

The SFrame provides information to be able to do stack trace is now
well defined and implemented in Binutils 2.41.  The format simply
contains enough information to be able to do stack trace given a
program counter (PC) value, the stack pointer, and the frame pointer.
The SFrame information is stored in a .sframe ELF section, which is
loaded into its own PT_GNU_SFRAME segment. We consider for this support
SFrame version 2.

This patch adds the bits to _dl_find_object to recognize and store in
struct dl_find_object the necessary info about SFrame section.

Signed-off-by: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
---
 bits/dl_find_object.h             |  3 ++
 conform/data/dlfcn.h-data         |  3 ++
 dlfcn/dlfcn.h                     |  7 ++-
 elf/dl-find_object.h              | 80 +++++++++++++++++++++++++++----
 manual/dynlink.texi               | 25 +++++++++-
 sysdeps/arm/bits/dl_find_object.h |  1 +
 sysdeps/x86/bits/dl_find_object.h |  1 +
 7 files changed, 110 insertions(+), 10 deletions(-)

diff --git a/bits/dl_find_object.h b/bits/dl_find_object.h
index 84baf73623..4b6ef7cf2b 100644
--- a/bits/dl_find_object.h
+++ b/bits/dl_find_object.h
@@ -30,3 +30,6 @@
 
 /* The ELF segment which contains the exception handling data.  */
 #define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME
+
+/* The ELF segment which contains the SFrame data.  */
+#define DLFO_SFRAME_SEGMENT_TYPE PT_GNU_SFRAME
diff --git a/conform/data/dlfcn.h-data b/conform/data/dlfcn.h-data
index e85288933c..72956ee98b 100644
--- a/conform/data/dlfcn.h-data
+++ b/conform/data/dlfcn.h-data
@@ -11,4 +11,7 @@ function {char*} dlerror (void)
 
 allow *_t
 allow RTLD_*
+
+macro DLF_SFRAME
+
 #endif
diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
index 4c2bdf9b64..416ff85f02 100644
--- a/dlfcn/dlfcn.h
+++ b/dlfcn/dlfcn.h
@@ -217,7 +217,11 @@ struct dl_find_object
   int dlfo_eh_count;		/* Number of exception handling entries.  */
   unsigned int __dlfo_eh_count_pad;
 # endif
-  __extension__ unsigned long long int __dflo_reserved[7];
+  void *dlfo_sframe;		/* SFrame stack trace data of the object.  */
+#if __WORDSIZE == 32
+  unsigned int __dlfo_sframe_pad;
+#endif
+  __extension__ unsigned long long int __dflo_reserved[6];
 };
 
 /* If ADDRESS is found in an object, fill in *RESULT and return 0.
@@ -226,6 +230,7 @@ int _dl_find_object (void *__address, struct dl_find_object *__result) __THROW;
 
 #endif /* __USE_GNU */
 
+#define DLF_SFRAME      (1 << 0)   /* SFrame stack trace data is valid.  */
 
 __END_DECLS
 
diff --git a/elf/dl-find_object.h b/elf/dl-find_object.h
index e433ff8740..a42016b3c7 100644
--- a/elf/dl-find_object.h
+++ b/elf/dl-find_object.h
@@ -26,6 +26,25 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+
+/* Type used to handle 64bit flag bits into a 32bit machine.  */
+typedef union
+{
+  __extension__ unsigned long long int __value64;
+  struct
+  {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    unsigned int __low;
+    unsigned int __high;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+    unsigned int __high;
+    unsigned int __low;
+#else
+# error Cannot handle __BYTE_ORDER byte order
+#endif
+  } __value32;
+} __atomic_wide_var;
+
 /* Internal version of struct dl_find_object.  Does not include the
    (yet unused) flags member.  We need to make a copy of data also in
    struct link_map to support non-contiguous mappings, and to support
@@ -33,6 +52,7 @@
    transactions).  */
 struct dl_find_object_internal
 {
+  __atomic_wide_var flags;
   uintptr_t map_start;
   uintptr_t map_end;            /* Set to map_start by dlclose.  */
   struct link_map *map;         /* Set to NULL by dlclose.  */
@@ -43,6 +63,7 @@ struct dl_find_object_internal
 #if DLFO_STRUCT_HAS_EH_COUNT
   int eh_count;
 #endif
+  void *sframe;
 };
 
 /* Create a copy of *SOURCE in *COPY using relaxed MO loads and
@@ -51,6 +72,15 @@ static inline void
 _dl_find_object_internal_copy (const struct dl_find_object_internal *source,
                                struct dl_find_object_internal *copy)
 {
+#if __HAVE_64B_ATOMICS
+  atomic_store_relaxed (&copy->flags.__value64,
+                        atomic_load_relaxed (&source->flags.__value64));
+#else
+  atomic_store_relaxed (&copy->flags.__value32.__low,
+                        atomic_load_relaxed (&source->flags.__value32.__low));
+  atomic_store_relaxed (&copy->flags.__value32.__high,
+                        atomic_load_relaxed (&source->flags.__value32.__high));
+#endif
   atomic_store_relaxed (&copy->map_start,
                         atomic_load_relaxed (&source->map_start));
   atomic_store_relaxed (&copy->map_end,
@@ -67,13 +97,15 @@ _dl_find_object_internal_copy (const struct dl_find_object_internal *source,
   atomic_store_relaxed (&copy->eh_count,
                         atomic_load_relaxed (&source->eh_count));
 #endif
+  atomic_store_relaxed (&copy->sframe,
+                        atomic_load_relaxed (&source->sframe));
 }
 
 static inline void
 _dl_find_object_to_external (struct dl_find_object_internal *internal,
                              struct dl_find_object *external)
 {
-  external->dlfo_flags = 0;
+  external->dlfo_flags = internal->flags.__value64;
   external->dlfo_map_start = (void *) internal->map_start;
   external->dlfo_map_end = (void *) internal->map_end;
   external->dlfo_link_map = internal->map;
@@ -84,6 +116,7 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
 # if DLFO_STRUCT_HAS_EH_COUNT
   external->dlfo_eh_count = internal->eh_count;
 # endif
+  external->dlfo_sframe = internal->sframe;
 }
 
 /* Extract the object location data from a link map and writes it to
@@ -92,6 +125,13 @@ static void __attribute__ ((unused))
 _dl_find_object_from_map (struct link_map *l,
                           struct dl_find_object_internal *result)
 {
+  uint64_t read_seg = 0;
+#if __HAVE_64B_ATOMICS
+  atomic_store_relaxed (&result->flags.__value64, 0);
+#else
+  atomic_store_relaxed (&result->flags.__value32.__low, 0);
+  atomic_store_relaxed (&result->flags.__value32.__high, 0);
+#endif
   atomic_store_relaxed (&result->map_start, (uintptr_t) l->l_map_start);
   atomic_store_relaxed (&result->map_end, (uintptr_t) l->l_map_end);
   atomic_store_relaxed (&result->map, l);
@@ -100,23 +140,47 @@ _dl_find_object_from_map (struct link_map *l,
   atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
 #endif
 
+  /* Initialize object's exception handling segment and SFrame segment
+     data.  */
+  atomic_store_relaxed (&result->sframe, NULL);
+  atomic_store_relaxed (&result->eh_frame, NULL);
+#if DLFO_STRUCT_HAS_EH_COUNT
+  atomic_store_relaxed (&result->eh_count, 0);
+#endif
+
   for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
        ph < ph_end; ++ph)
-    if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
+    switch (ph->p_type)
       {
+      case DLFO_EH_SEGMENT_TYPE:
         atomic_store_relaxed (&result->eh_frame,
                               (void *) (ph->p_vaddr + l->l_addr));
 #if DLFO_STRUCT_HAS_EH_COUNT
         atomic_store_relaxed (&result->eh_count, ph->p_memsz / 8);
 #endif
-        return;
-      }
+        read_seg |= 1;
+        break;
 
-  /* Object has no exception handling segment.  */
-  atomic_store_relaxed (&result->eh_frame, NULL);
-#if DLFO_STRUCT_HAS_EH_COUNT
-  atomic_store_relaxed (&result->eh_count, 0);
+      case DLFO_SFRAME_SEGMENT_TYPE:
+        atomic_store_relaxed (&result->sframe,
+                              (void *) (ph->p_vaddr + l->l_addr));
+#if __HAVE_64B_ATOMICS
+        atomic_store_relaxed (&result->flags.__value64,
+			      atomic_load_relaxed (&result->flags.__value64)
+			      | DLF_SFRAME);
+#else
+        atomic_store_relaxed
+	  (&result->flags.__value32.__low,
+	   atomic_load_relaxed (&result->flags.__value32.__low)
+	   | DLF_SFRAME);
 #endif
+        read_seg |= 2;
+        /* Fall through.  */
+      default:
+        if (read_seg == 3)
+          return;
+        break;
+      }
 }
 
 /* Called by the dynamic linker to set up the data structures for the
diff --git a/manual/dynlink.texi b/manual/dynlink.texi
index 3a4864f146..0fe7ecb63f 100644
--- a/manual/dynlink.texi
+++ b/manual/dynlink.texi
@@ -545,7 +545,7 @@ result data to the caller.
 
 @table @code
 @item unsigned long long int dlfo_flags
-Currently unused and always 0.
+Bit zero signals if SFrame stack data is valid.
 
 @item void *dlfo_map_start
 The start address of the inspected mapping.  This information comes from
@@ -562,6 +562,10 @@ This member contains a pointer to the link map of the object.
 This member contains a pointer to the exception handling data of the
 object.  See @code{DLFO_EH_SEGMENT_TYPE} below.
 
+@item void *dlfo_sframe
+This member contains a pointer to the SFrame stack trace data of the
+object.  See @code{DLFO_SFRAME_SEGMENT_TYPE} below.
+
 @end table
 
 This structure is a GNU extension.
@@ -599,6 +603,25 @@ macro expands to the program header type for the unwinding data.
 This macro is a GNU extension.
 @end deftypevr
 
+@deftypevr Macro int DLFO_SFRAME_SEGMENT_TYPE
+@standards{GNU, dlfcn.h}
+On targets using SFrame stack tracer, this macro expands to
+@code{PT_GNU_SFRAME}.  This indicates that @code{dlfo_sframe} in
+@code{struct dl_find_object} points to the @code{PT_GNU_SFRAME}
+segment of the object.
+
+This macro is a GNU extension.
+@end deftypevr
+
+@deftypevr Macro int DLFO_STRUCT_HAS_SFRAME
+@standards{GNU, dlfcn.h}
+On most targets, this macro is defined as @code{0}.  If it is defined to
+@code{1}, @code{struct dl_find_object} contains an additional member
+@code{dlfo_sframe}.
+
+This macro is a GNU extension.
+@end deftypevr
+
 @deftypefun {int} _dl_find_object (void *@var{address}, struct dl_find_object *@var{result})
 @standards{GNU, dlfcn.h}
 @safety{@mtsafe{}@assafe{}@acsafe{}}
diff --git a/sysdeps/arm/bits/dl_find_object.h b/sysdeps/arm/bits/dl_find_object.h
index 6365a005f8..1d6805709e 100644
--- a/sysdeps/arm/bits/dl_find_object.h
+++ b/sysdeps/arm/bits/dl_find_object.h
@@ -23,3 +23,4 @@
 #define DLFO_STRUCT_HAS_EH_DBASE 0
 #define DLFO_STRUCT_HAS_EH_COUNT 1
 #define DLFO_EH_SEGMENT_TYPE PT_ARM_EXIDX
+#define DLFO_SFRAME_SEGMENT_TYPE PT_GNU_SFRAME
diff --git a/sysdeps/x86/bits/dl_find_object.h b/sysdeps/x86/bits/dl_find_object.h
index 61880365c7..f2e85008f2 100644
--- a/sysdeps/x86/bits/dl_find_object.h
+++ b/sysdeps/x86/bits/dl_find_object.h
@@ -27,3 +27,4 @@
 #endif
 #define DLFO_STRUCT_HAS_EH_COUNT 0
 #define DLFO_EH_SEGMENT_TYPE PT_GNU_EH_FRAME
+#define DLFO_SFRAME_SEGMENT_TYPE PT_GNU_SFRAME
-- 
2.49.0



More information about the Libc-alpha mailing list