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