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
This commit is contained in:
James Clark
2022-05-24 13:07:00 +00:00
committed by Stephen M. Webb
parent 7001a99f30
commit b8cf600dfc
3 changed files with 138 additions and 0 deletions

View File

@@ -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

View File

@@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if !defined(UNW_REMOTE_ONLY)
#include "Garm64-test-sve-signal.c"
#endif

View File

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