From: Adhemerval Zanella Date: Wed, 23 Jul 2025 13:47:23 +0000 (-0300) Subject: Disable SFrame support by default X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a12d72019e09aa03e548fa803f9e766fc50d9861;p=thirdparty%2Fglibc.git Disable SFrame support by default And add extra checks to enable for binutils 2.45 and if the architecture explicitly enables it. When SFrame is disabled, all the related code is also not enabled for backtrace() and _dl_find_object(), so SFrame backtracking is not used even if the binary has the SFrame segment. This patch also adds some other related fixes: * Fixed an issue with AC_CHECK_PROG_VER, where the READELF_SFRAME usage prevented specifying a different readelf through READELF environment variable at configure time. * Add an extra arch-specific internal definition, libc_cv_support_sframe, to disable --enable-sframe on architectures that have binutils but not glibc support (s390x). * Renamed the tests without the .sframe segment and move the tst-backtrace1 from pthread to debug. * Use the built compiler strip to remove the .sframe segment, instead of the system one (which might not support SFrame). Checked on x86_64-linux-gnu and aarch64-linux-gnu. Reviewed-by: Sam James --- diff --git a/INSTALL b/INSTALL index cf60e1a380..0423b0c0c2 100644 --- a/INSTALL +++ b/INSTALL @@ -291,10 +291,11 @@ passed to 'configure'. For example: Default is to disable fortification. -'--disable-sframe' - By default, the GNU C Library is built with '-Wa,--gsframe' if the - current GNU 'binutils' supports it. You may want to use this - option if you don't plan to use SFrame stack tracer. +'--enable-sframe' + Experimental option supported by some architectures, where + the GNU C Library is built with '-Wa,--gsframe' if the binutils + supports it. This option also enables SFrame support for + backtrace. To build the library and related programs, type 'make'. This will produce a lot of output, some of which may look like errors from 'make' diff --git a/NEWS b/NEWS index 7c9ff07312..fdfae5edab 100644 --- a/NEWS +++ b/NEWS @@ -31,9 +31,10 @@ Major new features: glibc.malloc.tcache_max to a larger value (max 4194304). Tcache is also significantly faster for small sizes. -* New stack tracer using SFrame. Introducing --disable-sframe a new - configuration flag. Building glibc using sframe is automatically - enabled when the build system supports it. +* A new configure option, "--eanble-sframe", can be used to enable + the SFrame support on the GNU C Libraries. The SFrame is a new + stack trace information which can be used by backtrace. It requires + binutils with minimum version of 2.45. Deprecated and removed features, and other changes affecting compatibility: diff --git a/aclocal.m4 b/aclocal.m4 index e06366cdb2..21801429fb 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -145,6 +145,10 @@ if test -z "$NM"; then NM=`$CC -print-prog-name=nm` fi AC_SUBST(NM) +if test -z "$STRIP"; then + STRIP=`$CC -print-prog-name=strip` +fi +AC_SUBST(STRIP) ]) dnl Run a static link test with -nostdlib -nostartfiles. diff --git a/config.h.in b/config.h.in index 29126ea933..8b4077f578 100644 --- a/config.h.in +++ b/config.h.in @@ -287,6 +287,9 @@ /* Define if static PIE is enabled. */ #define ENABLE_STATIC_PIE 0 +/* Define if SFrame v2 is enabled. */ +#define ENABLE_SFRAME 0 + /* The default value of x86 CET control. */ #define DEFAULT_DL_X86_CET_CONTROL cet_elf_property diff --git a/config.make.in b/config.make.in index 382e003d87..fca75ab5d3 100644 --- a/config.make.in +++ b/config.make.in @@ -51,7 +51,6 @@ 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-no-error-execstack = @libc_cv_no_error_execstack@ @@ -114,6 +113,7 @@ OBJDUMP = @OBJDUMP@ OBJCOPY = @OBJCOPY@ GPROF = @GPROF@ READELF = @READELF@ +STRIP = @STRIP@ # Installation tools. INSTALL = @INSTALL@ diff --git a/configure b/configure index 6595d6be54..e8de94464c 100755 --- a/configure +++ b/configure @@ -620,8 +620,6 @@ DEFINES static_nss profile libc_cv_multidir -enable_gsframe -READELF_SFRAME libc_cv_test_x86_have_amx_tile test_enable_cet libc_cv_test_cc_mprefer_vector_width @@ -694,6 +692,7 @@ MAKEINFO MSGFMT MAKE LD +STRIP NM OBJDUMP READELF @@ -1510,8 +1509,7 @@ Optional Features: Use -D_FORTIFY_SOURCE=[1|2|3] to control code hardening, defaults to highest possible value supported by the build compiler. - --disable-sframe Disable building with SFrame stack trace information - [default=yes if GNU as is 2.41 or older] + --enable-sframe Enable building with SFrame support [default=no] Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -4895,7 +4893,7 @@ if test ${enable_sframe+y} then : enableval=$enable_sframe; use_sframe=$enableval else case e in #( - e) use_sframe=notset ;; + e) use_sframe=no ;; esac fi @@ -5142,6 +5140,10 @@ if test -z "$NM"; then NM=`$CC -print-prog-name=nm` fi +if test -z "$STRIP"; then + STRIP=`$CC -print-prog-name=strip` +fi + # Accept binutils 2.39 or newer. @@ -9356,21 +9358,30 @@ have-libgcc_s = $libc_cv_have_libgcc_s" -# Glibc stacktracer supports SFrame v2 or newer -libc_cv_readelf_version_ok=yes -# SFrame is supported from 2.41 or higher -for ac_prog in $READELF +enable_gsframe=no +if test $use_sframe = yes; then + # SFrame requires to be explicit enabled by the architecture + if test -z $libc_cv_support_sframe; 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 $? "the architecture doesn't support SFrame +See 'config.log' for more details" "$LINENO" 5; } + fi + + # SFrame requires binutils 2.45 or higher. + libc_cv_sframe_readelf_version=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} +if test ${ac_cv_prog_READELF+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. + e) if test -n "$READELF"; then + ac_cv_prog_READELF="$READELF" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH @@ -9383,7 +9394,7 @@ do 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" + ac_cv_prog_READELF="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi @@ -9394,29 +9405,29 @@ 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; } +READELF=$ac_cv_prog_READELF +if test -n "$READELF"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $READELF" >&5 +printf "%s\n" "$READELF" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi - test -n "$READELF_SFRAME" && break + test -n "$READELF" && break done -if test -z "$READELF_SFRAME"; then +if test -z "$READELF"; 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'` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking version of $READELF" >&5 +printf %s "checking version of $READELF... " >&6; } + ac_prog_version=`$READELF --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][0-9]*) + 2.4[5-9]*|2.[5-9][0-9]*|2.[1-9][0-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;; @@ -9425,12 +9436,17 @@ printf %s "checking version of $READELF_SFRAME... " >&6; } printf "%s\n" "$ac_prog_version" >&6; } fi if test $ac_verc_fail = yes; then - libc_cv_readelf_version_ok=no + libc_cv_sframe_readelf_version=no fi + if test $libc_cv_sframe_readelf_version == no; 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 $? "binutils too old to enable SFrame +See 'config.log' for more details" "$LINENO" 5; } + fi -# Check the current toolchain for SFrame support -if test $libc_cv_readelf_version_ok = yes; then + # Check if the current toolchain supports SFrame { 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} @@ -9443,32 +9459,32 @@ 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 + 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 + if test $libc_cv_default_sframe == no; 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 + fi + + enable_gsframe=yes + printf "%s\n" "#define ENABLE_SFRAME 1" >>confdefs.h +fi +config_vars="$config_vars +enable-gsframe = $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. diff --git a/configure.ac b/configure.ac index 25b80e34e4..fc01d054ba 100644 --- a/configure.ac +++ b/configure.ac @@ -441,10 +441,10 @@ case "$enable_fortify_source" in esac AC_ARG_ENABLE([sframe], - [AS_HELP_STRING([--disable-sframe], - [Disable building with SFrame stack trace information @<:@default=yes if GNU as is 2.41 or older@:>@])], + [AS_HELP_STRING([--enable-sframe], + [Enable building with SFrame support @<:@default=no@:>@])], [use_sframe=$enableval], - [use_sframe=notset]) + [use_sframe=no]) # We keep the original values in `$config_*' and never modify them, so we # can write them unchanged into config.make. Everything else uses @@ -2121,16 +2121,24 @@ AC_SUBST(libc_cv_test_cc_mprefer_vector_width) AC_SUBST(test_enable_cet) AC_SUBST(libc_cv_test_x86_have_amx_tile) -# Glibc stacktracer supports SFrame v2 or newer -libc_cv_readelf_version_ok=yes -# SFrame is supported from 2.41 or higher -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][0-9]*], - libc_cv_readelf_version_ok=no) +enable_gsframe=no +if test $use_sframe = yes; then + # SFrame requires to be explicit enabled by the architecture + if test -z $libc_cv_support_sframe; then + AC_MSG_FAILURE([the architecture doesn't support SFrame]) + fi -# Check the current toolchain for SFrame support -if test $libc_cv_readelf_version_ok = yes; then + # SFrame requires binutils 2.45 or higher. + libc_cv_sframe_readelf_version=yes + AC_CHECK_PROG_VER(READELF, $READELF, --version, + [GNU readelf.* \([0-9][0-9]*\.[0-9.]*\)], + [2.4[5-9]*|2.[5-9][0-9]*|2.[1-9][0-9][0-9]*|[3-9]*|[1-9][0-9]*], + libc_cv_sframe_readelf_version=no) + if test $libc_cv_sframe_readelf_version == no; then + AC_MSG_FAILURE([binutils too old to enable SFrame]) + fi + + # Check if the current toolchain supports SFrame AC_CACHE_CHECK([for SFrame support], libc_cv_default_sframe, [dnl cat > conftest.c </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 + 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 + if test $libc_cv_default_sframe == no; then + AC_MSG_FAILURE([toolchain doesn't support SFrame v2 or higher]) + fi + enable_gsframe=yes -elif test $use_sframe = yes; then - AC_MSG_FAILURE([toolchain doesn't support SFrame v2 or higher]) + AC_DEFINE(ENABLE_SFRAME) fi -AC_SUBST(enable_gsframe) +LIBC_CONFIG_VAR([enable-gsframe], [$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. diff --git a/debug/Makefile b/debug/Makefile index 6c857a56da..ab91d14af6 100644 --- a/debug/Makefile +++ b/debug/Makefile @@ -286,14 +286,17 @@ LDFLAGS-tst-backtrace4 = -rdynamic LDFLAGS-tst-backtrace5 = -rdynamic LDFLAGS-tst-backtrace6 = -rdynamic +$(objpfx)tst-backtrace1: $(shared-thread-library) + # When SFrame is enabled, make sure the dwarf unwinder is also exercised. ifeq ($(enable-gsframe),yes) dw_unwind_pair := \ - tst-backtrace7:tst-backtrace2 \ - tst-backtrace8:tst-backtrace3 \ - tst-backtrace9:tst-backtrace4 \ - tst-backtrace10:tst-backtrace5 \ - tst-backtrace11:tst-backtrace6 + tst-backtrace1-nosframe:tst-backtrace1 \ + tst-backtrace2-nosframe:tst-backtrace2 \ + tst-backtrace3-nosframe:tst-backtrace3 \ + tst-backtrace4-nosframe:tst-backtrace4 \ + tst-backtrace5-nosframe:tst-backtrace5 \ + tst-backtrace6-nosframe:tst-backtrace6 first_column = $(foreach pair,$(dw_unwind_pair),$(word 1,$(subst :, ,$(pair)))) tests-dw-unwind = $(patsubst %,$(objpfx)%.out,$(first_column)) @@ -302,7 +305,7 @@ endif define make-strip-rule $(objpfx)$(word 1,$(subst :, ,$(1))): $(objpfx)$(word 2,$(subst :, ,$(1))) - strip --remove-section=.sframe $$< -o $$@ + $(STRIP) --remove-section=.sframe $$< -o $$@ endef $(foreach pair,$(dw_unwind_pair),$(eval $(call make-strip-rule,$(pair)))) @@ -325,6 +328,7 @@ tests = \ backtrace-tst \ test-stpcpy_chk \ test-strcpy_chk \ + tst-backtrace1 \ tst-backtrace2 \ tst-backtrace3 \ tst-backtrace4 \ diff --git a/debug/backtrace.c b/debug/backtrace.c index 161999c17e..d563a04db5 100644 --- a/debug/backtrace.c +++ b/debug/backtrace.c @@ -20,7 +20,9 @@ #include #include #include +#if ENABLE_SFRAME #include +#endif struct trace_arg { @@ -31,6 +33,7 @@ struct trace_arg int size; }; +#if ENABLE_SFRAME /* Initialize the SFrame backtrace routine and attempt to backtrace the current stack using SFrame information. For the SFrame backtrace to be considered valid, the tracer must return more than @@ -64,6 +67,7 @@ do_sframe_backtrace (void **array, int size) frame.fp = (_Unwind_Ptr) __builtin_frame_address (0); return __stacktrace_sframe (array, size, &frame); } +#endif static _Unwind_Reason_Code backtrace_helper (struct _Unwind_Context *ctx, void *a) @@ -110,10 +114,12 @@ __backtrace (void **array, int size) if (size <= 0) return 0; +#if ENABLE_SFRAME /* Try first the SFrame backtracer. */ int cnt = do_sframe_backtrace (array, size); if (cnt > 1) return cnt; +#endif /* Try the dwarf unwinder. */ if (arg.unwind_link == NULL) diff --git a/sysdeps/pthread/tst-backtrace1.c b/debug/tst-backtrace1.c similarity index 100% rename from sysdeps/pthread/tst-backtrace1.c rename to debug/tst-backtrace1.c diff --git a/manual/install.texi b/manual/install.texi index 0c8d448362..77bec79d39 100644 --- a/manual/install.texi +++ b/manual/install.texi @@ -321,10 +321,13 @@ the build compiler. Default is to disable fortification. -@item --disable-sframe -By default, the GNU C Library is built with @option{-Wa,--gsframe} if -the current GNU @code{binutils} supports it. You may want to use this -option if you don't plan to use SFrame stack tracer. +@item --enable-sframe +Experimental option supported by some architectures, where @theglibc{} +is built with @option{-Wa,--gsframe} if @code{binutils} supports it. +Currently this is only supported on x86_64 and aarch64. The option +enables SFrame support on @code{backtrace}. + +Default is to disable SFrame support. @end table To build the library and related programs, type @code{make}. This will diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure index 26a0989a33..f364e65fe7 100755 --- a/sysdeps/aarch64/configure +++ b/sysdeps/aarch64/configure @@ -194,3 +194,5 @@ if test $build_mathvec = no; then printf "%s\n" "$as_me: WARNING: mathvec is disabled, this results in incomplete ABI." >&2;} fi +libc_cv_support_sframe=yes + diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac index 22fca8b565..a9a1b747f1 100644 --- a/sysdeps/aarch64/configure.ac +++ b/sysdeps/aarch64/configure.ac @@ -31,3 +31,5 @@ fi if test $build_mathvec = no; then AC_MSG_WARN([mathvec is disabled, this results in incomplete ABI.]) fi + +libc_cv_support_sframe=yes diff --git a/sysdeps/generic/Makefile b/sysdeps/generic/Makefile index c48e713eb3..1be63b74ce 100644 --- a/sysdeps/generic/Makefile +++ b/sysdeps/generic/Makefile @@ -21,7 +21,9 @@ CFLAGS-wordcopy.c += -Wno-uninitialized endif ifeq ($(subdir),elf) +ifeq ($(enable-gsframe),yes) sysdep_routines += sframe-read sframe +endif 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/pthread/Makefile b/sysdeps/pthread/Makefile index de146dddeb..7572f62cc0 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -62,7 +62,6 @@ tests += \ tst-abstime \ tst-atfork1 \ tst-attr1 \ - tst-backtrace1 \ tst-bad-schedattr \ tst-barrier1 \ tst-barrier2 \ diff --git a/sysdeps/x86_64/configure b/sysdeps/x86_64/configure index bbf520bfc9..32324f62da 100644 --- a/sysdeps/x86_64/configure +++ b/sysdeps/x86_64/configure @@ -289,6 +289,8 @@ fi config_vars="$config_vars have-x86-apx = $libc_cv_x86_have_apx" +libc_cv_support_sframe=yes + test -n "$critic_missing" && as_fn_error $? " *** $critic_missing" "$LINENO" 5 diff --git a/sysdeps/x86_64/configure.ac b/sysdeps/x86_64/configure.ac index 4a3f7f4541..a00958e219 100644 --- a/sysdeps/x86_64/configure.ac +++ b/sysdeps/x86_64/configure.ac @@ -104,5 +104,7 @@ if test $libc_cv_x86_have_apx = yes; then fi LIBC_CONFIG_VAR([have-x86-apx], [$libc_cv_x86_have_apx]) +libc_cv_support_sframe=yes + test -n "$critic_missing" && AC_MSG_ERROR([ *** $critic_missing])