diff options
Diffstat (limited to 'debug')
-rw-r--r-- | debug/Makefile | 55 | ||||
-rw-r--r-- | debug/backtrace.c | 52 | ||||
-rw-r--r-- | debug/tst-backtrace1.c | 84 | ||||
-rw-r--r-- | debug/tst-sprintf-fortify-rdonly-static.c | 1 |
4 files changed, 187 insertions, 5 deletions
diff --git a/debug/Makefile b/debug/Makefile index 4020184..4f7ac04 100644 --- a/debug/Makefile +++ b/debug/Makefile @@ -184,12 +184,20 @@ CPPFLAGS-tst-chk-cancel.c += $(no-fortify-source) -D_FORTIFY_SOURCE=2 CFLAGS-tst-sprintf-fortify-rdonly.c += $(no-fortify-source) -D_FORTIFY_SOURCE=2 CFLAGS-tst-sprintf-fortify-rdonly-mod.c += $(no-fortify-source) -D_FORTIFY_SOURCE=2 CFLAGS-tst-sprintf-fortify-rdonly-dlopen.c += $(no-fortify-source) -D_FORTIFY_SOURCE=2 +CFLAGS-tst-sprintf-fortify-rdonly-static.c += $(no-fortify-source) -D_FORTIFY_SOURCE=2 CFLAGS-tst-fortify-syslog.c += $(no-fortify-source) -D_FORTIFY_SOURCE=2 CFLAGS-tst-fortify-wide.c += $(no-fortify-source) -D_FORTIFY_SOURCE=2 - -$(objpfx)tst-sprintf-fortify-rdonly: \ - $(objpfx)tst-sprintf-fortify-rdonly-mod.so \ - $(objpfx)tst-sprintf-fortify-rdonly-dlopen.so +LDFLAGS-tst-sprintf-fortify-rdonly-static += $(relro-LDFLAGS) + +$(objpfx)tst-sprintf-fortify-rdonly: $(objpfx)tst-sprintf-fortify-rdonly-mod.so +$(objpfx)tst-sprintf-fortify-rdonly.out: \ + $(objpfx)tst-sprintf-fortify-rdonly-dlopen.so +$(objpfx)tst-sprintf-fortify-rdonly-static: \ + $(objpfx)tst-sprintf-fortify-rdonly-dlopen.o +$(objpfx)tst-sprintf-fortify-rdonly-static.out: \ + $(objpfx)tst-sprintf-fortify-rdonly-dlopen.so +tst-sprintf-fortify-rdonly-static-ENV = \ + LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)/elf # _FORTIFY_SOURCE tests. # Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and @@ -278,6 +286,39 @@ 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-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)) +ifeq ($(run-built-tests),yes) +tests-special += $(tests-dw-unwind) +endif +endif + +define make-strip-rule +$(objpfx)$(word 1,$(subst :, ,$(1))): $(objpfx)$(word 2,$(subst :, ,$(1))) + $(STRIP) --remove-section=.sframe $$< -o $$@ +endef + +$(foreach pair,$(dw_unwind_pair),$(eval $(call make-strip-rule,$(pair)))) + +define make-run-rule +$(objpfx)$(word 1,$(subst :, ,$(1))).out: /dev/null $(objpfx)$(word 1,$(subst :, ,$(1))) + $$(make-test-out) > $$@; $$(evaluate-test) +endef + +$(foreach pair,$(dw_unwind_pair),$(eval $(call make-run-rule,$(pair)))) + CFLAGS-tst-ssp-1.c += -fstack-protector-all # Disable compiler optimizations around vsprintf (the function under test). @@ -289,6 +330,7 @@ tests = \ backtrace-tst \ test-stpcpy_chk \ test-strcpy_chk \ + tst-backtrace1 \ tst-backtrace2 \ tst-backtrace3 \ tst-backtrace4 \ @@ -300,9 +342,14 @@ tests = \ tst-longjmp_chk3 \ tst-realpath-chk \ tst-sprintf-fortify-rdonly \ + tst-sprintf-fortify-rdonly-static \ tst-sprintf-fortify-unchecked \ # tests +tests-static = \ + tst-sprintf-fortify-rdonly-static \ + # tests-static + tests-time64 += \ $(tests-all-time64-chk) \ # tests-time64 diff --git a/debug/backtrace.c b/debug/backtrace.c index 05cdc84..d563a04 100644 --- a/debug/backtrace.c +++ b/debug/backtrace.c @@ -20,6 +20,9 @@ #include <stdlib.h> #include <unwind.h> #include <unwind-link.h> +#if ENABLE_SFRAME +#include <sframe.h> +#endif struct trace_arg { @@ -30,6 +33,42 @@ 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 + one frame. If it doesn't, this could indicate a mixed + environment for example, glibc may have been compiled with SFrame + support, while the application was not. An even more complex + scenario arises when the application uses shared objects compiled + with differing configurations. + + Additionally, glibc includes certain callback paths that must be + considered. For example: an application calls shared object A, + which calls shared object B, which in turn calls qsort() in + glibc. qsort() then invokes a helper in shared object C, which + raises a SIGFPE signal, handled by object D, which requests a + backtrace. Any of these components may or may not include SFrame + encoding. + + In cases where a stack frame lacks SFrame information, the SFrame + backtracer can fall back to using the DWARF unwinder. + + This function must be always inline. Otherwise the + __builtin_frame_address and the __getXX helper functions will not + return the right addresses. */ + +static inline int __attribute__ ((always_inline)) +do_sframe_backtrace (void **array, int size) +{ + frame frame; + frame.pc = __getPC (); + frame.sp = __getSP (); + 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) { @@ -72,7 +111,18 @@ __backtrace (void **array, int size) .cnt = -1 }; - if (size <= 0 || arg.unwind_link == NULL) + 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) return 0; UNWIND_LINK_PTR (arg.unwind_link, _Unwind_Backtrace) diff --git a/debug/tst-backtrace1.c b/debug/tst-backtrace1.c new file mode 100644 index 0000000..01b8a0c --- /dev/null +++ b/debug/tst-backtrace1.c @@ -0,0 +1,84 @@ +/* Copyright (C) 2004-2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <execinfo.h> +#include <pthread.h> +#include <stdio.h> + +#define BT_SIZE 64 +void *bt_array[BT_SIZE]; +int bt_cnt; + +int +do_bt (void) +{ + bt_cnt = backtrace (bt_array, BT_SIZE); + return 56; +} + +int +call_do_bt (void) +{ + return do_bt () + 1; +} + +void * +tf (void *arg) +{ + if (call_do_bt () != 57) + return (void *) 1L; + return NULL; +} + +int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL)) + { + puts ("create failed"); + return 1; + } + + void *res; + if (pthread_join (th, &res)) + { + puts ("join failed"); + return 1; + } + + if (res != NULL) + { + puts ("thread failed"); + return 1; + } + + char **text = backtrace_symbols (bt_array, bt_cnt); + if (text == NULL) + { + puts ("backtrace_symbols failed"); + return 1; + } + + for (int i = 0; i < bt_cnt; ++i) + puts (text[i]); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/debug/tst-sprintf-fortify-rdonly-static.c b/debug/tst-sprintf-fortify-rdonly-static.c new file mode 100644 index 0000000..ca5bbd5 --- /dev/null +++ b/debug/tst-sprintf-fortify-rdonly-static.c @@ -0,0 +1 @@ +#include "tst-sprintf-fortify-rdonly.c" |