mirror of
https://github.com/libunwind/libunwind.git
synced 2026-01-12 00:04:03 +08:00
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:
committed by
Stephen M. Webb
parent
84607272d8
commit
7bc6cecda1
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user