628 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3/*4 * Ptrace test for hw breakpoints5 *6 * Based on tools/testing/selftests/breakpoints/breakpoint_test.c7 *8 * This test forks and the parent then traces the child doing various9 * types of ptrace enabled breakpoints10 *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 0x11F29#define PVR_8xx 0x0050000030 31bool is_8xx;32 33/*34 * Use volatile on all global var so that compiler doesn't35 * optimise their load/stores. Otherwise selftest can fail.36 */37static volatile __u64 glvar;38 39#define DAWR_MAX_LEN 51240static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));41 42#define A_LEN 643#define B_LEN 644struct gstruct {45 __u8 a[A_LEN]; /* double word aligned */46 __u8 b[B_LEN]; /* double word unaligned */47};48static volatile struct gstruct gstruct __attribute__((aligned(512)));49 50static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));51 52static 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 60static bool dawr_present(struct ppc_debug_info *dbginfo)61{62 return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);63}64 65static 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 92static 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 115static 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 else142 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 else158 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 else173 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 else185 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 else191 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 else197 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 212static 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 generated238 * before executing load/store. Singlestep the instruction239 * and then continue the test.240 */241 ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);242 wait(NULL);243 }244}245 246static 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 254static 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 265static 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 0274#define DABR_WRITE_SHIFT 1275#define DABR_TRANSLATION_SHIFT 2276 277static 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 318static 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 336static 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 else348 info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;349}350 351static 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 381static 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 397static 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 433static 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 465static 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 496static 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 533static 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 551static 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 */570static void571run_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 591static 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. If617 * it has reached here, it means all tests were successful.618 */619 return TEST_PASS;620}621 622int 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