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