1 // SPDX-License-Identifier: GPL-2.0+
4 * Ptrace test for hw breakpoints
6 * Based on tools/testing/selftests/breakpoints/breakpoint_test.c
8 * This test forks and the parent then traces the child doing various
9 * types of ptrace enabled breakpoints
11 * Copyright (C) 2018 Michael Neuling, IBM Corporation.
14 #include <sys/ptrace.h>
21 #include <sys/types.h>
25 /* Breakpoint access modes */
32 static pid_t child_pid;
33 static struct ppc_debug_info dbginfo;
35 static void get_dbginfo(void)
39 ret = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
41 perror("Can't get breakpoint info\n");
46 static bool hwbreak_present(void)
48 return (dbginfo.num_data_bps != 0);
51 static bool dawr_present(void)
53 return !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
56 static void set_breakpoint_addr(void *addr)
60 ret = ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, addr);
62 perror("Can't set breakpoint addr\n");
67 static int set_hwbreakpoint_addr(void *addr, int range)
71 struct ppc_hw_breakpoint info;
74 info.trigger_type = PPC_BREAKPOINT_TRIGGER_RW;
75 info.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
77 info.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
78 info.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
79 info.addr = (__u64)addr;
80 info.addr2 = (__u64)addr + range;
81 info.condition_value = 0;
83 ret = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
85 perror("Can't set breakpoint\n");
91 static int del_hwbreakpoint_addr(int watchpoint_handle)
95 ret = ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, watchpoint_handle);
97 perror("Can't delete hw breakpoint\n");
103 #define DAWR_LENGTH_MAX 512
105 /* Dummy variables to test read/write accesses */
106 static unsigned long long
107 dummy_array[DAWR_LENGTH_MAX / sizeof(unsigned long long)]
108 __attribute__((aligned(512)));
109 static unsigned long long *dummy_var = dummy_array;
111 static void write_var(int len)
120 pcval = (char *)dummy_var;
124 psval = (short *)dummy_var;
128 pival = (int *)dummy_var;
132 plval = (long long *)dummy_var;
133 *plval = 0xffffffffffffffffLL;
138 static void read_var(int len)
140 char cval __attribute__((unused));
141 short sval __attribute__((unused));
142 int ival __attribute__((unused));
143 long long lval __attribute__((unused));
147 cval = *(char *)dummy_var;
150 sval = *(short *)dummy_var;
153 ival = *(int *)dummy_var;
156 lval = *(long long *)dummy_var;
162 * Do the r/w accesses to trigger the breakpoints. And run
165 static void trigger_tests(void)
169 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
171 perror("Can't be traced?\n");
175 /* Wake up father so that it sets up the first test */
176 kill(getpid(), SIGUSR1);
178 /* Test write watchpoints */
179 for (len = 1; len <= sizeof(long); len <<= 1)
182 /* Test read/write watchpoints (on read accesses) */
183 for (len = 1; len <= sizeof(long); len <<= 1)
186 /* Test when breakpoint is unset */
188 /* Test write watchpoints */
189 for (len = 1; len <= sizeof(long); len <<= 1)
192 /* Test read/write watchpoints (on read accesses) */
193 for (len = 1; len <= sizeof(long); len <<= 1)
197 static void check_success(const char *msg)
202 /* Wait for the child to SIGTRAP */
207 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
208 msg2 = "Child process hit the breakpoint";
211 printf("%s Result: [%s]\n", msg, msg2);
214 static void launch_watchpoints(char *buf, int mode, int len,
215 struct ppc_debug_info *dbginfo, bool dawr)
217 const char *mode_str;
218 unsigned long data = (unsigned long)(dummy_var);
232 /* Set DABR_TRANSLATION bit */
235 /* use PTRACE_SET_DEBUGREG breakpoints */
236 set_breakpoint_addr((void *)data);
237 ptrace(PTRACE_CONT, child_pid, NULL, 0);
238 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
240 /* Unregister hw brkpoint */
241 set_breakpoint_addr(NULL);
243 data = (data & ~7); /* remove dabr control bits */
245 /* use PPC_PTRACE_SETHWDEBUG breakpoint */
246 if (!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
247 return; /* not supported */
248 wh = set_hwbreakpoint_addr((void *)data, 0);
249 ptrace(PTRACE_CONT, child_pid, NULL, 0);
250 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
252 /* Unregister hw brkpoint */
253 del_hwbreakpoint_addr(wh);
255 /* try a wider range */
258 range = 512 - ((int)data & (DAWR_LENGTH_MAX - 1));
259 wh = set_hwbreakpoint_addr((void *)data, range);
260 ptrace(PTRACE_CONT, child_pid, NULL, 0);
261 sprintf(buf, "Test %s watchpoint with len: %d ", mode_str, len);
263 /* Unregister hw brkpoint */
264 del_hwbreakpoint_addr(wh);
267 /* Set the breakpoints and check the child successfully trigger them */
268 static int launch_tests(bool dawr)
273 struct ppc_debug_info dbginfo;
275 i = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo);
277 perror("Can't set breakpoint info\n");
280 if (!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
281 printf("WARNING: Kernel doesn't support PPC_PTRACE_SETHWDEBUG\n");
283 /* Write watchpoint */
284 for (len = 1; len <= sizeof(long); len <<= 1)
285 launch_watchpoints(buf, BP_W, len, &dbginfo, dawr);
287 /* Read-Write watchpoint */
288 for (len = 1; len <= sizeof(long); len <<= 1)
289 launch_watchpoints(buf, BP_RW, len, &dbginfo, dawr);
291 ptrace(PTRACE_CONT, child_pid, NULL, 0);
294 * Now we have unregistered the breakpoint, access by child
295 * should not cause SIGTRAP.
300 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
301 printf("FAIL: Child process hit the breakpoint, which is not expected\n");
302 ptrace(PTRACE_CONT, child_pid, NULL, 0);
306 if (WIFEXITED(status))
307 printf("Child exited normally\n");
312 static int ptrace_hwbreak(void)
329 SKIP_IF(!hwbreak_present());
330 dawr = dawr_present();
332 ret = launch_tests(dawr);
339 int main(int argc, char **argv, char **envp)
341 return test_harness(ptrace_hwbreak, "ptrace-hwbreak");