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])