1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2016 Google, Inc.
5 * Original Code by Pavel Labath <labath@google.com>
7 * Code modified by Pratyush Anand <panand@redhat.com>
8 * for testing different byte select for each access size.
13 #include <asm/ptrace.h>
14 #include <sys/types.h>
16 #include <sys/ptrace.h>
17 #include <sys/param.h>
29 #include "../kselftest.h"
31 static volatile uint8_t var
[96] __attribute__((__aligned__(32)));
33 static void child(int size
, int wr
)
35 volatile uint8_t *addr
= &var
[32 + wr
];
37 if (ptrace(PTRACE_TRACEME
, 0, NULL
, NULL
) != 0) {
39 "ptrace(PTRACE_TRACEME) failed: %s\n",
44 if (raise(SIGSTOP
) != 0) {
46 "raise(SIGSTOP) failed: %s\n", strerror(errno
));
50 if ((uintptr_t) addr
% size
) {
52 "Wrong address write for the given size: %s\n",
62 *(uint16_t *)addr
= 47;
65 *(uint32_t *)addr
= 47;
68 *(uint64_t *)addr
= 47;
71 __asm__
volatile ("stp x29, x30, %0" : "=m" (addr
[0]));
74 __asm__
volatile ("stp q29, q30, %0" : "=m" (addr
[0]));
81 static bool set_watchpoint(pid_t pid
, int size
, int wp
)
83 const volatile uint8_t *addr
= &var
[32 + wp
];
84 const int offset
= (uintptr_t)addr
% 8;
85 const unsigned int byte_mask
= ((1 << size
) - 1) << offset
;
86 const unsigned int type
= 2; /* Write */
87 const unsigned int enable
= 1;
88 const unsigned int control
= byte_mask
<< 5 | type
<< 3 | enable
;
89 struct user_hwdebug_state dreg_state
;
92 memset(&dreg_state
, 0, sizeof(dreg_state
));
93 dreg_state
.dbg_regs
[0].addr
= (uintptr_t)(addr
- offset
);
94 dreg_state
.dbg_regs
[0].ctrl
= control
;
95 iov
.iov_base
= &dreg_state
;
96 iov
.iov_len
= offsetof(struct user_hwdebug_state
, dbg_regs
) +
97 sizeof(dreg_state
.dbg_regs
[0]);
98 if (ptrace(PTRACE_SETREGSET
, pid
, NT_ARM_HW_WATCH
, &iov
) == 0)
103 "ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) not supported on this hardware: %s\n",
107 "ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) failed: %s\n",
112 static bool arun_test(int wr_size
, int wp_size
, int wr
, int wp
)
120 ksft_test_result_fail(
121 "fork() failed: %s\n", strerror(errno
));
127 wpid
= waitpid(pid
, &status
, __WALL
);
130 "waitpid() failed: %s\n", strerror(errno
));
133 if (!WIFSTOPPED(status
)) {
135 "child did not stop: %s\n", strerror(errno
));
138 if (WSTOPSIG(status
) != SIGSTOP
) {
139 ksft_print_msg("child did not stop with SIGSTOP\n");
143 if (!set_watchpoint(pid
, wp_size
, wp
))
146 if (ptrace(PTRACE_CONT
, pid
, NULL
, NULL
) < 0) {
148 "ptrace(PTRACE_SINGLESTEP) failed: %s\n",
154 wpid
= waitpid(pid
, &status
, __WALL
);
157 "waitpid() failed: %s\n", strerror(errno
));
161 if (WIFEXITED(status
)) {
162 ksft_print_msg("child did not single-step\n");
165 if (!WIFSTOPPED(status
)) {
166 ksft_print_msg("child did not stop\n");
169 if (WSTOPSIG(status
) != SIGTRAP
) {
170 ksft_print_msg("child did not stop with SIGTRAP\n");
173 if (ptrace(PTRACE_GETSIGINFO
, pid
, NULL
, &siginfo
) != 0) {
175 "ptrace(PTRACE_GETSIGINFO): %s\n",
179 if (siginfo
.si_code
!= TRAP_HWBKPT
) {
181 "Unexpected si_code %d\n", siginfo
.si_code
);
186 wpid
= waitpid(pid
, &status
, 0);
189 "waitpid() failed: %s\n", strerror(errno
));
195 static void sigalrm(int sig
)
199 int main(int argc
, char **argv
)
202 bool succeeded
= true;
203 struct sigaction act
;
210 act
.sa_handler
= sigalrm
;
211 sigemptyset(&act
.sa_mask
);
213 sigaction(SIGALRM
, &act
, NULL
);
214 for (size
= 1; size
<= 32; size
= size
*2) {
215 for (wr
= 0; wr
<= 32; wr
= wr
+ size
) {
216 for (wp
= wr
- size
; wp
<= wr
+ size
; wp
= wp
+ size
) {
217 result
= run_test(size
, MIN(size
, 8), wr
, wp
);
218 if ((result
&& wr
== wp
) ||
219 (!result
&& wr
!= wp
))
220 ksft_test_result_pass(
221 "Test size = %d write offset = %d watchpoint offset = %d\n",
224 ksft_test_result_fail(
225 "Test size = %d write offset = %d watchpoint offset = %d\n",
233 for (size
= 1; size
<= 32; size
= size
*2) {
234 if (run_test(size
, 8, -size
, -8))
235 ksft_test_result_pass(
236 "Test size = %d write offset = %d watchpoint offset = -8\n",
239 ksft_test_result_fail(
240 "Test size = %d write offset = %d watchpoint offset = -8\n",