@@ -1008,6 +1008,7 @@ endif
install-tests: all install-gtk
$(call QUIET_INSTALL, tests) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
+ $(INSTALL) tests/arm_unwind_pac.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) tests/pe-file.exe* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
@@ -66,6 +66,7 @@ perf-y += expand-cgroup.o
perf-y += perf-time-to-tsc.o
perf-y += dlfilter-test.o
perf-y += sigtrap.o
+perf-y += arm_unwind_pac.o
$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
$(call rule_mkdir)
new file mode 100644
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <subcmd/exec-cmd.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "pmu.h"
+#include "tests.h"
+#include "debug.h"
+
+#if defined(HAVE_LIBUNWIND_SUPPORT) && defined(__aarch64__)
+
+#define BUF_MAX 1024
+
+static bool test_command_exists(const char *cmd)
+{
+ char buf[BUF_MAX];
+
+ scnprintf(buf, BUF_MAX, "which %s", cmd);
+ return !system(buf);
+}
+
+static int run_dir(const char *d, const char *compiler, const char *compiler_argv)
+{
+ char buf[BUF_MAX];
+
+ if (!test_command_exists(compiler))
+ return TEST_SKIP;
+
+ scnprintf(buf, BUF_MAX, "%s/arm_unwind_pac.sh %s '%s'", d, compiler, compiler_argv);
+ return system(buf) ? TEST_FAIL : TEST_OK;
+}
+
+static int run(const char *compiler, const char *compiler_argv)
+{
+ struct stat st;
+ char exec_test_path[BUF_MAX];
+ char *exec_path;
+
+ /* Check development tree tests. */
+ if (!lstat("./tests", &st))
+ return run_dir("./tests", compiler, compiler_argv);
+
+ /* Otherwise, check installed path */
+ exec_path = get_argv_exec_path();
+ if (exec_path == NULL)
+ return -1;
+
+ snprintf(exec_test_path, BUF_MAX, "%s/tests", exec_path);
+ if (!lstat(exec_test_path, &st))
+ return run_dir(exec_test_path, compiler, compiler_argv);
+
+ return TEST_SKIP;
+}
+
+#define TEST_COMPILER(_test, compiler, args) \
+ static int test__##_test(struct test_suite *test __maybe_unused, \
+ int subtest __maybe_unused) \
+ { \
+ return run(compiler, args); \
+ }
+
+/*
+ * gcc compilers
+ */
+TEST_COMPILER(gcc8, "gcc-8", "-msign-return-address=all")
+TEST_COMPILER(gcc9, "gcc-9", "-mbranch-protection=pac-ret+leaf")
+TEST_COMPILER(gcc10, "gcc-10", "-mbranch-protection=pac-ret+leaf")
+TEST_COMPILER(gcc11, "gcc-11", "-mbranch-protection=pac-ret+leaf")
+TEST_COMPILER(gcc12, "gcc-12", "-mbranch-protection=pac-ret+leaf")
+
+/*
+ * clang compilers
+ */
+TEST_COMPILER(clang12, "clang-12", "-msign-return-address=all")
+TEST_COMPILER(clang13, "clang-13", "-msign-return-address=all")
+TEST_COMPILER(clang14, "clang-14", "-msign-return-address=all")
+
+static struct test_case pac_tests[] = {
+#define PAC_TEST_CASE(name, test) \
+ TEST_CASE_REASON(name, test, "not installed")
+
+ PAC_TEST_CASE("gcc-8", gcc8),
+ PAC_TEST_CASE("gcc-9", gcc9),
+ PAC_TEST_CASE("gcc-10", gcc10),
+ PAC_TEST_CASE("gcc-11", gcc11),
+ PAC_TEST_CASE("gcc-12", gcc12),
+
+ PAC_TEST_CASE("clang-12", clang12),
+ PAC_TEST_CASE("clang-13", clang13),
+ PAC_TEST_CASE("clang-14", clang14),
+
+#undef PAC_TEST_CASE
+ { .name = NULL, }
+};
+
+struct test_suite suite__arm_unwind_pac = {
+ .desc = "Arm64 unwinding with PAC support",
+ .test_cases = pac_tests,
+};
+
+#else // HAVE_LIBUNWIND_SUPPORT && __aarch64__
+
+static int test__arm_unwind_pac(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
+{
+ return TEST_SKIP;
+}
+
+DEFINE_SUITE("Arm64 unwinding with PAC support", arm_unwind_pac);
+
+#endif // HAVE_LIBUNWIND_SUPPORT && __aarch64__
new file mode 100755
@@ -0,0 +1,57 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+COMPILER_CMD="$1"
+COMPILER_ARG="$2 -g -fno-omit-frame-pointer -fno-inline"
+
+echo "COMPILER_CMD=$COMPILER_CMD"
+echo "COMPILER_ARG=$COMPILER_ARG"
+
+TMPDIR=$(mktemp -d /tmp/__perf_test.XXXXX)
+
+clean_up() {
+ rm -rf $TMPDIR
+}
+
+trap clean_up exit term int
+
+cat << EOF > $TMPDIR/program.c
+void bar(void) {
+ for(;;);
+}
+void foo(void) {
+ bar();
+}
+int main(void) {
+ foo();
+ return 0;
+}
+EOF
+
+$COMPILER_CMD $COMPILER_ARG $TMPDIR/program.c -o $TMPDIR/program
+
+perf record --call-graph=dwarf -e cycles//u -o $TMPDIR/perf-dwarf.data -- $TMPDIR/program &
+PID=$!
+sleep 1
+kill $PID
+wait $PID
+
+perf record --call-graph=fp -e cycles//u -o $TMPDIR/perf-fp.data -- $TMPDIR/program &
+PID=$!
+sleep 1
+kill $PID
+wait $PID
+
+perf report --symbols=bar -i $TMPDIR/perf-dwarf.data --stdio > $TMPDIR/report-dwarf
+perf report --symbols=bar -i $TMPDIR/perf-fp.data --stdio > $TMPDIR/report-fp
+
+set -e
+set -x
+
+grep "main" $TMPDIR/report-dwarf
+grep "foo" $TMPDIR/report-dwarf
+grep "bar" $TMPDIR/report-dwarf
+
+grep "main" $TMPDIR/report-fp
+grep "foo" $TMPDIR/report-fp
+grep "bar" $TMPDIR/report-fp
@@ -108,6 +108,7 @@ static struct test_suite *generic_tests[] = {
&suite__perf_time_to_tsc,
&suite__dlfilter,
&suite__sigtrap,
+ &suite__arm_unwind_pac,
NULL,
};
@@ -147,6 +147,7 @@ DECLARE_SUITE(expand_cgroup_events);
DECLARE_SUITE(perf_time_to_tsc);
DECLARE_SUITE(dlfilter);
DECLARE_SUITE(sigtrap);
+DECLARE_SUITE(arm_unwind_pac);
/*
* PowerPC and S390 do not support creation of instruction breakpoints using the