Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 /*
0004  * Ptrace test for hw breakpoints
0005  *
0006  * Based on tools/testing/selftests/breakpoints/breakpoint_test.c
0007  *
0008  * This test forks and the parent then traces the child doing various
0009  * types of ptrace enabled breakpoints
0010  *
0011  * Copyright (C) 2018 Michael Neuling, IBM Corporation.
0012  */
0013 
0014 #include <sys/ptrace.h>
0015 #include <unistd.h>
0016 #include <stddef.h>
0017 #include <sys/user.h>
0018 #include <stdio.h>
0019 #include <stdlib.h>
0020 #include <signal.h>
0021 #include <sys/types.h>
0022 #include <sys/wait.h>
0023 #include <sys/syscall.h>
0024 #include <linux/limits.h>
0025 #include "ptrace.h"
0026 
0027 #define SPRN_PVR    0x11F
0028 #define PVR_8xx     0x00500000
0029 
0030 bool is_8xx;
0031 
0032 /*
0033  * Use volatile on all global var so that compiler doesn't
0034  * optimise their load/stores. Otherwise selftest can fail.
0035  */
0036 static volatile __u64 glvar;
0037 
0038 #define DAWR_MAX_LEN 512
0039 static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));
0040 
0041 #define A_LEN 6
0042 #define B_LEN 6
0043 struct gstruct {
0044     __u8 a[A_LEN]; /* double word aligned */
0045     __u8 b[B_LEN]; /* double word unaligned */
0046 };
0047 static volatile struct gstruct gstruct __attribute__((aligned(512)));
0048 
0049 static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));
0050 
0051 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
0052 {
0053     if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
0054         perror("Can't get breakpoint info");
0055         exit(-1);
0056     }
0057 }
0058 
0059 static bool dawr_present(struct ppc_debug_info *dbginfo)
0060 {
0061     return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
0062 }
0063 
0064 static void write_var(int len)
0065 {
0066     __u8 *pcvar;
0067     __u16 *psvar;
0068     __u32 *pivar;
0069     __u64 *plvar;
0070 
0071     switch (len) {
0072     case 1:
0073         pcvar = (__u8 *)&glvar;
0074         *pcvar = 0xff;
0075         break;
0076     case 2:
0077         psvar = (__u16 *)&glvar;
0078         *psvar = 0xffff;
0079         break;
0080     case 4:
0081         pivar = (__u32 *)&glvar;
0082         *pivar = 0xffffffff;
0083         break;
0084     case 8:
0085         plvar = (__u64 *)&glvar;
0086         *plvar = 0xffffffffffffffffLL;
0087         break;
0088     }
0089 }
0090 
0091 static void read_var(int len)
0092 {
0093     __u8 cvar __attribute__((unused));
0094     __u16 svar __attribute__((unused));
0095     __u32 ivar __attribute__((unused));
0096     __u64 lvar __attribute__((unused));
0097 
0098     switch (len) {
0099     case 1:
0100         cvar = (__u8)glvar;
0101         break;
0102     case 2:
0103         svar = (__u16)glvar;
0104         break;
0105     case 4:
0106         ivar = (__u32)glvar;
0107         break;
0108     case 8:
0109         lvar = (__u64)glvar;
0110         break;
0111     }
0112 }
0113 
0114 static void test_workload(void)
0115 {
0116     __u8 cvar __attribute__((unused));
0117     __u32 ivar __attribute__((unused));
0118     int len = 0;
0119 
0120     if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) {
0121         perror("Child can't be traced?");
0122         exit(-1);
0123     }
0124 
0125     /* Wake up father so that it sets up the first test */
0126     kill(getpid(), SIGUSR1);
0127 
0128     /* PTRACE_SET_DEBUGREG, WO test */
0129     for (len = 1; len <= sizeof(glvar); len <<= 1)
0130         write_var(len);
0131 
0132     /* PTRACE_SET_DEBUGREG, RO test */
0133     for (len = 1; len <= sizeof(glvar); len <<= 1)
0134         read_var(len);
0135 
0136     /* PTRACE_SET_DEBUGREG, RW test */
0137     for (len = 1; len <= sizeof(glvar); len <<= 1) {
0138         if (rand() % 2)
0139             read_var(len);
0140         else
0141             write_var(len);
0142     }
0143 
0144     /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
0145     syscall(__NR_getcwd, &cwd, PATH_MAX);
0146 
0147     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
0148     write_var(1);
0149 
0150     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
0151     read_var(1);
0152 
0153     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
0154     if (rand() % 2)
0155         write_var(1);
0156     else
0157         read_var(1);
0158 
0159     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
0160     syscall(__NR_getcwd, &cwd, PATH_MAX);
0161 
0162     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
0163     gstruct.a[rand() % A_LEN] = 'a';
0164 
0165     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
0166     cvar = gstruct.a[rand() % A_LEN];
0167 
0168     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
0169     if (rand() % 2)
0170         gstruct.a[rand() % A_LEN] = 'a';
0171     else
0172         cvar = gstruct.a[rand() % A_LEN];
0173 
0174     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
0175     gstruct.b[rand() % B_LEN] = 'b';
0176 
0177     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
0178     cvar = gstruct.b[rand() % B_LEN];
0179 
0180     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
0181     if (rand() % 2)
0182         gstruct.b[rand() % B_LEN] = 'b';
0183     else
0184         cvar = gstruct.b[rand() % B_LEN];
0185 
0186     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
0187     if (rand() % 2)
0188         *((int *)(gstruct.a + 4)) = 10;
0189     else
0190         ivar = *((int *)(gstruct.a + 4));
0191 
0192     /* PPC_PTRACE_SETHWDEBUG. DAWR_MAX_LEN. RW test */
0193     if (rand() % 2)
0194         big_var[rand() % DAWR_MAX_LEN] = 'a';
0195     else
0196         cvar = big_var[rand() % DAWR_MAX_LEN];
0197 
0198     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
0199     gstruct.a[rand() % A_LEN] = 'a';
0200 
0201     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
0202     cvar = gstruct.b[rand() % B_LEN];
0203 
0204     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
0205     gstruct.a[rand() % A_LEN] = 'a';
0206 
0207     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
0208     cvar = gstruct.a[rand() % A_LEN];
0209 }
0210 
0211 static void check_success(pid_t child_pid, const char *name, const char *type,
0212               unsigned long saddr, int len)
0213 {
0214     int status;
0215     siginfo_t siginfo;
0216     unsigned long eaddr = (saddr + len - 1) | 0x7;
0217 
0218     saddr &= ~0x7;
0219 
0220     /* Wait for the child to SIGTRAP */
0221     wait(&status);
0222 
0223     ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo);
0224 
0225     if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
0226         (unsigned long)siginfo.si_addr < saddr ||
0227         (unsigned long)siginfo.si_addr > eaddr) {
0228         printf("%s, %s, len: %d: Fail\n", name, type, len);
0229         exit(-1);
0230     }
0231 
0232     printf("%s, %s, len: %d: Ok\n", name, type, len);
0233 
0234     if (!is_8xx) {
0235         /*
0236          * For ptrace registered watchpoint, signal is generated
0237          * before executing load/store. Singlestep the instruction
0238          * and then continue the test.
0239          */
0240         ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);
0241         wait(NULL);
0242     }
0243 }
0244 
0245 static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr)
0246 {
0247     if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) {
0248         perror("PTRACE_SET_DEBUGREG failed");
0249         exit(-1);
0250     }
0251 }
0252 
0253 static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info)
0254 {
0255     int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info);
0256 
0257     if (wh <= 0) {
0258         perror("PPC_PTRACE_SETHWDEBUG failed");
0259         exit(-1);
0260     }
0261     return wh;
0262 }
0263 
0264 static void ptrace_delhwdebug(pid_t child_pid, int wh)
0265 {
0266     if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) {
0267         perror("PPC_PTRACE_DELHWDEBUG failed");
0268         exit(-1);
0269     }
0270 }
0271 
0272 #define DABR_READ_SHIFT     0
0273 #define DABR_WRITE_SHIFT    1
0274 #define DABR_TRANSLATION_SHIFT  2
0275 
0276 static int test_set_debugreg(pid_t child_pid)
0277 {
0278     unsigned long wp_addr = (unsigned long)&glvar;
0279     char *name = "PTRACE_SET_DEBUGREG";
0280     int len;
0281 
0282     /* PTRACE_SET_DEBUGREG, WO test*/
0283     wp_addr &= ~0x7UL;
0284     wp_addr |= (1UL << DABR_WRITE_SHIFT);
0285     wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
0286     for (len = 1; len <= sizeof(glvar); len <<= 1) {
0287         ptrace_set_debugreg(child_pid, wp_addr);
0288         ptrace(PTRACE_CONT, child_pid, NULL, 0);
0289         check_success(child_pid, name, "WO", wp_addr, len);
0290     }
0291 
0292     /* PTRACE_SET_DEBUGREG, RO test */
0293     wp_addr &= ~0x7UL;
0294     wp_addr |= (1UL << DABR_READ_SHIFT);
0295     wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
0296     for (len = 1; len <= sizeof(glvar); len <<= 1) {
0297         ptrace_set_debugreg(child_pid, wp_addr);
0298         ptrace(PTRACE_CONT, child_pid, NULL, 0);
0299         check_success(child_pid, name, "RO", wp_addr, len);
0300     }
0301 
0302     /* PTRACE_SET_DEBUGREG, RW test */
0303     wp_addr &= ~0x7UL;
0304     wp_addr |= (1Ul << DABR_READ_SHIFT);
0305     wp_addr |= (1UL << DABR_WRITE_SHIFT);
0306     wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
0307     for (len = 1; len <= sizeof(glvar); len <<= 1) {
0308         ptrace_set_debugreg(child_pid, wp_addr);
0309         ptrace(PTRACE_CONT, child_pid, NULL, 0);
0310         check_success(child_pid, name, "RW", wp_addr, len);
0311     }
0312 
0313     ptrace_set_debugreg(child_pid, 0);
0314     return 0;
0315 }
0316 
0317 static int test_set_debugreg_kernel_userspace(pid_t child_pid)
0318 {
0319     unsigned long wp_addr = (unsigned long)cwd;
0320     char *name = "PTRACE_SET_DEBUGREG";
0321 
0322     /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
0323     wp_addr &= ~0x7UL;
0324     wp_addr |= (1Ul << DABR_READ_SHIFT);
0325     wp_addr |= (1UL << DABR_WRITE_SHIFT);
0326     wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
0327     ptrace_set_debugreg(child_pid, wp_addr);
0328     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0329     check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8);
0330 
0331     ptrace_set_debugreg(child_pid, 0);
0332     return 0;
0333 }
0334 
0335 static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
0336                   unsigned long addr, int len)
0337 {
0338     info->version = 1;
0339     info->trigger_type = type;
0340     info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
0341     info->addr = (__u64)addr;
0342     info->addr2 = (__u64)addr + len;
0343     info->condition_value = 0;
0344     if (!len)
0345         info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
0346     else
0347         info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
0348 }
0349 
0350 static void test_sethwdebug_exact(pid_t child_pid)
0351 {
0352     struct ppc_hw_breakpoint info;
0353     unsigned long wp_addr = (unsigned long)&glvar;
0354     char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
0355     int len = 1; /* hardcoded in kernel */
0356     int wh;
0357 
0358     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
0359     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
0360     wh = ptrace_sethwdebug(child_pid, &info);
0361     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0362     check_success(child_pid, name, "WO", wp_addr, len);
0363     ptrace_delhwdebug(child_pid, wh);
0364 
0365     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
0366     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0);
0367     wh = ptrace_sethwdebug(child_pid, &info);
0368     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0369     check_success(child_pid, name, "RO", wp_addr, len);
0370     ptrace_delhwdebug(child_pid, wh);
0371 
0372     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
0373     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0);
0374     wh = ptrace_sethwdebug(child_pid, &info);
0375     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0376     check_success(child_pid, name, "RW", wp_addr, len);
0377     ptrace_delhwdebug(child_pid, wh);
0378 }
0379 
0380 static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid)
0381 {
0382     struct ppc_hw_breakpoint info;
0383     unsigned long wp_addr = (unsigned long)&cwd;
0384     char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
0385     int len = 1; /* hardcoded in kernel */
0386     int wh;
0387 
0388     /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
0389     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
0390     wh = ptrace_sethwdebug(child_pid, &info);
0391     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0392     check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len);
0393     ptrace_delhwdebug(child_pid, wh);
0394 }
0395 
0396 static void test_sethwdebug_range_aligned(pid_t child_pid)
0397 {
0398     struct ppc_hw_breakpoint info;
0399     unsigned long wp_addr;
0400     char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED";
0401     int len;
0402     int wh;
0403 
0404     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
0405     wp_addr = (unsigned long)&gstruct.a;
0406     len = A_LEN;
0407     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
0408     wh = ptrace_sethwdebug(child_pid, &info);
0409     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0410     check_success(child_pid, name, "WO", wp_addr, len);
0411     ptrace_delhwdebug(child_pid, wh);
0412 
0413     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
0414     wp_addr = (unsigned long)&gstruct.a;
0415     len = A_LEN;
0416     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
0417     wh = ptrace_sethwdebug(child_pid, &info);
0418     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0419     check_success(child_pid, name, "RO", wp_addr, len);
0420     ptrace_delhwdebug(child_pid, wh);
0421 
0422     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
0423     wp_addr = (unsigned long)&gstruct.a;
0424     len = A_LEN;
0425     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
0426     wh = ptrace_sethwdebug(child_pid, &info);
0427     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0428     check_success(child_pid, name, "RW", wp_addr, len);
0429     ptrace_delhwdebug(child_pid, wh);
0430 }
0431 
0432 static void test_multi_sethwdebug_range(pid_t child_pid)
0433 {
0434     struct ppc_hw_breakpoint info1, info2;
0435     unsigned long wp_addr1, wp_addr2;
0436     char *name1 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED";
0437     char *name2 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED";
0438     int len1, len2;
0439     int wh1, wh2;
0440 
0441     wp_addr1 = (unsigned long)&gstruct.a;
0442     wp_addr2 = (unsigned long)&gstruct.b;
0443     len1 = A_LEN;
0444     len2 = B_LEN;
0445     get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
0446     get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
0447 
0448     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
0449     wh1 = ptrace_sethwdebug(child_pid, &info1);
0450 
0451     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
0452     wh2 = ptrace_sethwdebug(child_pid, &info2);
0453 
0454     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0455     check_success(child_pid, name1, "WO", wp_addr1, len1);
0456 
0457     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0458     check_success(child_pid, name2, "RO", wp_addr2, len2);
0459 
0460     ptrace_delhwdebug(child_pid, wh1);
0461     ptrace_delhwdebug(child_pid, wh2);
0462 }
0463 
0464 static void test_multi_sethwdebug_range_dawr_overlap(pid_t child_pid)
0465 {
0466     struct ppc_hw_breakpoint info1, info2;
0467     unsigned long wp_addr1, wp_addr2;
0468     char *name = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap";
0469     int len1, len2;
0470     int wh1, wh2;
0471 
0472     wp_addr1 = (unsigned long)&gstruct.a;
0473     wp_addr2 = (unsigned long)&gstruct.a;
0474     len1 = A_LEN;
0475     len2 = A_LEN;
0476     get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
0477     get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
0478 
0479     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
0480     wh1 = ptrace_sethwdebug(child_pid, &info1);
0481 
0482     /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
0483     wh2 = ptrace_sethwdebug(child_pid, &info2);
0484 
0485     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0486     check_success(child_pid, name, "WO", wp_addr1, len1);
0487 
0488     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0489     check_success(child_pid, name, "RO", wp_addr2, len2);
0490 
0491     ptrace_delhwdebug(child_pid, wh1);
0492     ptrace_delhwdebug(child_pid, wh2);
0493 }
0494 
0495 static void test_sethwdebug_range_unaligned(pid_t child_pid)
0496 {
0497     struct ppc_hw_breakpoint info;
0498     unsigned long wp_addr;
0499     char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED";
0500     int len;
0501     int wh;
0502 
0503     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
0504     wp_addr = (unsigned long)&gstruct.b;
0505     len = B_LEN;
0506     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
0507     wh = ptrace_sethwdebug(child_pid, &info);
0508     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0509     check_success(child_pid, name, "WO", wp_addr, len);
0510     ptrace_delhwdebug(child_pid, wh);
0511 
0512     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
0513     wp_addr = (unsigned long)&gstruct.b;
0514     len = B_LEN;
0515     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
0516     wh = ptrace_sethwdebug(child_pid, &info);
0517     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0518     check_success(child_pid, name, "RO", wp_addr, len);
0519     ptrace_delhwdebug(child_pid, wh);
0520 
0521     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
0522     wp_addr = (unsigned long)&gstruct.b;
0523     len = B_LEN;
0524     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
0525     wh = ptrace_sethwdebug(child_pid, &info);
0526     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0527     check_success(child_pid, name, "RW", wp_addr, len);
0528     ptrace_delhwdebug(child_pid, wh);
0529 
0530 }
0531 
0532 static void test_sethwdebug_range_unaligned_dar(pid_t child_pid)
0533 {
0534     struct ppc_hw_breakpoint info;
0535     unsigned long wp_addr;
0536     char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE";
0537     int len;
0538     int wh;
0539 
0540     /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
0541     wp_addr = (unsigned long)&gstruct.b;
0542     len = B_LEN;
0543     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
0544     wh = ptrace_sethwdebug(child_pid, &info);
0545     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0546     check_success(child_pid, name, "RW", wp_addr, len);
0547     ptrace_delhwdebug(child_pid, wh);
0548 }
0549 
0550 static void test_sethwdebug_dawr_max_range(pid_t child_pid)
0551 {
0552     struct ppc_hw_breakpoint info;
0553     unsigned long wp_addr;
0554     char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN";
0555     int len;
0556     int wh;
0557 
0558     /* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */
0559     wp_addr = (unsigned long)big_var;
0560     len = DAWR_MAX_LEN;
0561     get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
0562     wh = ptrace_sethwdebug(child_pid, &info);
0563     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0564     check_success(child_pid, name, "RW", wp_addr, len);
0565     ptrace_delhwdebug(child_pid, wh);
0566 }
0567 
0568 /* Set the breakpoints and check the child successfully trigger them */
0569 static void
0570 run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr)
0571 {
0572     test_set_debugreg(child_pid);
0573     test_set_debugreg_kernel_userspace(child_pid);
0574     test_sethwdebug_exact(child_pid);
0575     test_sethwdebug_exact_kernel_userspace(child_pid);
0576     if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) {
0577         test_sethwdebug_range_aligned(child_pid);
0578         if (dawr || is_8xx) {
0579             test_sethwdebug_range_unaligned(child_pid);
0580             test_sethwdebug_range_unaligned_dar(child_pid);
0581             test_sethwdebug_dawr_max_range(child_pid);
0582             if (dbginfo->num_data_bps > 1) {
0583                 test_multi_sethwdebug_range(child_pid);
0584                 test_multi_sethwdebug_range_dawr_overlap(child_pid);
0585             }
0586         }
0587     }
0588 }
0589 
0590 static int ptrace_hwbreak(void)
0591 {
0592     pid_t child_pid;
0593     struct ppc_debug_info dbginfo;
0594     bool dawr;
0595 
0596     child_pid = fork();
0597     if (!child_pid) {
0598         test_workload();
0599         return 0;
0600     }
0601 
0602     wait(NULL);
0603 
0604     get_dbginfo(child_pid, &dbginfo);
0605     SKIP_IF(dbginfo.num_data_bps == 0);
0606 
0607     dawr = dawr_present(&dbginfo);
0608     run_tests(child_pid, &dbginfo, dawr);
0609 
0610     /* Let the child exit first. */
0611     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0612     wait(NULL);
0613 
0614     /*
0615      * Testcases exits immediately with -1 on any failure. If
0616      * it has reached here, it means all tests were successful.
0617      */
0618     return TEST_PASS;
0619 }
0620 
0621 int main(int argc, char **argv, char **envp)
0622 {
0623     int pvr = 0;
0624     asm __volatile__ ("mfspr %0,%1" : "=r"(pvr) : "i"(SPRN_PVR));
0625     if (pvr == PVR_8xx)
0626         is_8xx = true;
0627 
0628     return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
0629 }