diff --git a/tools/testing/selftests/arm64/abi/ptrace.c b/tools/testing/selftests/arm64/abi/ptrace.c
index c83f0441e9d0..9e8494d950fe 100644
--- a/tools/testing/selftests/arm64/abi/ptrace.c
+++ b/tools/testing/selftests/arm64/abi/ptrace.c
@@ -18,15 +18,22 @@
 #include <asm/sigcontext.h>
 #include <asm/ptrace.h>
 
+#include "ptrace.h"
 #include "../../kselftest.h"
 
 #define EXPECTED_TESTS 11
 
 #define MAX_TPIDRS 2
 
-static bool have_sme(void)
+static int do_child(void)
 {
-	return getauxval(AT_HWCAP2) & HWCAP2_SME;
+	if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
+		ksft_exit_fail_perror("PTRACE_TRACEME");
+
+	if (raise(SIGSTOP))
+		ksft_exit_fail_perror("raise(SIGSTOP)");
+
+	return EXIT_SUCCESS;
 }
 
 static void test_tpidr(pid_t child)
@@ -132,119 +139,11 @@ static void test_tpidr(pid_t child)
 	}
 }
 
-static void test_hw_debug(pid_t child, int type, const char *type_name)
-{
-	struct user_hwdebug_state state;
-	struct iovec iov;
-	int slots, arch, ret;
-
-	iov.iov_len = sizeof(state);
-	iov.iov_base = &state;
-
-	/* Should be able to read the values */
-	ret = ptrace(PTRACE_GETREGSET, child, type, &iov);
-	ksft_test_result(ret == 0, "read_%s\n", type_name);
-
-	if (ret == 0) {
-		/* Low 8 bits is the number of slots, next 4 bits the arch */
-		slots = state.dbg_info & 0xff;
-		arch = (state.dbg_info >> 8) & 0xf;
-
-		ksft_print_msg("%s version %d with %d slots\n", type_name,
-			       arch, slots);
-
-		/* Zero is not currently architecturally valid */
-		ksft_test_result(arch, "%s_arch_set\n", type_name);
-	} else {
-		ksft_test_result_skip("%s_arch_set\n", type_name);
-	}
-}
-
-static int do_child(void)
-{
-	if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
-		ksft_exit_fail_perror("PTRACE_TRACEME");
-
-	if (raise(SIGSTOP))
-		ksft_exit_fail_perror("raise(SIGSTOP)");
-
-	return EXIT_SUCCESS;
-}
-
-static int do_parent(pid_t child)
+static void run_tests(pid_t child)
 {
-	int ret = EXIT_FAILURE;
-	pid_t pid;
-	int status;
-	siginfo_t si;
-
-	/* Attach to the child */
-	while (1) {
-		int sig;
-
-		pid = wait(&status);
-		if (pid == -1) {
-			perror("wait");
-			goto error;
-		}
-
-		/*
-		 * This should never happen but it's hard to flag in
-		 * the framework.
-		 */
-		if (pid != child)
-			continue;
-
-		if (WIFEXITED(status) || WIFSIGNALED(status))
-			ksft_exit_fail_msg("Child died unexpectedly\n");
-
-		if (!WIFSTOPPED(status))
-			goto error;
-
-		sig = WSTOPSIG(status);
-
-		if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
-			if (errno == ESRCH)
-				goto disappeared;
-
-			if (errno == EINVAL) {
-				sig = 0; /* bust group-stop */
-				goto cont;
-			}
-
-			ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
-					      strerror(errno));
-			goto error;
-		}
-
-		if (sig == SIGSTOP && si.si_code == SI_TKILL &&
-		    si.si_pid == pid)
-			break;
-
-	cont:
-		if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
-			if (errno == ESRCH)
-				goto disappeared;
-
-			ksft_test_result_fail("PTRACE_CONT: %s\n",
-					      strerror(errno));
-			goto error;
-		}
-	}
-
-	ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
-
 	test_tpidr(child);
 	test_hw_debug(child, NT_ARM_HW_WATCH, "NT_ARM_HW_WATCH");
 	test_hw_debug(child, NT_ARM_HW_BREAK, "NT_ARM_HW_BREAK");
