Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kselftest/arm64: Add test coverage for NT_ARM_TLS

In preparation for extending support for NT_ARM_TLS to cover additional
TPIDRs add some tests for the existing interface. Do this in a generic
ptrace test program to provide a place to collect additional tests in
the future.

Signed-off-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20220829154921.837871-2-broonie@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Mark Brown and committed by
Catalin Marinas
ecaf4d3f b90cb105

+167 -1
+1
tools/testing/selftests/arm64/abi/.gitignore
··· 1 + ptrace 1 2 syscall-abi 2 3 tpidr2
+1 -1
tools/testing/selftests/arm64/abi/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 # Copyright (C) 2021 ARM Limited 3 3 4 - TEST_GEN_PROGS := syscall-abi tpidr2 4 + TEST_GEN_PROGS := ptrace syscall-abi tpidr2 5 5 6 6 include ../../lib.mk 7 7
+165
tools/testing/selftests/arm64/abi/ptrace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2022 ARM Limited. 4 + */ 5 + #include <errno.h> 6 + #include <stdbool.h> 7 + #include <stddef.h> 8 + #include <stdio.h> 9 + #include <stdlib.h> 10 + #include <string.h> 11 + #include <unistd.h> 12 + #include <sys/auxv.h> 13 + #include <sys/prctl.h> 14 + #include <sys/ptrace.h> 15 + #include <sys/types.h> 16 + #include <sys/uio.h> 17 + #include <sys/wait.h> 18 + #include <asm/sigcontext.h> 19 + #include <asm/ptrace.h> 20 + 21 + #include "../../kselftest.h" 22 + 23 + #define EXPECTED_TESTS 3 24 + 25 + #define MAX_TPIDRS 1 26 + 27 + static bool have_sme(void) 28 + { 29 + return getauxval(AT_HWCAP2) & HWCAP2_SME; 30 + } 31 + 32 + static void test_tpidr(pid_t child) 33 + { 34 + uint64_t read_val[MAX_TPIDRS]; 35 + uint64_t write_val[MAX_TPIDRS]; 36 + struct iovec read_iov, write_iov; 37 + int ret; 38 + 39 + read_iov.iov_base = read_val; 40 + write_iov.iov_base = write_val; 41 + 42 + /* Should be able to read a single TPIDR... */ 43 + read_iov.iov_len = sizeof(uint64_t); 44 + ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_TLS, &read_iov); 45 + ksft_test_result(ret == 0, "read_tpidr_one\n"); 46 + 47 + /* ...write a new value.. */ 48 + write_iov.iov_len = sizeof(uint64_t); 49 + write_val[0] = read_val[0]++; 50 + ret = ptrace(PTRACE_SETREGSET, child, NT_ARM_TLS, &write_iov); 51 + ksft_test_result(ret == 0, "write_tpidr_one\n"); 52 + 53 + /* ...then read it back */ 54 + ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_TLS, &read_iov); 55 + ksft_test_result(ret == 0 && write_val[0] == read_val[0], 56 + "verify_tpidr_one\n"); 57 + } 58 + 59 + static int do_child(void) 60 + { 61 + if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) 62 + ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno)); 63 + 64 + if (raise(SIGSTOP)) 65 + ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno)); 66 + 67 + return EXIT_SUCCESS; 68 + } 69 + 70 + static int do_parent(pid_t child) 71 + { 72 + int ret = EXIT_FAILURE; 73 + pid_t pid; 74 + int status; 75 + siginfo_t si; 76 + 77 + /* Attach to the child */ 78 + while (1) { 79 + int sig; 80 + 81 + pid = wait(&status); 82 + if (pid == -1) { 83 + perror("wait"); 84 + goto error; 85 + } 86 + 87 + /* 88 + * This should never happen but it's hard to flag in 89 + * the framework. 90 + */ 91 + if (pid != child) 92 + continue; 93 + 94 + if (WIFEXITED(status) || WIFSIGNALED(status)) 95 + ksft_exit_fail_msg("Child died unexpectedly\n"); 96 + 97 + if (!WIFSTOPPED(status)) 98 + goto error; 99 + 100 + sig = WSTOPSIG(status); 101 + 102 + if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) { 103 + if (errno == ESRCH) 104 + goto disappeared; 105 + 106 + if (errno == EINVAL) { 107 + sig = 0; /* bust group-stop */ 108 + goto cont; 109 + } 110 + 111 + ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n", 112 + strerror(errno)); 113 + goto error; 114 + } 115 + 116 + if (sig == SIGSTOP && si.si_code == SI_TKILL && 117 + si.si_pid == pid) 118 + break; 119 + 120 + cont: 121 + if (ptrace(PTRACE_CONT, pid, NULL, sig)) { 122 + if (errno == ESRCH) 123 + goto disappeared; 124 + 125 + ksft_test_result_fail("PTRACE_CONT: %s\n", 126 + strerror(errno)); 127 + goto error; 128 + } 129 + } 130 + 131 + ksft_print_msg("Parent is %d, child is %d\n", getpid(), child); 132 + 133 + test_tpidr(child); 134 + 135 + ret = EXIT_SUCCESS; 136 + 137 + error: 138 + kill(child, SIGKILL); 139 + 140 + disappeared: 141 + return ret; 142 + } 143 + 144 + int main(void) 145 + { 146 + int ret = EXIT_SUCCESS; 147 + pid_t child; 148 + 149 + srandom(getpid()); 150 + 151 + ksft_print_header(); 152 + 153 + ksft_set_plan(EXPECTED_TESTS); 154 + 155 + child = fork(); 156 + if (!child) 157 + return do_child(); 158 + 159 + if (do_parent(child)) 160 + ret = EXIT_FAILURE; 161 + 162 + ksft_print_cnts(); 163 + 164 + return ret; 165 + }