xref: /netbsd-src/external/gpl3/gdb/dist/gdb/testsuite/gdb.arch/aarch64-dbreg-contents.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
1 /* Test case for setting a memory-write unaligned watchpoint on aarch64.
2 
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.
6 
7   Permission is granted to anyone to use this software for any purpose,
8   including commercial applications, and to alter it and redistribute it
9   freely.  */
10 
11 #define _GNU_SOURCE 1
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/ptrace.h>
15 #include <asm/ptrace.h>
16 #include <assert.h>
17 #include <sys/wait.h>
18 #include <stddef.h>
19 #include <errno.h>
20 #include <sys/uio.h>
21 #include <elf.h>
22 #include <error.h>
23 
24 static pid_t child;
25 
26 static void
cleanup(void)27 cleanup (void)
28 {
29   if (child > 0)
30     kill (child, SIGKILL);
31   child = 0;
32 }
33 
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)
41 
42 static void
set_watchpoint(pid_t pid,volatile void * addr,unsigned len_mask)43 set_watchpoint (pid_t pid, volatile void *addr, unsigned len_mask)
44 {
45   struct user_hwdebug_state dreg_state;
46   struct iovec iov;
47   long l;
48 
49   assert (len_mask >= 0x01);
50   assert (len_mask <= 0xff);
51 
52   iov.iov_base = &dreg_state;
53   iov.iov_len = sizeof (dreg_state);
54   errno = 0;
55   l = ptrace (PTRACE_GETREGSET, pid, NT_ARM_HW_WATCH, &iov);
56   assert (l == 0);
57   assert (AARCH64_DEBUG_ARCH (dreg_state.dbg_info) >= AARCH64_DEBUG_ARCH_V8);
58   assert (AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info) >= 1);
59 
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));
63 
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);
67 
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;
71 
72   iov.iov_base = &dreg_state;
73   iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs)
74                  + sizeof (dreg_state.dbg_regs[0]));
75   errno = 0;
76   l = ptrace (PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &iov);
77   if (errno != 0)
78     error (1, errno, "PTRACE_SETREGSET: NT_ARM_HW_WATCH");
79   assert (l == 0);
80 }
81 
82 static volatile long long check;
83 
84 int
main(void)85 main (void)
86 {
87   pid_t got_pid;
88   int i, status;
89   long l;
90 
91   atexit (cleanup);
92 
93   child = fork ();
94   assert (child >= 0);
95   if (child == 0)
96     {
97       l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
98       assert (l == 0);
99       i = raise (SIGUSR1);
100       assert (i == 0);
101       check = -1;
102       i = raise (SIGUSR2);
103       /* NOTREACHED */
104       assert (0);
105     }
106 
107   got_pid = waitpid (child, &status, 0);
108   assert (got_pid == child);
109   assert (WIFSTOPPED (status));
110   assert (WSTOPSIG (status) == SIGUSR1);
111 
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);
116 
117   errno = 0;
118   l = ptrace (PTRACE_CONT, child, 0l, 0l);
119   assert_perror (errno);
120   assert (l == 0);
121 
122   got_pid = waitpid (child, &status, 0);
123   assert (got_pid == child);
124   assert (WIFSTOPPED (status));
125   if (WSTOPSIG (status) == SIGUSR2)
126     {
127       /* We missed the watchpoint - unsupported by hardware?  */
128       cleanup ();
129       return 2;
130     }
131   assert (WSTOPSIG (status) == SIGTRAP);
132 
133   return 0;
134 }
135