1 // SPDX-License-Identifier: GPL-2.0+ 2 3 /* 4 * Ptrace test for hw breakpoints 5 * 6 * Based on tools/testing/selftests/breakpoints/breakpoint_test.c 7 * 8 * This test forks and the parent then traces the child doing various 9 * types of ptrace enabled breakpoints 10 * 11 * Copyright (C) 2018 Michael Neuling, IBM Corporation. 12 */ 13 14 #include <sys/ptrace.h> 15 #include <unistd.h> 16 #include <stddef.h> 17 #include <sys/user.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <signal.h> 21 #include <sys/types.h> 22 #include <sys/wait.h> 23 #include "ptrace.h" 24 25 /* Breakpoint access modes */ 26 enum { 27 BP_X = 1, 28 BP_RW = 2, 29 BP_W = 4, 30 }; 31 32 static pid_t child_pid; 33 static struct ppc_debug_info dbginfo; 34 35 static void get_dbginfo(void) 36 { 37 int ret; 38 39 ret = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo); 40 if (ret) { 41 perror("Can't get breakpoint info\n"); 42 exit(-1); 43 } 44 } 45 46 static bool hwbreak_present(void) 47 { 48 return (dbginfo.num_data_bps != 0); 49 } 50 51 static bool dawr_present(void) 52 { 53 return !!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR); 54 } 55 56 static void set_breakpoint_addr(void *addr) 57 { 58 int ret; 59 60 ret = ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, addr); 61 if (ret) { 62 perror("Can't set breakpoint addr\n"); 63 exit(-1); 64 } 65 } 66 67 static int set_hwbreakpoint_addr(void *addr, int range) 68 { 69 int ret; 70 71 struct ppc_hw_breakpoint info; 72 73 info.version = 1; 74 info.trigger_type = PPC_BREAKPOINT_TRIGGER_RW; 75 info.addr_mode = PPC_BREAKPOINT_MODE_EXACT; 76 if (range > 0) 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; 82 83 ret = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info); 84 if (ret < 0) { 85 perror("Can't set breakpoint\n"); 86 exit(-1); 87 } 88 return ret; 89 } 90 91 static int del_hwbreakpoint_addr(int watchpoint_handle) 92 { 93 int ret; 94 95 ret = ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, watchpoint_handle); 96 if (ret < 0) { 97 perror("Can't delete hw breakpoint\n"); 98 exit(-1); 99 } 100 return ret; 101 } 102 103 #define DAWR_LENGTH_MAX 512 104 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; 110 111 static void write_var(int len) 112 { 113 long long *plval; 114 char *pcval; 115 short *psval; 116 int *pival; 117 118 switch (len) { 119 case 1: 120 pcval = (char *)dummy_var; 121 *pcval = 0xff; 122 break; 123 case 2: 124 psval = (short *)dummy_var; 125 *psval = 0xffff; 126 break; 127 case 4: 128 pival = (int *)dummy_var; 129 *pival = 0xffffffff; 130 break; 131 case 8: 132 plval = (long long *)dummy_var; 133 *plval = 0xffffffffffffffffLL; 134 break; 135 } 136 } 137 138 static void read_var(int len) 139 { 140 char cval __attribute__((unused)); 141 short sval __attribute__((unused)); 142 int ival __attribute__((unused)); 143 long long lval __attribute__((unused)); 144 145 switch (len) { 146 case 1: 147 cval = *(char *)dummy_var; 148 break; 149 case 2: 150 sval = *(short *)dummy_var; 151 break; 152 case 4: 153 ival = *(int *)dummy_var; 154 break; 155 case 8: 156 lval = *(long long *)dummy_var; 157 break; 158 } 159 } 160 161 /* 162 * Do the r/w accesses to trigger the breakpoints. And run 163 * the usual traps. 164 */ 165 static void trigger_tests(void) 166 { 167 int len, ret; 168 169 ret = ptrace(PTRACE_TRACEME, 0, NULL, 0); 170 if (ret) { 171 perror("Can't be traced?\n"); 172 return; 173 } 174 175 /* Wake up father so that it sets up the first test */ 176 kill(getpid(), SIGUSR1); 177 178 /* Test write watchpoints */ 179 for (len = 1; len <= sizeof(long); len <<= 1) 180 write_var(len); 181 182 /* Test read/write watchpoints (on read accesses) */ 183 for (len = 1; len <= sizeof(long); len <<= 1) 184 read_var(len); 185 186 /* Test when breakpoint is unset */ 187 188 /* Test write watchpoints */ 189 for (len = 1; len <= sizeof(long); len <<= 1) 190 write_var(len); 191 192 /* Test read/write watchpoints (on read accesses) */ 193 for (len = 1; len <= sizeof(long); len <<= 1) 194 read_var(len); 195 } 196 197 static void check_success(const char *msg) 198 { 199 const char *msg2; 200 int status; 201 202 /* Wait for the child to SIGTRAP */ 203 wait(&status); 204 205 msg2 = "Failed"; 206 207 if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { 208 msg2 = "Child process hit the breakpoint"; 209 } 210 211 printf("%s Result: [%s]\n", msg, msg2); 212 } 213 214 static void launch_watchpoints(char *buf, int mode, int len, 215 struct ppc_debug_info *dbginfo, bool dawr) 216 { 217 const char *mode_str; 218 unsigned long data = (unsigned long)(dummy_var); 219 int wh, range; 220 221 data &= ~0x7UL; 222 223 if (mode == BP_W) { 224 data |= (1UL << 1); 225 mode_str = "write"; 226 } else { 227 data |= (1UL << 0); 228 data |= (1UL << 1); 229 mode_str = "read"; 230 } 231 232 /* Set DABR_TRANSLATION bit */ 233 data |= (1UL << 2); 234 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); 239 check_success(buf); 240 /* Unregister hw brkpoint */ 241 set_breakpoint_addr(NULL); 242 243 data = (data & ~7); /* remove dabr control bits */ 244 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); 251 check_success(buf); 252 /* Unregister hw brkpoint */ 253 del_hwbreakpoint_addr(wh); 254 255 /* try a wider range */ 256 range = 8; 257 if (dawr) 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); 262 check_success(buf); 263 /* Unregister hw brkpoint */ 264 del_hwbreakpoint_addr(wh); 265 } 266 267 /* Set the breakpoints and check the child successfully trigger them */ 268 static int launch_tests(bool dawr) 269 { 270 char buf[1024]; 271 int len, i, status; 272 273 struct ppc_debug_info dbginfo; 274 275 i = ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, &dbginfo); 276 if (i) { 277 perror("Can't set breakpoint info\n"); 278 exit(-1); 279 } 280 if (!(dbginfo.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE)) 281 printf("WARNING: Kernel doesn't support PPC_PTRACE_SETHWDEBUG\n"); 282 283 /* Write watchpoint */ 284 for (len = 1; len <= sizeof(long); len <<= 1) 285 launch_watchpoints(buf, BP_W, len, &dbginfo, dawr); 286 287 /* Read-Write watchpoint */ 288 for (len = 1; len <= sizeof(long); len <<= 1) 289 launch_watchpoints(buf, BP_RW, len, &dbginfo, dawr); 290 291 ptrace(PTRACE_CONT, child_pid, NULL, 0); 292 293 /* 294 * Now we have unregistered the breakpoint, access by child 295 * should not cause SIGTRAP. 296 */ 297 298 wait(&status); 299 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); 303 return TEST_FAIL; 304 } 305 306 if (WIFEXITED(status)) 307 printf("Child exited normally\n"); 308 309 return TEST_PASS; 310 } 311 312 static int ptrace_hwbreak(void) 313 { 314 pid_t pid; 315 int ret; 316 bool dawr; 317 318 pid = fork(); 319 if (!pid) { 320 trigger_tests(); 321 return 0; 322 } 323 324 wait(NULL); 325 326 child_pid = pid; 327 328 get_dbginfo(); 329 SKIP_IF(!hwbreak_present()); 330 dawr = dawr_present(); 331 332 ret = launch_tests(dawr); 333 334 wait(NULL); 335 336 return ret; 337 } 338 339 int main(int argc, char **argv, char **envp) 340 { 341 return test_harness(ptrace_hwbreak, "ptrace-hwbreak"); 342 } 343