-
-	ret = EXIT_SUCCESS;
-
-error:
-	kill(child, SIGKILL);
-
-disappeared:
-	return ret;
 }
 
 int main(void)
diff --git a/tools/testing/selftests/arm64/abi/ptrace.h b/tools/testing/selftests/arm64/abi/ptrace.h
new file mode 100644
index 000000000000..ae65c58cd3bf
--- /dev/null
+++ b/tools/testing/selftests/arm64/abi/ptrace.h
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 ARM Limited.
+ */
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <asm/sigcontext.h>
+#include <asm/ptrace.h>
+
+#include "../../kselftest.h"
+
+static void run_tests(pid_t child);
+
+static int do_child(void);
+
+#ifdef __aarch64__
+static bool have_sme(void)
+{
+	return getauxval(AT_HWCAP2) & HWCAP2_SME;
+}
+
+static void test_hw_debug(pid_t child, int type, const char *type_name)
+{
+	struct user_hwdebug_state state;
+	struct iovec iov;
+	int slots, arch, ret;
+
+	iov.iov_len = sizeof(state);
+	iov.iov_base = &state;
+
+	/* Should be able to read the values */
+	ret = ptrace(PTRACE_GETREGSET, child, type, &iov);
+	ksft_test_result(ret == 0, "read_%s\n", type_name);
+
+	if (ret == 0) {
+		/* Low 8 bits is the number of slots, next 4 bits the arch */
+		slots = state.dbg_info & 0xff;
+		arch = (state.dbg_info >> 8) & 0xf;
+
+		ksft_print_msg("%s version %d with %d slots\n", type_name,
+			       arch, slots);
+
+		/* Zero is not currently architecturally valid */
+		ksft_test_result(arch, "%s_arch_set\n", type_name);
+	} else {
+		ksft_test_result_skip("%s_arch_set\n", type_name);
+	}
+}
+#endif
+
+static int do_parent(pid_t child)
+{
+	int ret = EXIT_FAILURE;
+	pid_t pid;
+	int status;
+	siginfo_t si;
+
+	/* Attach to the child */
+	while (1) {
+		int sig;
+
+		pid = wait(&status);
+		if (pid == -1) {
+			perror("wait");
+			goto error;
+		}
+
+		/*
+		 * This should never happen but it's hard to flag in
+		 * the framework.
+		 */
+		if (pid != child)
+			continue;
+
+		if (WIFEXITED(status) || WIFSIGNALED(status))
+			ksft_exit_fail_msg("Child died unexpectedly\n");
+
+		if (!WIFSTOPPED(status))
+			goto error;
+
+		sig = WSTOPSIG(status);
+
+		if (sig == SIGTRAP)
+			ksft_print_msg("Child received SIGTRAP\n");
+
+		if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
+			if (errno == ESRCH)
+				goto disappeared;
+
+			if (errno == EINVAL)
+				goto cont;
+
+			ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
+					      strerror(errno));
+			goto error;
+		}
+
+		if (sig == SIGSTOP && si.si_code == SI_TKILL &&
+		    si.si_pid == pid)
+			break;
+
+cont:
+		/* bust group-stop */
+		if (ptrace(PTRACE_CONT, pid, NULL, 0)) {
+			if (errno == ESRCH)
+				goto disappeared;
+
+			ksft_test_result_fail("PTRACE_CONT: %s\n",
+					      strerror(errno));
+			goto error;
+		}
+	}
+
+	ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
+
+	ret = EXIT_SUCCESS;
+	run_tests(child);
+
+error:
+	kill(child, SIGKILL);
+
+disappeared:
+	return ret;
+}
