[RFC,3/5] configure: Add --enable-sframe option

Message ID 20250318130333.18829-4-claudiu.zissulescu-ianculescu@oracle.com (mailing list archive)
State New
Headers
Series glibc: Add SFrame support for stack backtracking |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch fail Patch failed to apply to master at the time it was sent

Commit Message

Claudiu Zissulescu-Ianculescu March 18, 2025, 1:03 p.m. UTC
  From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>

Enable SFrame stack track information. The --enable-sframe option
allows the glibc build to compile with SFrame stack track
information. Thus, enabling glibc's backtrace to work within glibc.

Signed-off-by: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
---
 Makeconfig     |   8 +++-
 config.make.in |   1 +
 configure      | 128 +++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac   |  43 +++++++++++++++++
 4 files changed, 179 insertions(+), 1 deletion(-)
  

Comments

Joseph Myers March 18, 2025, 4:27 p.m. UTC | #1
On Tue, 18 Mar 2025, claudiu.zissulescu-ianculescu@oracle.com wrote:

> Enable SFrame stack track information. The --enable-sframe option
> allows the glibc build to compile with SFrame stack track
> information. Thus, enabling glibc's backtrace to work within glibc.

A new configure option should be documented in install.texi (with INSTALL 
regenerated).
  
Jens Remus March 19, 2025, 3:51 p.m. UTC | #2
On 18.03.2025 14:03, claudiu.zissulescu-ianculescu@oracle.com wrote:

> Enable SFrame stack track information. The --enable-sframe option
> allows the glibc build to compile with SFrame stack track
> information. Thus, enabling glibc's backtrace to work within glibc.

I am not familiar with this part of Glibc.  Should Glibc by itself
determine to be built by default with SFrame stack trace information,
if the toolchain supports it, unless it is configured with
--disable-sframe, or should distributors control this via CFLAGS, e.g.
their distribution default rpmbuild macros?

Thanks and regards,
Jens
  
Claudiu Zissulescu-Ianculescu March 25, 2025, 10:50 a.m. UTC | #3
Hi Joseph,

Thank you for all your input. I'll try to address all the concerns in my
second attempt,

Claudiu

On 3/18/25 6:27 PM, Joseph Myers wrote:
> On Tue, 18 Mar 2025, claudiu.zissulescu-ianculescu@oracle.com wrote:
> 
>> Enable SFrame stack track information. The --enable-sframe option
>> allows the glibc build to compile with SFrame stack track
>> information. Thus, enabling glibc's backtrace to work within glibc.
> 
> A new configure option should be documented in install.texi (with INSTALL 
> regenerated).
>
  
Claudiu Zissulescu-Ianculescu March 25, 2025, 11:27 a.m. UTC | #4
On 3/19/25 5:51 PM, Jens Remus wrote:
> On 18.03.2025 14:03, claudiu.zissulescu-ianculescu@oracle.com wrote:
> 
>> Enable SFrame stack track information. The --enable-sframe option
>> allows the glibc build to compile with SFrame stack track
>> information. Thus, enabling glibc's backtrace to work within glibc.
> 
> I am not familiar with this part of Glibc.  Should Glibc by itself
> determine to be built by default with SFrame stack trace information,
> if the toolchain supports it, unless it is configured with
> --disable-sframe, or should distributors control this via CFLAGS, e.g.
> their distribution default rpmbuild macros?

That is my understanding, if a new feature is added, that one is enabled
by default unless specified. But the maintainers will correct me :)
  

Patch

diff --git a/Makeconfig b/Makeconfig
index a87ff7b1d3..7d360f7daf 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -1011,6 +1011,12 @@  else
 +cflags += $(no-fortify-source)
 endif
 
+# Enable SFrame while compiling for stack backtracing.
+ifeq ($(enable-gsframe),yes)
+as-sframe = -Wa,--gsframe
+endif
++cflags += $(as-sframe)
+
 # Each sysdeps directory can contain header files that both will be
 # used to compile and will be installed.  Each can also contain an
 # include/ subdirectory, whose header files will be used to compile
@@ -1158,7 +1164,7 @@  endif
 ifndef ASFLAGS
 ASFLAGS := $(filter -g% -fdebug-prefix-map=%,$(CFLAGS))
 endif
