summaryrefslogtreecommitdiff
path: root/tests/Garm64-test-sve-signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Garm64-test-sve-signal.c')
-rw-r--r--tests/Garm64-test-sve-signal.c121
1 files changed, 121 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