Fix some QNX test failures due to syscall name

Two tests were failing on QNX because they hard-code the syscall
function name for raising a signal and the hard-coded function name is
wrong for QNX OS.

Ran the relevant test code through clang-format and fixed additional
issues with Aarch64 scalable vector extension (SVE) on QNX.
This commit is contained in:
Stephen Webb
2025-08-07 11:25:06 -04:00
committed by Stephen M. Webb
parent 84607272d8
commit 7bc6cecda1
3 changed files with 238 additions and 144 deletions

View File

@@ -108,6 +108,10 @@ tdep_access_reg (struct cursor *c, unw_regnum_t reg, unw_word_t *valp,
unw_accessors_t *a = unw_get_accessors_int (as);
void *arg = c->dwarf.as_arg;
unw_word_t addr = DWARF_GET_LOC (c->dwarf.loc[reg]);
if (addr == 0)
{
return -1;
}
uint16_t val16;
/*

View File

@@ -1,140 +1,215 @@
/*
/**
* @file tests/Garm64-test-sve-signal.c
*
* Verify that unwinding from a signal handler works when variable width
* SVE registers are pushed onto the stack
* SVE registers are pushed onto the stack.
*
* Requires that both libunwind is built with SVE support enabled (that is, the
* compiler supports `-march=armv8-a+sve` and that this test is being run on an
* OS with SVE support enabled (which requires both hardware support and OS
* support).
*/
/*
* This file is part of libunwind.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "unw_test.h"
#include <stdio.h>
#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 <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
# include <arm_sve.h>
# include <signal.h>
# include <stdbool.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <unistd.h>
#if defined(__linux__)
#include <sys/auxv.h>
#endif
# include "libunwind.h"
# define UNW_TEST_SIGNAL_FRAME "signal_frame"
# if defined(__linux__)
# include <sys/auxv.h>
# define UNW_TEST_KILL_SYSCALL "kill"
/**
* Probe for SVE support in the host Linux kernel.
*/
bool
sve_is_enabled (void)
{
return (getauxval (AT_HWCAP) & HWCAP_SVE) ? true : false;
}
# elif defined(__QNX__)
# include <sys/syspage.h>
# define UNW_TEST_KILL_SYSCALL "SignalKill"
/**
* Probe for SVE support in the host QNX OS kernel.
*/
bool
sve_is_enabled (void)
{
return SYSPAGE_ENTRY (cpuinfo)->flags & AARCH64_CPU_FLAG_SVE;
}
# else
# define UNW_TEST_KILL_SYSCALL "kill"
/**
* Assume there is no SVE suppoirt in the host kernel.
*/
bool
sve_is_enabled (void)
{
return false;
}
# endif
bool verbose = false;
int64_t z[100];
void signal_handler(int signum)
void
signal_handler (int signum)
{
unw_cursor_t cursor;
unw_cursor_t cursor;
unw_context_t context;
const char* expected[] = {
"signal_frame",
"kill",
"sum",
"square",
"main",
const char * expected[] = {
UNW_TEST_SIGNAL_FRAME, UNW_TEST_KILL_SYSCALL, "sum", "square", "main",
};
unw_getcontext(&context);
unw_init_local(&cursor, &context);
unw_getcontext (&context);
unw_init_local (&cursor, &context);
for (unsigned int depth = 0; depth < sizeof(expected) / sizeof(expected[0]); ++depth)
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_word_t pc;
int unw_rc = unw_step (&cursor);
if (unw_rc <= 0)
{
fprintf (stderr, "Frame: %d unw_step error: %d\n", depth, unw_rc);
exit (UNW_TEST_EXIT_FAIL);
}
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);
}
unw_rc = unw_get_reg (&cursor, UNW_REG_IP, &pc);
if (pc == 0 || unw_rc != 0)
{
fprintf (stderr, "Frame: %d unw_get_reg error: %d\n", depth, unw_rc);
exit (UNW_TEST_EXIT_FAIL);
}
char sym[256];
unw_rc = unw_is_signal_frame(&cursor);
unw_rc = unw_is_signal_frame (&cursor);
if (unw_rc > 0)
{
strcpy(sym, "signal_frame");
strcpy (sym, UNW_TEST_SIGNAL_FRAME);
}
else if (unw_rc < 0)
{
printf("Frame: %d unw_is_signal_frame error: %d\n", depth, unw_rc);
exit(-1);
fprintf (stderr, "Frame: %d unw_is_signal_frame error: %d\n", depth, unw_rc);
exit (UNW_TEST_EXIT_FAIL);
}
else
{
unw_rc = unw_get_proc_name(&cursor, sym, sizeof(sym), &offset);
unw_word_t offset;
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);
fprintf (stderr, "Frame: %d unw_get_proc_name error: %d\n", depth, unw_rc);
exit (UNW_TEST_EXIT_FAIL);
}
}
if (verbose)
fprintf (stdout, " IP=%#010lx \"%s\"\n", (unsigned long)pc, sym);
if (strcmp(sym, expected[depth]) != 0)
if (strcmp (sym, expected[depth]) != 0)
{
printf("Frame: %d expected %s but found %s\n", depth, expected[depth], sym);
exit(-1);
fprintf (stderr, "Frame: %d expected %s but found %s\n", depth, expected[depth], sym);
exit (UNW_TEST_EXIT_FAIL);
}
}
exit(0); /* PASS */
exit (UNW_TEST_EXIT_PASS);
}
int64_t sum(svint64_t z0)
int64_t
sum (svint64_t z0)
{
int64_t ret = svaddv_s64(svptrue_b64(), z0);
int64_t ret = svaddv_s64 (svptrue_b64 (), z0);
kill (getpid (), SIGUSR1);
return ret;
}
int64_t square(svint64_t z0)
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);
z0 = svmul_s64_z (svptrue_b64 (), z0, z0);
res += sum (z0);
}
return res;
}
bool has_sve(void) {
#if defined(__linux__)
return (getauxval(AT_HWCAP) & HWCAP_SVE) ? true : false;
#else
printf("Cannot determine if SVE is present, assuming it is not\n");
return false;
#endif
}
int main()
int
main (int argc, char *argv[])
{
if (!has_sve()) {
printf("SVE not available, skipping\n");
return 77;
}
verbose = (argc > 1);
if (!sve_is_enabled ())
{
fprintf (stderr, "SVE is not enabled: skip\n");
return UNW_TEST_EXIT_SKIP;
}
signal(SIGUSR1, signal_handler);
for (unsigned int i = 0; i < sizeof(z) / sizeof(z[0]); ++i)
z[i] = rand();
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);
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;
fprintf (stderr, "Signal handler wasn't called\n");
return UNW_TEST_EXIT_HARD_ERROR;
}
#else /* !__ARM_FEATURE_SVE */
int
main ()
main (int argc, char *argv[])
{
return 77; /* SKIP */
int verbose = (argc > 1);
if (verbose)
fprintf (stdout, "SVE is not enabled: skip\n");
return UNW_TEST_EXIT_SKIP;
}
#endif