-override ASFLAGS += -Werror=undef $(ASFLAGS-config) $(asflags-cpu)
+override ASFLAGS += -Werror=undef $(ASFLAGS-config) $(asflags-cpu) $(as-sframe)
 
 ifndef BUILD_CC
 BUILD_CC = $(CC)
diff --git a/config.make.in b/config.make.in
index 36096881b7..db2367f007 100644
--- a/config.make.in
+++ b/config.make.in
@@ -51,6 +51,7 @@  c++-cstdlib-header = @CXX_CSTDLIB_HEADER@
 c++-cmath-header = @CXX_CMATH_HEADER@
 c++-bits-std_abs-h = @CXX_BITS_STD_ABS_H@
 enable-werror = @enable_werror@
+enable-gsframe = @enable_gsframe@
 
 have-z-execstack = @libc_cv_z_execstack@
 have-protected-data = @libc_cv_protected_data@
diff --git a/configure b/configure
index ec0b62db36..7908121794 100755
--- a/configure
+++ b/configure
@@ -620,6 +620,8 @@  DEFINES
 static_nss
 profile
 libc_cv_multidir
+enable_gsframe
+READELF_SFRAME
 shared
 static
 ldd_rewrite_script
@@ -808,6 +810,7 @@  enable_mathvec
 enable_cet
 enable_scv
 enable_fortify_source
+enable_sframe
 with_cpu
 '
       ac_precious_vars='build_alias
@@ -1491,6 +1494,8 @@  Optional Features:
                           Use -D_FORTIFY_SOURCE=[1|2|3] to control code
                           hardening, defaults to highest possible value
                           supported by the build compiler.
+  --enable-sframe         Enable SFrame stack trace information [default
+                          depends on toolchain]
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -4855,6 +4860,16 @@  case "$enable_fortify_source" in
 *) as_fn_error $? "Not a valid argument for --enable-fortify-source: \"$enable_fortify_source\"" "$LINENO" 5;;
 esac
 
+# Check whether --enable-sframe was given.
+if test ${enable_sframe+y}
+then :
+  enableval=$enable_sframe; use_sframe=$enableval
+else case e in #(
+  e) use_sframe=notset ;;
+esac
+fi
+
+
 # We keep the original values in `$config_*' and never modify them, so we
 # can write them unchanged into config.make.  Everything else uses
 # $machine, $vendor, and $os, and changes them whenever convenient.
@@ -8110,6 +8125,119 @@  fi
 config_vars="$config_vars
 enable-static-pie = $libc_cv_static_pie"
 
+# Glibc stacktracer supports SFrame v2 or newer
+libc_cv_readelf_version_ok=yes
+for ac_prog in $READELF
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_READELF_SFRAME+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) if test -n "$READELF_SFRAME"; then
+  ac_cv_prog_READELF_SFRAME="$READELF_SFRAME" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  case $as_dir in #(((
+    '') as_dir=./ ;;
+    */) ;;
+    *) as_dir=$as_dir/ ;;
+  esac
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+    ac_cv_prog_READELF_SFRAME="$ac_prog"
+    printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi ;;
+esac
+fi
+READELF_SFRAME=$ac_cv_prog_READELF_SFRAME
+if test -n "$READELF_SFRAME"; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $READELF_SFRAME" >&5
+printf "%s\n" "$READELF_SFRAME" >&6; }
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+  test -n "$READELF_SFRAME" && break
+done
+
+if test -z "$READELF_SFRAME"; then
+  ac_verc_fail=yes
+else
+  # Found it, now check the version.
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking version of $READELF_SFRAME" >&5
+printf %s "checking version of $READELF_SFRAME... " >&6; }
+  ac_prog_version=`$READELF_SFRAME --version 2>&1 | sed -n 's/^.*GNU readelf.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    2.4[1-9]*|2.[5-9][0-9]*|[3-9].*|[1-9][0-9]*)
+       ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+    *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+
+  esac
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_prog_version" >&5
+printf "%s\n" "$ac_prog_version" >&6; }
+fi
+if test $ac_verc_fail = yes; then
+  libc_cv_readelf_version_ok=no
+fi
+
+
+# Check the current toolchain for SFrame support
+if test $libc_cv_readelf_version_ok = yes; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SFrame support" >&5
+printf %s "checking for SFrame support... " >&6; }
+if test ${libc_cv_default_sframe+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) cat > conftest.c <<EOF
+int test_function(void)
+{
+  return 42;
+}
+EOF
+  libc_cv_default_sframe=no
+  if ${CC} -c conftest.c -o conftest.o -Wa,--gsframe >/dev/null 2>&1 && \
+     # Check if .sframe section is present and if version > 1
+     $READELF --sframe conftest.o | grep "SFRAME_VER" | grep -qv "VERSION_1"; then
+          libc_cv_default_sframe=yes
+  fi
+  rm -f conftest.c conftest.o
+   ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_default_sframe" >&5
+printf "%s\n" "$libc_cv_default_sframe" >&6; }
+fi
+
+# Prevent enabling sframe on non-supporting toolchains
+enable_gsframe=no
+if test $use_sframe$libc_cv_default_sframe = yesyes || \
+   test $use_sframe$libc_cv_default_sframe = notsetyes; then
+  enable_gsframe=yes
+elif test $use_sframe = yes; then
+   { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
+as_fn_error $? "toolchain doesn't support SFrame V2 or higher
+See 'config.log' for more details" "$LINENO" 5; }
+fi
+
+
 # Set the `multidir' variable by grabbing the variable from the compiler.
 # We do it once and save the result in a generated makefile.
 libc_cv_multidir=`${CC-cc} $CFLAGS $CPPFLAGS -print-multi-directory`
