From b8cf600dfc862a94959a3f43bfcbb797ae6d8dfa Mon Sep 17 00:00:00 2001 From: James Clark Date: Tue, 24 May 2022 13:07:00 +0000 Subject: 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 Signed-off-by: James Clark Change-Id: Ibe38e6b0fa26276c545f044ffdd26fbdb2789c38 --- tests/Garm64-test-sve-signal.c | 121 +++++++++++++++++++++++++++++++++++++++++ tests/Larm64-test-sve-signal.c | 5 ++ tests/Makefile.am | 12 ++++ 3 files changed, 138 insertions(+) create mode 100644 tests/Garm64-test-sve-signal.c create mode 100644 tests/Larm64-test-sve-signal.c 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 +#include +#include +#include +#include +#include +#include +#include + +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 +#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) -- cgit v1.2.1