aboutsummaryrefslogtreecommitdiff
path: root/debug
diff options
context:
space:
mode:
Diffstat (limited to 'debug')
-rw-r--r--debug/Makefile55
-rw-r--r--debug/backtrace.c52
-rw-r--r--debug/tst-backtrace1.c84
-rw-r--r--debug/tst-sprintf-fortify-rdonly-static.c1
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"