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 #define SPRN_PVR 0x11F 26 #define PVR_8xx 0x00500000 27 28 bool is_8xx; 29 30 /* 31 * Use volatile on all global var so that compiler doesn't 32 * optimise their load/stores. Otherwise selftest can fail. 33 */ 34 static volatile __u64 glvar; 35 36 #define DAWR_MAX_LEN 512 37 static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512))); 38 39 #define A_LEN 6 40 #define B_LEN 6 41 struct gstruct { 42 __u8 a[A_LEN]; /* double word aligned */ 43 __u8 b[B_LEN]; /* double word unaligned */ 44 }; 45 static volatile struct gstruct gstruct __attribute__((aligned(512))); 46 47 48 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo) 49 { 50 if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) { 51 perror("Can't get breakpoint info"); 52 exit(-1); 53 } 54 } 55 56 static bool dawr_present(struct ppc_debug_info *dbginfo) 57 { 58 return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR); 59 } 60 61 static void write_var(int len) 62 { 63 __u8 *pcvar; 64 __u16 *psvar; 65 __u32 *pivar; 66 __u64 *plvar; 67 68 switch (len) { 69 case 1: 70 pcvar = (__u8 *)&glvar; 71 *pcvar = 0xff; 72 break; 73 case 2: 74 psvar = (__u16 *)&glvar; 75 *psvar = 0xffff; 76 break; 77 case 4: 78 pivar = (__u32 *)&glvar; 79 *pivar = 0xffffffff; 80 break; 81 case 8: 82 plvar = (__u64 *)&glvar; 83 *plvar = 0xffffffffffffffffLL; 84 break; 85 } 86 } 87 88 static void read_var(int len) 89 { 90 __u8 cvar __attribute__((unused)); 91 __u16 svar __attribute__((unused)); 92 __u32 ivar __attribute__((unused)); 93 __u64 lvar __attribute__((unused)); 94 95 switch (len) { 96 case 1: 97 cvar = (__u8)glvar; 98 break; 99 case 2: 100 svar = (__u16)glvar; 101 break; 102 case 4: 103 ivar = (__u32)glvar; 104 break; 105 case 8: 106 lvar = (__u64)glvar; 107 break; 108 } 109 } 110 111 static void test_workload(void) 112 { 113 __u8 cvar __attribute__((unused)); 114 __u32 ivar __attribute__((unused)); 115 int len = 0; 116 117 if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) { 118 perror("Child can't be traced?"); 119 exit(-1); 120 } 121 122 /* Wake up father so that it sets up the first test */ 123 kill(getpid(), SIGUSR1); 124 125 /* PTRACE_SET_DEBUGREG, WO test */ 126 for (len = 1; len <= sizeof(glvar); len <<= 1) 127 write_var(len); 128 129 /* PTRACE_SET_DEBUGREG, RO test */ 130 for (len = 1; len <= sizeof(glvar); len <<= 1) 131 read_var(len); 132 133 /* PTRACE_SET_DEBUGREG, RW test */ 134 for (len = 1; len <= sizeof(glvar); len <<= 1) { 135 if (rand() % 2) 136 read_var(len); 137 else 138 write_var(len); 139 } 140 141 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */ 142 write_var(1); 143 144 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */ 145 read_var(1); 146 147 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */ 148 if (rand() % 2) 149 write_var(1); 150 else 151 read_var(1); 152 153 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */ 154 gstruct.a[rand() % A_LEN] = 'a'; 155 156 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */ 157 cvar = gstruct.a[rand() % A_LEN]; 158 159 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */ 160 if (rand() % 2) 161 gstruct.a[rand() % A_LEN] = 'a'; 162 else 163 cvar = gstruct.a[rand() % A_LEN]; 164 165 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */ 166 gstruct.b[rand() % B_LEN] = 'b'; 167 168 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */ 169 cvar = gstruct.b[rand() % B_LEN]; 170 171 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */ 172 if (rand() % 2) 173 gstruct.b[rand() % B_LEN] = 'b'; 174 else 175 cvar = gstruct.b[rand() % B_LEN]; 176 177 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */ 178 if (rand() % 2) 179 *((int *)(gstruct.a + 4)) = 10; 180 else 181 ivar = *((int *)(gstruct.a + 4)); 182 183 /* PPC_PTRACE_SETHWDEBUG. DAWR_MAX_LEN. RW test */ 184 if (rand() % 2) 185 big_var[rand() % DAWR_MAX_LEN] = 'a'; 186 else 187 cvar = big_var[rand() % DAWR_MAX_LEN]; 188 } 189 190 static void check_success(pid_t child_pid, const char *name, const char *type, 191 unsigned long saddr, int len) 192 { 193 int status; 194 siginfo_t siginfo; 195 unsigned long eaddr = (saddr + len - 1) | 0x7; 196 197 saddr &= ~0x7; 198 199 /* Wait for the child to SIGTRAP */ 200 wait(&status); 201 202 ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo); 203 204 if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP || 205 (unsigned long)siginfo.si_addr < saddr || 206 (unsigned long)siginfo.si_addr > eaddr) { 207 printf("%s, %s, len: %d: Fail\n", name, type, len); 208 exit(-1); 209 } 210 211 printf("%s, %s, len: %d: Ok\n", name, type, len); 212 213 if (!is_8xx) { 214 /* 215 * For ptrace registered watchpoint, signal is generated 216 * before executing load/store. Singlestep the instruction 217 * and then continue the test. 218 */ 219 ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0); 220 wait(NULL); 221 } 222 } 223 224 static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr) 225 { 226 if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) { 227 perror("PTRACE_SET_DEBUGREG failed"); 228 exit(-1); 229 } 230 } 231 232 static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info) 233 { 234 int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info); 235 236 if (wh <= 0) { 237 perror("PPC_PTRACE_SETHWDEBUG failed"); 238 exit(-1); 239 } 240 return wh; 241 } 242 243 static void ptrace_delhwdebug(pid_t child_pid, int wh) 244 { 245 if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) { 246 perror("PPC_PTRACE_DELHWDEBUG failed"); 247 exit(-1); 248 } 249 } 250 251 #define DABR_READ_SHIFT 0 252 #define DABR_WRITE_SHIFT 1 253 #define DABR_TRANSLATION_SHIFT 2 254 255 static int test_set_debugreg(pid_t child_pid) 256 { 257 unsigned long wp_addr = (unsigned long)&glvar; 258 char *name = "PTRACE_SET_DEBUGREG"; 259 int len; 260 261 /* PTRACE_SET_DEBUGREG, WO test*/ 262 wp_addr &= ~0x7UL; 263 wp_addr |= (1UL << DABR_WRITE_SHIFT); 264 wp_addr |= (1UL << DABR_TRANSLATION_SHIFT); 265 for (len = 1; len <= sizeof(glvar); len <<= 1) { 266 ptrace_set_debugreg(child_pid, wp_addr); 267 ptrace(PTRACE_CONT, child_pid, NULL, 0); 268 check_success(child_pid, name, "WO", wp_addr, len); 269 } 270 271 /* PTRACE_SET_DEBUGREG, RO test */ 272 wp_addr &= ~0x7UL; 273 wp_addr |= (1UL << DABR_READ_SHIFT); 274 wp_addr |= (1UL << DABR_TRANSLATION_SHIFT); 275 for (len = 1; len <= sizeof(glvar); len <<= 1) { 276 ptrace_set_debugreg(child_pid, wp_addr); 277 ptrace(PTRACE_CONT, child_pid, NULL, 0); 278 check_success(child_pid, name, "RO", wp_addr, len); 279 } 280 281 /* PTRACE_SET_DEBUGREG, RW test */ 282 wp_addr &= ~0x7UL; 283 wp_addr |= (1Ul << DABR_READ_SHIFT); 284 wp_addr |= (1UL << DABR_WRITE_SHIFT); 285 wp_addr |= (1UL << DABR_TRANSLATION_SHIFT); 286 for (len = 1; len <= sizeof(glvar); len <<= 1) { 287 ptrace_set_debugreg(child_pid, wp_addr); 288 ptrace(PTRACE_CONT, child_pid, NULL, 0); 289 check_success(child_pid, name, "RW", wp_addr, len); 290 } 291 292 ptrace_set_debugreg(child_pid, 0); 293 return 0; 294 } 295 296 static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type, 297 unsigned long addr, int len) 298 { 299 info->version = 1; 300 info->trigger_type = type; 301 info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; 302 info->addr = (__u64)addr; 303 info->addr2 = (__u64)addr + len; 304 info->condition_value = 0; 305 if (!len) 306 info->addr_mode = PPC_BREAKPOINT_MODE_EXACT; 307 else 308 info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; 309 } 310 311 static void test_sethwdebug_exact(pid_t child_pid) 312 { 313 struct ppc_hw_breakpoint info; 314 unsigned long wp_addr = (unsigned long)&glvar; 315 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT"; 316 int len = 1; /* hardcoded in kernel */ 317 int wh; 318 319 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */ 320 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0); 321 wh = ptrace_sethwdebug(child_pid, &info); 322 ptrace(PTRACE_CONT, child_pid, NULL, 0); 323 check_success(child_pid, name, "WO", wp_addr, len); 324 ptrace_delhwdebug(child_pid, wh); 325 326 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */ 327 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0); 328 wh = ptrace_sethwdebug(child_pid, &info); 329 ptrace(PTRACE_CONT, child_pid, NULL, 0); 330 check_success(child_pid, name, "RO", wp_addr, len); 331 ptrace_delhwdebug(child_pid, wh); 332 333 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */ 334 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0); 335 wh = ptrace_sethwdebug(child_pid, &info); 336 ptrace(PTRACE_CONT, child_pid, NULL, 0); 337 check_success(child_pid, name, "RW", wp_addr, len); 338 ptrace_delhwdebug(child_pid, wh); 339 } 340 341 static void test_sethwdebug_range_aligned(pid_t child_pid) 342 { 343 struct ppc_hw_breakpoint info; 344 unsigned long wp_addr; 345 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED"; 346 int len; 347 int wh; 348 349 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */ 350 wp_addr = (unsigned long)&gstruct.a; 351 len = A_LEN; 352 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len); 353 wh = ptrace_sethwdebug(child_pid, &info); 354 ptrace(PTRACE_CONT, child_pid, NULL, 0); 355 check_success(child_pid, name, "WO", wp_addr, len); 356 ptrace_delhwdebug(child_pid, wh); 357 358 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */ 359 wp_addr = (unsigned long)&gstruct.a; 360 len = A_LEN; 361 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len); 362 wh = ptrace_sethwdebug(child_pid, &info); 363 ptrace(PTRACE_CONT, child_pid, NULL, 0); 364 check_success(child_pid, name, "RO", wp_addr, len); 365 ptrace_delhwdebug(child_pid, wh); 366 367 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */ 368 wp_addr = (unsigned long)&gstruct.a; 369 len = A_LEN; 370 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); 371 wh = ptrace_sethwdebug(child_pid, &info); 372 ptrace(PTRACE_CONT, child_pid, NULL, 0); 373 check_success(child_pid, name, "RW", wp_addr, len); 374 ptrace_delhwdebug(child_pid, wh); 375 } 376 377 static void test_sethwdebug_range_unaligned(pid_t child_pid) 378 { 379 struct ppc_hw_breakpoint info; 380 unsigned long wp_addr; 381 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED"; 382 int len; 383 int wh; 384 385 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */ 386 wp_addr = (unsigned long)&gstruct.b; 387 len = B_LEN; 388 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len); 389 wh = ptrace_sethwdebug(child_pid, &info); 390 ptrace(PTRACE_CONT, child_pid, NULL, 0); 391 check_success(child_pid, name, "WO", wp_addr, len); 392 ptrace_delhwdebug(child_pid, wh); 393 394 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */ 395 wp_addr = (unsigned long)&gstruct.b; 396 len = B_LEN; 397 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len); 398 wh = ptrace_sethwdebug(child_pid, &info); 399 ptrace(PTRACE_CONT, child_pid, NULL, 0); 400 check_success(child_pid, name, "RO", wp_addr, len); 401 ptrace_delhwdebug(child_pid, wh); 402 403 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */ 404 wp_addr = (unsigned long)&gstruct.b; 405 len = B_LEN; 406 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); 407 wh = ptrace_sethwdebug(child_pid, &info); 408 ptrace(PTRACE_CONT, child_pid, NULL, 0); 409 check_success(child_pid, name, "RW", wp_addr, len); 410 ptrace_delhwdebug(child_pid, wh); 411 412 } 413 414 static void test_sethwdebug_range_unaligned_dar(pid_t child_pid) 415 { 416 struct ppc_hw_breakpoint info; 417 unsigned long wp_addr; 418 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE"; 419 int len; 420 int wh; 421 422 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */ 423 wp_addr = (unsigned long)&gstruct.b; 424 len = B_LEN; 425 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len); 426 wh = ptrace_sethwdebug(child_pid, &info); 427 ptrace(PTRACE_CONT, child_pid, NULL, 0); 428 check_success(child_pid, name, "RW", wp_addr, len); 429 ptrace_delhwdebug(child_pid, wh); 430 } 431 432 static void test_sethwdebug_dawr_max_range(pid_t child_pid) 433 { 434 struct ppc_hw_breakpoint info; 435 unsigned long wp_addr; 436 char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN"; 437 int len; 438 int wh; 439 440 /* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */ 441 wp_addr = (unsigned long)big_var; 442 len = DAWR_MAX_LEN; 443 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); 444 wh = ptrace_sethwdebug(child_pid, &info); 445 ptrace(PTRACE_CONT, child_pid, NULL, 0); 446 check_success(child_pid, name, "RW", wp_addr, len); 447 ptrace_delhwdebug(child_pid, wh); 448 } 449 450 /* Set the breakpoints and check the child successfully trigger them */ 451 static void 452 run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr) 453 { 454 test_set_debugreg(child_pid); 455 if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) { 456 test_sethwdebug_exact(child_pid); 457 458 test_sethwdebug_range_aligned(child_pid); 459 if (dawr || is_8xx) { 460 test_sethwdebug_range_unaligned(child_pid); 461 test_sethwdebug_range_unaligned_dar(child_pid); 462 test_sethwdebug_dawr_max_range(child_pid); 463 } 464 } 465 } 466 467 static int ptrace_hwbreak(void) 468 { 469 pid_t child_pid; 470 struct ppc_debug_info dbginfo; 471 bool dawr; 472 473 child_pid = fork(); 474 if (!child_pid) { 475 test_workload(); 476 return 0; 477 } 478 479 wait(NULL); 480 481 get_dbginfo(child_pid, &dbginfo); 482 SKIP_IF(dbginfo.num_data_bps == 0); 483 484 dawr = dawr_present(&dbginfo); 485 run_tests(child_pid, &dbginfo, dawr); 486 487 /* Let the child exit first. */ 488 ptrace(PTRACE_CONT, child_pid, NULL, 0); 489 wait(NULL); 490 491 /* 492 * Testcases exits immediately with -1 on any failure. If 493 * it has reached here, it means all tests were successful. 494 */ 495 return TEST_PASS; 496 } 497 498 int main(int argc, char **argv, char **envp) 499 { 500 int pvr = 0; 501 asm __volatile__ ("mfspr %0,%1" : "=r"(pvr) : "i"(SPRN_PVR)); 502 if (pvr == PVR_8xx) 503 is_8xx = true; 504 505 return test_harness(ptrace_hwbreak, "ptrace-hwbreak"); 506 } 507