linux/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c
<<
>>
Prefs
   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}
 630