2 * Copyright (C) 2016 Google, Inc.
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * Original Code by Pavel Labath <labath@google.com>
15 * Code modified by Pratyush Anand <panand@redhat.com>
16 * for testing different byte select for each access size.
22 #include <asm/ptrace.h>
23 #include <sys/types.h>
25 #include <sys/ptrace.h>
26 #include <sys/param.h>
38 #include "../kselftest.h"
40 static volatile uint8_t var
[96] __attribute__((__aligned__(32)));
42 static void child(int size
, int wr
)
44 volatile uint8_t *addr
= &var
[32 + wr
];
46 if (ptrace(PTRACE_TRACEME
, 0, NULL
, NULL
) != 0) {
48 "ptrace(PTRACE_TRACEME) failed: %s\n",
53 if (raise(SIGSTOP
) != 0) {
55 "raise(SIGSTOP) failed: %s\n", strerror(errno
));
59 if ((uintptr_t) addr
% size
) {
61 "Wrong address write for the given size: %s\n",
71 *(uint16_t *)addr
= 47;
74 *(uint32_t *)addr
= 47;
77 *(uint64_t *)addr
= 47;
80 __asm__
volatile ("stp x29, x30, %0" : "=m" (addr
[0]));
83 __asm__
volatile ("stp q29, q30, %0" : "=m" (addr
[0]));
90 static bool set_watchpoint(pid_t pid
, int size
, int wp
)
92 const volatile uint8_t *addr
= &var
[32 + wp
];
93 const int offset
= (uintptr_t)addr
% 8;
94 const unsigned int byte_mask
= ((1 << size
) - 1) << offset
;
95 const unsigned int type
= 2; /* Write */
96 const unsigned int enable
= 1;
97 const unsigned int control
= byte_mask
<< 5 | type
<< 3 | enable
;
98 struct user_hwdebug_state dreg_state
;
101 memset(&dreg_state
, 0, sizeof(dreg_state
));
102 dreg_state
.dbg_regs
[0].addr
= (uintptr_t)(addr
- offset
);
103 dreg_state
.dbg_regs
[0].ctrl
= control
;
104 iov
.iov_base
= &dreg_state
;
105 iov
.iov_len
= offsetof(struct user_hwdebug_state
, dbg_regs
) +
106 sizeof(dreg_state
.dbg_regs
[0]);
107 if (ptrace(PTRACE_SETREGSET
, pid
, NT_ARM_HW_WATCH
, &iov
) == 0)
112 "ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) not supported on this hardware: %s\n",
116 "ptrace(PTRACE_SETREGSET, NT_ARM_HW_WATCH) failed: %s\n",
121 static bool run_test(int wr_size
, int wp_size
, int wr
, int wp
)
129 ksft_test_result_fail(
130 "fork() failed: %s\n", strerror(errno
));
136 wpid
= waitpid(pid
, &status
, __WALL
);
139 "waitpid() failed: %s\n", strerror(errno
));
142 if (!WIFSTOPPED(status
)) {
144 "child did not stop: %s\n", strerror(errno
));
147 if (WSTOPSIG(status
) != SIGSTOP
) {
148 ksft_print_msg("child did not stop with SIGSTOP\n");
152 if (!set_watchpoint(pid
, wp_size
, wp
))
155 if (ptrace(PTRACE_CONT
, pid
, NULL
, NULL
) < 0) {
157 "ptrace(PTRACE_SINGLESTEP) failed: %s\n",
163 wpid
= waitpid(pid
, &status
, __WALL
);
166 "waitpid() failed: %s\n", strerror(errno
));
170 if (WIFEXITED(status
)) {
171 ksft_print_msg("child did not single-step\n");
174 if (!WIFSTOPPED(status
)) {
175 ksft_print_msg("child did not stop\n");
178 if (WSTOPSIG(status
) != SIGTRAP
) {
179 ksft_print_msg("child did not stop with SIGTRAP\n");
182 if (ptrace(PTRACE_GETSIGINFO
, pid
, NULL
, &siginfo
) != 0) {
184 "ptrace(PTRACE_GETSIGINFO): %s\n",
188 if (siginfo
.si_code
!= TRAP_HWBKPT
) {
190 "Unexpected si_code %d\n", siginfo
.si_code
);
195 wpid
= waitpid(pid
, &status
, 0);
198 "waitpid() failed: %s\n", strerror(errno
));
204 static void sigalrm(int sig
)
208 int main(int argc
, char **argv
)
211 bool succeeded
= true;
212 struct sigaction act
;
218 act
.sa_handler
= sigalrm
;
219 sigemptyset(&act
.sa_mask
);
221 sigaction(SIGALRM
, &act
, NULL
);
222 for (size
= 1; size
<= 32; size
= size
*2) {
223 for (wr
= 0; wr
<= 32; wr
= wr
+ size
) {
224 for (wp
= wr
- size
; wp
<= wr
+ size
; wp
= wp
+ size
) {
225 result
= run_test(size
, MIN(size
, 8), wr
, wp
);
226 if ((result
&& wr
== wp
) ||
227 (!result
&& wr
!= wp
))
228 ksft_test_result_pass(
229 "Test size = %d write offset = %d watchpoint offset = %d\n",
232 ksft_test_result_fail(
233 "Test size = %d write offset = %d watchpoint offset = %d\n",
241 for (size
= 1; size
<= 32; size
= size
*2) {
242 if (run_test(size
, 8, -size
, -8))
243 ksft_test_result_pass(
244 "Test size = %d write offset = %d watchpoint offset = -8\n",
247 ksft_test_result_fail(
248 "Test size = %d write offset = %d watchpoint offset = -8\n",