summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Clark <james.clark@arm.com>2022-05-24 13:07:00 +0000
committerStephen M. Webb <stephen.webb@bregmasoft.ca>2022-11-07 20:00:42 -0500
commitb8cf600dfc862a94959a3f43bfcbb797ae6d8dfa (patch)
treed901ed4368d3d5492185562bc426de81e316c74d
parent7001a99f30b62dcfe4728dba7f9f6bc5da913077 (diff)
downloadlibunwind-b8cf600dfc862a94959a3f43bfcbb797ae6d8dfa.tar.gz
arm64: Add test for SVE unwinding from signal handler
The test is skipped if the compiler doesn't support SVE, otherwise it uses some SVE intrinsics across a few functions and then sends a signal to take a backtrace from the sum() function. Without the previous SVE changes, the unwinding fails at sum() and the stack looks like: -> signal_handler() -> kill() -> sum() With the changes the full stack to main can be unwound and the test passes: -> signal_handler() -> kill() -> sum() -> square() -> main() Currently this test will pass on a Graviton 3 instance on AWS and with gcc-10. Co-authored-by: Kent Cheung <Kent.Cheung@arm.com> Signed-off-by: James Clark <james.clark@arm.com> Change-Id: Ibe38e6b0fa26276c545f044ffdd26fbdb2789c38
-rw-r--r--tests/Garm64-test-sve-signal.c121
-rw-r--r--tests/Larm64-test-sve-signal.c5
-rw-r--r--tests/Makefile.am12
3 files changed, 138 insertions, 0 deletions
diff --git a/tests/Garm64-test-sve-signal.c b/tests/Garm64-test-sve-signal.c
new file mode 100644
index 00000000..52cb9ac6
--- /dev/null
+++ b/tests/Garm64-test-sve-signal.c
@@ -0,0 +1,121 @@
+/*
+ * Verify that unwinding from a signal handler works when variable width
+ * SVE registers are pushed onto the stack
+ */
+
+#if defined(__ARM_FEATURE_SVE) && defined(__ARM_FEATURE_SVE_VECTOR_OPERATORS)
+
+#include <arm_sve.h>
+#include <libunwind.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+int64_t z[100];
+
+void signal_handler(int signum)
+{
+ unw_cursor_t cursor;
+ unw_context_t context;
+
+ const char* expected[] = {
+ "signal_frame",
+ "kill",
+ "sum",
+ "square",
+ "main",
+ };
+
+ unw_getcontext(&context);
+ unw_init_local(&cursor, &context);
+
+ for (unsigned int depth = 0; depth < sizeof(expected) / sizeof(expected[0]); ++depth)
+ {
+ unw_word_t offset, pc;
+ int unw_rc = unw_step(&cursor);
+ if (unw_rc <= 0) {
+ printf("Frame: %d unw_step error: %d\n", depth, unw_rc);
+ exit(-1);
+ }
+
+ unw_rc = unw_get_reg(&cursor, UNW_REG_IP, &pc);
+ if (pc == 0 || unw_rc != 0) {
+ printf("Frame: %d unw_get_reg error: %d\n", depth, unw_rc);
+ exit(-1);
+ }
+
+ char sym[256];
+ unw_rc = unw_is_signal_frame(&cursor);
+ if (unw_rc > 0)
+ {
+ strcpy(sym, "signal_frame");
+ }
+ else if (unw_rc < 0)
+ {
+ printf("Frame: %d unw_is_signal_frame error: %d\n", depth, unw_rc);
+ exit(-1);
+ }
+ else
+ {
+ unw_rc = unw_get_proc_name(&cursor, sym, sizeof(sym), &offset);
+ if (unw_rc)
+ {
+ printf("Frame: %d unw_get_proc_name error: %d\n", depth, unw_rc);
+ exit(-1);
+ }
+ }
+
+ if (strcmp(sym, expected[depth]) != 0)
+ {
+ printf("Frame: %d expected %s but found %s\n", depth, expected[depth], sym);
+ exit(-1);
+ }
+ }
+
+ exit(0); /* PASS */
+}
+
+int64_t sum(svint64_t z0)
+{
+ int64_t ret = svaddv_s64(svptrue_b64(), z0);
+ kill (getpid (), SIGUSR1);
+ return ret;
+}
+
+int64_t square(svint64_t z0)
+{
+ int64_t res = 0;
+ for (int i = 0; i < 100; ++i)
+ {
+ z0 = svmul_s64_z(svptrue_b64(), z0, z0);
+ res += sum(z0);
+ }
+ return res;
+}
+
+int main()
+{
+ signal(SIGUSR1, signal_handler);
+ for (unsigned int i = 0; i < sizeof(z) / sizeof(z[0]); ++i)
+ z[i] = rand();
+
+ svint64_t z0 = svld1(svptrue_b64(), &z[0]);
+ square(z0);
+
+ /*
+ * Shouldn't get here, exit is called from signal handler
+ */
+ printf("Signal handler wasn't called\n");
+ return -1;
+}
+
+#else /* !__ARM_FEATURE_SVE */
+int
+main ()
+{
+ return 77; /* SKIP */
+}
+#endif
diff --git a/tests/Larm64-test-sve-signal.c b/tests/Larm64-test-sve-signal.c
new file mode 100644
index 00000000..f1358045
--- /dev/null
+++ b/tests/Larm64-test-sve-signal.c
@@ -0,0 +1,5 @@
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#if !defined(UNW_REMOTE_ONLY)
+#include "Garm64-test-sve-signal.c"
+#endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5576c4c0..2838c186 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -46,6 +46,11 @@ if ARCH_X86_64
endif #ARCH X86_64
endif #!ARCH_PPC64
endif #!ARCH_IA64
+
+if ARCH_AARCH64
+ check_PROGRAMS_arch += Garm64-test-sve-signal Larm64-test-sve-signal
+endif
+
check_PROGRAMS_cdep += Gtest-bt Ltest-bt Gtest-exc Ltest-exc \
Gtest-init Ltest-init \
Gtest-concurrent Ltest-concurrent \
@@ -161,6 +166,10 @@ Gx64_test_dwarf_expressions_SOURCES = Gx64-test-dwarf-expressions.c \
Lx64_test_dwarf_expressions_SOURCES = Lx64-test-dwarf-expressions.c \
x64-test-dwarf-expressions.S
+Garm64_test_sve_signal_SOURCES = Garm64-test-sve-signal.c
+Larm64_test_sve_signal_SOURCES = Larm64-test-sve-signal.c
+Garm64_test_sve_signal_CFLAGS = -fno-inline -march=native
+Larm64_test_sve_signal_CFLAGS = -fno-inline -march=native
Gtest_init_SOURCES = Gtest-init.cxx
Ltest_init_SOURCES = Ltest-init.cxx
@@ -261,3 +270,6 @@ ppc64_test_altivec_LDADD = $(LIBUNWIND)
Gx64_test_dwarf_expressions_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
Lx64_test_dwarf_expressions_LDADD = $(LIBUNWIND_local)
+
+Garm64_test_sve_signal_LDADD = $(LIBUNWIND) $(LIBUNWIND_local)
+Larm64_test_sve_signal_LDADD = $(LIBUNWIND_local)