View File

@@ -1,92 +1,106 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2019 Brock York <twunknown AT gmail.com>
/**
* @file tests/Garm64-test-sve-signal.c
*
* Verify proper unwind functionality through a bad function pointer.
*
* It's not cleaqr why this test is specific to x86_64 hosts.
*/
/*
* This file is part of libunwind.
* Copyright (C) 2019 Brock York <twunknown AT gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "unw_test.h"
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <ucontext.h>
#include <unistd.h>
#include <sys/types.h>
#ifdef HAVE_SYS_PTRACE_H
#include <sys/ptrace.h>
# include <sys/ptrace.h>
#endif
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include "compiler.h"
#include "libunwind.h"
bool verbose = false;
/*
* unwind in the signal handler checking the backtrace is correct
* after a bad jump.
*/
void handle_sigsegv(int signal UNUSED, siginfo_t *info UNUSED, void *ucontext UNUSED)
void
handle_sigsegv (int signal UNUSED, siginfo_t *info UNUSED, void *ucontext UNUSED)
{
/*
* 0 = success
* !0 = general failure
* 77 = test skipped
* 99 = complete failure
*/
int test_status = 0;
unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp, offset;
char name[1000];
int found_signal_frame = 0;
int i = 0;
char *names[] = {
#if defined __FreeBSD__
int test_status = UNW_TEST_EXIT_PASS;
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip, sp, offset;
char name[1000];
int found_signal_frame = 0;
int i = 0;
char * names[] = {
#if defined(__FreeBSD__)
"",
#elif defined(__QNX__) && __QNX__ >= 800
"__signalstub",
#endif
"",
"main",
};
int names_count = sizeof(names) / sizeof(*names);
int names_count = sizeof (names) / sizeof (*names);
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unw_getcontext (&uc);
unw_init_local (&cursor, &uc);
while (unw_step(&cursor) > 0 && !test_status)
while (unw_step (&cursor) > 0)
{
if (unw_is_signal_frame(&cursor))
if (unw_is_signal_frame (&cursor))
{
found_signal_frame = 1;
}
if (found_signal_frame)
{
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
memset(name, 0, sizeof(char) * 1000);
unw_get_proc_name(&cursor, name, sizeof(char) * 1000, &offset);
printf("ip = %lx, sp = %lx offset = %lx name = %s\n", (long) ip, (long) sp, (long) offset, name);
unw_get_reg (&cursor, UNW_REG_IP, &ip);
unw_get_reg (&cursor, UNW_REG_SP, &sp);
memset (name, 0, sizeof (char) * 1000);
unw_get_proc_name (&cursor, name, sizeof (char) * 1000, &offset);
if (verbose)
{
fprintf (stdout, "ip = %#010lx, sp = %#010lx offset = %#010lx name = %s\n",
(long)ip, (long)sp, (long)offset, name);
}
if (i < names_count)
{
if (strcmp(names[i], name) != 0)
if (strcmp (names[i], name) != 0)
{
test_status = 1;
printf("frame %s doesn't match expected frame %s\n", name, names[i]);
fprintf (stderr, "frame %d '%s' doesn't match expected frame '%s'\n", i, name, names[i]);
test_status = UNW_TEST_EXIT_FAIL;
}
else
{
@@ -96,32 +110,33 @@ void handle_sigsegv(int signal UNUSED, siginfo_t *info UNUSED, void *ucontext UN
}
}
if (i != names_count) //Make sure we found all the frames!
if (i != names_count) // Make sure we found all the frames!
{
printf("Failed to find all frames i:%d != names_count:%d\n", i, names_count);
test_status = 1;
fprintf (stderr, "Failed to find all frames i:%d != names_count:%d\n", i, names_count);
test_status = UNW_TEST_EXIT_FAIL;
}
/*return test_status to test harness*/
exit(test_status);
exit (test_status);
}
void (*invalid_function)() = (void*)1;
void (*invalid_function) () = (void *)1;
int main(int argc UNUSED, char *argv[] UNUSED)
int
main (int argc, char *argv[] UNUSED)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_sigsegv;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
verbose = (argc > 1);
invalid_function();
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_sigaction = handle_sigsegv;
sa.sa_flags = SA_SIGINFO;
sigaction (SIGSEGV, &sa, NULL);
invalid_function ();
/*
* 99 is the hard error exit status for automake tests:
* https://www.gnu.org/software/automake/manual/html_node/Scripts_002dbased-Testsuites.html#Scripts_002dbased-Testsuites
* If we dont end up in the signal handler something went horribly wrong.
*/
return 99;
return UNW_TEST_EXIT_HARD_ERROR;
}