diff --git a/configure.ac b/configure.ac
index 7c9b57789e..2d8c1be411 100644
--- a/configure.ac
+++ b/configure.ac
@@ -426,6 +426,12 @@  case "$enable_fortify_source" in
 *) AC_MSG_ERROR([Not a valid argument for --enable-fortify-source: "$enable_fortify_source"]);;
 esac
 
+AC_ARG_ENABLE([sframe],
+	      [AS_HELP_STRING([--enable-sframe],
+			     [Enable SFrame stack trace information @<:@default depends on toolchain@:>@])],
+	      [use_sframe=$enableval],
+	      [use_sframe=notset])
+
 # We keep the original values in `$config_*' and never modify them, so we
 # can write them unchanged into config.make.  Everything else uses
 # $machine, $vendor, and $os, and changes them whenever convenient.
@@ -1776,6 +1782,43 @@  if test "$libc_cv_static_pie" = "yes"; then
 fi
 LIBC_CONFIG_VAR([enable-static-pie], [$libc_cv_static_pie])
 
+# Glibc stacktracer supports SFrame v2 or newer
+libc_cv_readelf_version_ok=yes
+AC_CHECK_PROG_VER(READELF_SFRAME, $READELF, --version,
+  [GNU readelf.* \([0-9][0-9]*\.[0-9.]*\)],
+  [2.4[1-9]*|2.[5-9][0-9]*|[3-9].*|[1-9][0-9]*],
+  libc_cv_readelf_version_ok=no)
+
+# Check the current toolchain for SFrame support
+if test $libc_cv_readelf_version_ok = yes; then
+  AC_CACHE_CHECK([for SFrame support], libc_cv_default_sframe,
+  [dnl
+cat > conftest.c <<EOF
+int test_function(void)
+{
+  return 42;
+}
+EOF
+  libc_cv_default_sframe=no
+  if ${CC} -c conftest.c -o conftest.o -Wa,--gsframe >/dev/null 2>&1 && \
+     # Check if .sframe section is present and if version > 1
+     $READELF --sframe conftest.o | grep "SFRAME_VER" | grep -qv "VERSION_1"; then
+          libc_cv_default_sframe=yes
+  fi
+  rm -f conftest.c conftest.o
+  ])
+fi
+
+# Prevent enabling sframe on non-supporting toolchains
+enable_gsframe=no
+if test $use_sframe$libc_cv_default_sframe = yesyes || \
+   test $use_sframe$libc_cv_default_sframe = notsetyes; then
+  enable_gsframe=yes
+elif test $use_sframe = yes; then
+   AC_MSG_FAILURE([toolchain doesn't support SFrame V2 or higher])
+fi
+AC_SUBST(enable_gsframe)
+
 # Set the `multidir' variable by grabbing the variable from the compiler.
 # We do it once and save the result in a generated makefile.
 libc_cv_multidir=`${CC-cc} $CFLAGS $CPPFLAGS -print-multi-directory`