1 /* Test case for setting a memory-write unaligned watchpoint on aarch64.
3 This software is provided 'as-is', without any express or implied
4 warranty. In no event will the authors be held liable for any damages
5 arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it
14 #include <sys/ptrace.h>
15 #include <asm/ptrace.h>
30 kill (child
, SIGKILL
);
34 /* Macros to extract fields from the hardware debug information word. */
35 #define AARCH64_DEBUG_NUM_SLOTS(x) ((x) & 0xff)
36 #define AARCH64_DEBUG_ARCH(x) (((x) >> 8) & 0xff)
37 /* Macro for the expected version of the ARMv8-A debug architecture. */
38 #define AARCH64_DEBUG_ARCH_V8 0x6
39 #define DR_CONTROL_ENABLED(ctrl) (((ctrl) & 0x1) == 1)
40 #define DR_CONTROL_LENGTH(ctrl) (((ctrl) >> 5) & 0xff)
43 set_watchpoint (pid_t pid
, volatile void *addr
, unsigned len_mask
)
45 struct user_hwdebug_state dreg_state
;
49 assert (len_mask
>= 0x01);
50 assert (len_mask
<= 0xff);
52 iov
.iov_base
= &dreg_state
;
53 iov
.iov_len
= sizeof (dreg_state
);
55 l
= ptrace (PTRACE_GETREGSET
, pid
, NT_ARM_HW_WATCH
, &iov
);
57 assert (AARCH64_DEBUG_ARCH (dreg_state
.dbg_info
) >= AARCH64_DEBUG_ARCH_V8
);
58 assert (AARCH64_DEBUG_NUM_SLOTS (dreg_state
.dbg_info
) >= 1);
60 assert (!DR_CONTROL_ENABLED (dreg_state
.dbg_regs
[0].ctrl
));
61 dreg_state
.dbg_regs
[0].ctrl
|= 1;
62 assert ( DR_CONTROL_ENABLED (dreg_state
.dbg_regs
[0].ctrl
));
64 assert (DR_CONTROL_LENGTH (dreg_state
.dbg_regs
[0].ctrl
) == 0);
65 dreg_state
.dbg_regs
[0].ctrl
|= len_mask
<< 5;
66 assert (DR_CONTROL_LENGTH (dreg_state
.dbg_regs
[0].ctrl
) == len_mask
);
68 dreg_state
.dbg_regs
[0].ctrl
|= 2 << 3; // write
69 dreg_state
.dbg_regs
[0].ctrl
|= 2 << 1; // enabled at el0
70 dreg_state
.dbg_regs
[0].addr
= (uintptr_t) addr
;
72 iov
.iov_base
= &dreg_state
;
73 iov
.iov_len
= (offsetof (struct user_hwdebug_state
, dbg_regs
)
74 + sizeof (dreg_state
.dbg_regs
[0]));
76 l
= ptrace (PTRACE_SETREGSET
, pid
, NT_ARM_HW_WATCH
, &iov
);
78 error (1, errno
, "PTRACE_SETREGSET: NT_ARM_HW_WATCH");
82 static volatile long long check
;
97 l
= ptrace (PTRACE_TRACEME
, 0, NULL
, NULL
);
107 got_pid
= waitpid (child
, &status
, 0);
108 assert (got_pid
== child
);
109 assert (WIFSTOPPED (status
));
110 assert (WSTOPSIG (status
) == SIGUSR1
);
112 /* Add a watchpoint to check.
113 Restart the child. It will write to check.
114 Check child has stopped on the watchpoint. */
115 set_watchpoint (child
, &check
, 0x02);
118 l
= ptrace (PTRACE_CONT
, child
, 0l, 0l);
119 assert_perror (errno
);
122 got_pid
= waitpid (child
, &status
, 0);
123 assert (got_pid
== child
);
124 assert (WIFSTOPPED (status
));
125 if (WSTOPSIG (status
) == SIGUSR2
)
127 /* We missed the watchpoint - unsupported by hardware? */
131 assert (WSTOPSIG (status
) == SIGTRAP
);