ptrace-hwbreak.c (17598B)
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 30bool 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 */ 36static volatile __u64 glvar; 37 38#define DAWR_MAX_LEN 512 39static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512))); 40 41#define A_LEN 6 42#define B_LEN 6 43struct gstruct { 44 __u8 a[A_LEN]; /* double word aligned */ 45 __u8 b[B_LEN]; /* double word unaligned */ 46}; 47static volatile struct gstruct gstruct __attribute__((aligned(512))); 48 49static volatile char cwd[PATH_MAX] __attribute__((aligned(8))); 50 51static 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 59static bool dawr_present(struct ppc_debug_info *dbginfo) 60{ 61 return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR); 62} 63 64static 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 91static 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 114static 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 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */ 199 gstruct.a[rand() % A_LEN] = 'a'; 200 201 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */ 202 cvar = gstruct.b[rand() % B_LEN]; 203 204 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */ 205 gstruct.a[rand() % A_LEN] = 'a'; 206 207 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */ 208 cvar = gstruct.a[rand() % A_LEN]; 209} 210 211static void check_success(pid_t child_pid, const char *name, const char *type, 212 unsigned long saddr, int len) 213{ 214 int status; 215 siginfo_t siginfo; 216 unsigned long eaddr = (saddr + len - 1) | 0x7; 217 218 saddr &= ~0x7; 219 220 /* Wait for the child to SIGTRAP */ 221 wait(&status); 222 223 ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo); 224 225 if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP || 226 (unsigned long)siginfo.si_addr < saddr || 227 (unsigned long)siginfo.si_addr > eaddr) { 228 printf("%s, %s, len: %d: Fail\n", name, type, len); 229 exit(-1); 230 } 231 232 printf("%s, %s, len: %d: Ok\n", name, type, len); 233 234 if (!is_8xx) { 235 /* 236 * For ptrace registered watchpoint, signal is generated 237 * before executing load/store. Singlestep the instruction 238 * and then continue the test. 239 */ 240 ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0); 241 wait(NULL); 242 } 243} 244 245static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr) 246{ 247 if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) { 248 perror("PTRACE_SET_DEBUGREG failed"); 249 exit(-1); 250 } 251} 252 253static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info) 254{ 255 int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info); 256 257 if (wh <= 0) { 258 perror("PPC_PTRACE_SETHWDEBUG failed"); 259 exit(-1); 260 } 261 return wh; 262} 263 264static void ptrace_delhwdebug(pid_t child_pid, int wh) 265{ 266 if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) { 267 perror("PPC_PTRACE_DELHWDEBUG failed"); 268 exit(-1); 269 } 270} 271 272#define DABR_READ_SHIFT 0 273#define DABR_WRITE_SHIFT 1 274#define DABR_TRANSLATION_SHIFT 2 275 276static int test_set_debugreg(pid_t child_pid) 277{ 278 unsigned long wp_addr = (unsigned long)&glvar; 279 char *name = "PTRACE_SET_DEBUGREG"; 280 int len; 281 282 /* PTRACE_SET_DEBUGREG, WO test*/ 283 wp_addr &= ~0x7UL; 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, "WO", wp_addr, len); 290 } 291 292 /* PTRACE_SET_DEBUGREG, RO test */ 293 wp_addr &= ~0x7UL; 294 wp_addr |= (1UL << DABR_READ_SHIFT); 295 wp_addr |= (1UL << DABR_TRANSLATION_SHIFT); 296 for (len = 1; len <= sizeof(glvar); len <<= 1) { 297 ptrace_set_debugreg(child_pid, wp_addr); 298 ptrace(PTRACE_CONT, child_pid, NULL, 0); 299 check_success(child_pid, name, "RO", wp_addr, len); 300 } 301 302 /* PTRACE_SET_DEBUGREG, RW test */ 303 wp_addr &= ~0x7UL; 304 wp_addr |= (1Ul << DABR_READ_SHIFT); 305 wp_addr |= (1UL << DABR_WRITE_SHIFT); 306 wp_addr |= (1UL << DABR_TRANSLATION_SHIFT); 307 for (len = 1; len <= sizeof(glvar); len <<= 1) { 308 ptrace_set_debugreg(child_pid, wp_addr); 309 ptrace(PTRACE_CONT, child_pid, NULL, 0); 310 check_success(child_pid, name, "RW", wp_addr, len); 311 } 312 313 ptrace_set_debugreg(child_pid, 0); 314 return 0; 315} 316 317static int test_set_debugreg_kernel_userspace(pid_t child_pid) 318{ 319 unsigned long wp_addr = (unsigned long)cwd; 320 char *name = "PTRACE_SET_DEBUGREG"; 321 322 /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */ 323 wp_addr &= ~0x7UL; 324 wp_addr |= (1Ul << DABR_READ_SHIFT); 325 wp_addr |= (1UL << DABR_WRITE_SHIFT); 326 wp_addr |= (1UL << DABR_TRANSLATION_SHIFT); 327 ptrace_set_debugreg(child_pid, wp_addr); 328 ptrace(PTRACE_CONT, child_pid, NULL, 0); 329 check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8); 330 331 ptrace_set_debugreg(child_pid, 0); 332 return 0; 333} 334 335static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type, 336 unsigned long addr, int len) 337{ 338 info->version = 1; 339 info->trigger_type = type; 340 info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE; 341 info->addr = (__u64)addr; 342 info->addr2 = (__u64)addr + len; 343 info->condition_value = 0; 344 if (!len) 345 info->addr_mode = PPC_BREAKPOINT_MODE_EXACT; 346 else 347 info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE; 348} 349 350static void test_sethwdebug_exact(pid_t child_pid) 351{ 352 struct ppc_hw_breakpoint info; 353 unsigned long wp_addr = (unsigned long)&glvar; 354 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT"; 355 int len = 1; /* hardcoded in kernel */ 356 int wh; 357 358 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */ 359 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0); 360 wh = ptrace_sethwdebug(child_pid, &info); 361 ptrace(PTRACE_CONT, child_pid, NULL, 0); 362 check_success(child_pid, name, "WO", wp_addr, len); 363 ptrace_delhwdebug(child_pid, wh); 364 365 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */ 366 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0); 367 wh = ptrace_sethwdebug(child_pid, &info); 368 ptrace(PTRACE_CONT, child_pid, NULL, 0); 369 check_success(child_pid, name, "RO", wp_addr, len); 370 ptrace_delhwdebug(child_pid, wh); 371 372 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */ 373 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0); 374 wh = ptrace_sethwdebug(child_pid, &info); 375 ptrace(PTRACE_CONT, child_pid, NULL, 0); 376 check_success(child_pid, name, "RW", wp_addr, len); 377 ptrace_delhwdebug(child_pid, wh); 378} 379 380static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid) 381{ 382 struct ppc_hw_breakpoint info; 383 unsigned long wp_addr = (unsigned long)&cwd; 384 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT"; 385 int len = 1; /* hardcoded in kernel */ 386 int wh; 387 388 /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */ 389 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0); 390 wh = ptrace_sethwdebug(child_pid, &info); 391 ptrace(PTRACE_CONT, child_pid, NULL, 0); 392 check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len); 393 ptrace_delhwdebug(child_pid, wh); 394} 395 396static void test_sethwdebug_range_aligned(pid_t child_pid) 397{ 398 struct ppc_hw_breakpoint info; 399 unsigned long wp_addr; 400 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED"; 401 int len; 402 int wh; 403 404 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */ 405 wp_addr = (unsigned long)&gstruct.a; 406 len = A_LEN; 407 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len); 408 wh = ptrace_sethwdebug(child_pid, &info); 409 ptrace(PTRACE_CONT, child_pid, NULL, 0); 410 check_success(child_pid, name, "WO", wp_addr, len); 411 ptrace_delhwdebug(child_pid, wh); 412 413 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */ 414 wp_addr = (unsigned long)&gstruct.a; 415 len = A_LEN; 416 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len); 417 wh = ptrace_sethwdebug(child_pid, &info); 418 ptrace(PTRACE_CONT, child_pid, NULL, 0); 419 check_success(child_pid, name, "RO", wp_addr, len); 420 ptrace_delhwdebug(child_pid, wh); 421 422 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */ 423 wp_addr = (unsigned long)&gstruct.a; 424 len = A_LEN; 425 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, 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 432static void test_multi_sethwdebug_range(pid_t child_pid) 433{ 434 struct ppc_hw_breakpoint info1, info2; 435 unsigned long wp_addr1, wp_addr2; 436 char *name1 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED"; 437 char *name2 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED"; 438 int len1, len2; 439 int wh1, wh2; 440 441 wp_addr1 = (unsigned long)&gstruct.a; 442 wp_addr2 = (unsigned long)&gstruct.b; 443 len1 = A_LEN; 444 len2 = B_LEN; 445 get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1); 446 get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2); 447 448 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */ 449 wh1 = ptrace_sethwdebug(child_pid, &info1); 450 451 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */ 452 wh2 = ptrace_sethwdebug(child_pid, &info2); 453 454 ptrace(PTRACE_CONT, child_pid, NULL, 0); 455 check_success(child_pid, name1, "WO", wp_addr1, len1); 456 457 ptrace(PTRACE_CONT, child_pid, NULL, 0); 458 check_success(child_pid, name2, "RO", wp_addr2, len2); 459 460 ptrace_delhwdebug(child_pid, wh1); 461 ptrace_delhwdebug(child_pid, wh2); 462} 463 464static void test_multi_sethwdebug_range_dawr_overlap(pid_t child_pid) 465{ 466 struct ppc_hw_breakpoint info1, info2; 467 unsigned long wp_addr1, wp_addr2; 468 char *name = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap"; 469 int len1, len2; 470 int wh1, wh2; 471 472 wp_addr1 = (unsigned long)&gstruct.a; 473 wp_addr2 = (unsigned long)&gstruct.a; 474 len1 = A_LEN; 475 len2 = A_LEN; 476 get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1); 477 get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2); 478 479 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */ 480 wh1 = ptrace_sethwdebug(child_pid, &info1); 481 482 /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */ 483 wh2 = ptrace_sethwdebug(child_pid, &info2); 484 485 ptrace(PTRACE_CONT, child_pid, NULL, 0); 486 check_success(child_pid, name, "WO", wp_addr1, len1); 487 488 ptrace(PTRACE_CONT, child_pid, NULL, 0); 489 check_success(child_pid, name, "RO", wp_addr2, len2); 490 491 ptrace_delhwdebug(child_pid, wh1); 492 ptrace_delhwdebug(child_pid, wh2); 493} 494 495static void test_sethwdebug_range_unaligned(pid_t child_pid) 496{ 497 struct ppc_hw_breakpoint info; 498 unsigned long wp_addr; 499 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED"; 500 int len; 501 int wh; 502 503 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */ 504 wp_addr = (unsigned long)&gstruct.b; 505 len = B_LEN; 506 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len); 507 wh = ptrace_sethwdebug(child_pid, &info); 508 ptrace(PTRACE_CONT, child_pid, NULL, 0); 509 check_success(child_pid, name, "WO", wp_addr, len); 510 ptrace_delhwdebug(child_pid, wh); 511 512 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */ 513 wp_addr = (unsigned long)&gstruct.b; 514 len = B_LEN; 515 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len); 516 wh = ptrace_sethwdebug(child_pid, &info); 517 ptrace(PTRACE_CONT, child_pid, NULL, 0); 518 check_success(child_pid, name, "RO", wp_addr, len); 519 ptrace_delhwdebug(child_pid, wh); 520 521 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */ 522 wp_addr = (unsigned long)&gstruct.b; 523 len = B_LEN; 524 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); 525 wh = ptrace_sethwdebug(child_pid, &info); 526 ptrace(PTRACE_CONT, child_pid, NULL, 0); 527 check_success(child_pid, name, "RW", wp_addr, len); 528 ptrace_delhwdebug(child_pid, wh); 529 530} 531 532static void test_sethwdebug_range_unaligned_dar(pid_t child_pid) 533{ 534 struct ppc_hw_breakpoint info; 535 unsigned long wp_addr; 536 char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE"; 537 int len; 538 int wh; 539 540 /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */ 541 wp_addr = (unsigned long)&gstruct.b; 542 len = B_LEN; 543 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len); 544 wh = ptrace_sethwdebug(child_pid, &info); 545 ptrace(PTRACE_CONT, child_pid, NULL, 0); 546 check_success(child_pid, name, "RW", wp_addr, len); 547 ptrace_delhwdebug(child_pid, wh); 548} 549 550static void test_sethwdebug_dawr_max_range(pid_t child_pid) 551{ 552 struct ppc_hw_breakpoint info; 553 unsigned long wp_addr; 554 char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN"; 555 int len; 556 int wh; 557 558 /* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */ 559 wp_addr = (unsigned long)big_var; 560 len = DAWR_MAX_LEN; 561 get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len); 562 wh = ptrace_sethwdebug(child_pid, &info); 563 ptrace(PTRACE_CONT, child_pid, NULL, 0); 564 check_success(child_pid, name, "RW", wp_addr, len); 565 ptrace_delhwdebug(child_pid, wh); 566} 567 568/* Set the breakpoints and check the child successfully trigger them */ 569static void 570run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr) 571{ 572 test_set_debugreg(child_pid); 573 test_set_debugreg_kernel_userspace(child_pid); 574 test_sethwdebug_exact(child_pid); 575 test_sethwdebug_exact_kernel_userspace(child_pid); 576 if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) { 577 test_sethwdebug_range_aligned(child_pid); 578 if (dawr || is_8xx) { 579 test_sethwdebug_range_unaligned(child_pid); 580 test_sethwdebug_range_unaligned_dar(child_pid); 581 test_sethwdebug_dawr_max_range(child_pid); 582 if (dbginfo->num_data_bps > 1) { 583 test_multi_sethwdebug_range(child_pid); 584 test_multi_sethwdebug_range_dawr_overlap(child_pid); 585 } 586 } 587 } 588} 589 590static int ptrace_hwbreak(void) 591{ 592 pid_t child_pid; 593 struct ppc_debug_info dbginfo; 594 bool dawr; 595 596 child_pid = fork(); 597 if (!child_pid) { 598 test_workload(); 599 return 0; 600 } 601 602 wait(NULL); 603 604 get_dbginfo(child_pid, &dbginfo); 605 SKIP_IF(dbginfo.num_data_bps == 0); 606 607 dawr = dawr_present(&dbginfo); 608 run_tests(child_pid, &dbginfo, dawr); 609 610 /* Let the child exit first. */ 611 ptrace(PTRACE_CONT, child_pid, NULL, 0); 612 wait(NULL); 613 614 /* 615 * Testcases exits immediately with -1 on any failure. If 616 * it has reached here, it means all tests were successful. 617 */ 618 return TEST_PASS; 619} 620 621int main(int argc, char **argv, char **envp) 622{ 623 int pvr = 0; 624 asm __volatile__ ("mfspr %0,%1" : "=r"(pvr) : "i"(SPRN_PVR)); 625 if (pvr == PVR_8xx) 626 is_8xx = true; 627 628 return test_harness(ptrace_hwbreak, "ptrace-hwbreak"); 629}