linux/tools/testing/selftests/powerpc/ptrace/ptrace-perf-hwbreak.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2#include <stdio.h>
   3#include <string.h>
   4#include <signal.h>
   5#include <stdlib.h>
   6#include <unistd.h>
   7#include <errno.h>
   8#include <linux/hw_breakpoint.h>
   9#include <linux/perf_event.h>
  10#include <asm/unistd.h>
  11#include <sys/ptrace.h>
  12#include <sys/wait.h>
  13#include "ptrace.h"
  14
  15char data[16];
  16
  17/* Overlapping address range */
  18volatile __u64 *ptrace_data1 = (__u64 *)&data[0];
  19volatile __u64 *perf_data1 = (__u64 *)&data[4];
  20
  21/* Non-overlapping address range */
  22volatile __u64 *ptrace_data2 = (__u64 *)&data[0];
  23volatile __u64 *perf_data2 = (__u64 *)&data[8];
  24
  25static unsigned long pid_max_addr(void)
  26{
  27        FILE *fp;
  28        char *line, *c;
  29        char addr[100];
  30        size_t len = 0;
  31
  32        fp = fopen("/proc/kallsyms", "r");
  33        if (!fp) {
  34                printf("Failed to read /proc/kallsyms. Exiting..\n");
  35                exit(EXIT_FAILURE);
  36        }
  37
  38        while (getline(&line, &len, fp) != -1) {
  39                if (!strstr(line, "pid_max") || strstr(line, "pid_max_max") ||
  40                    strstr(line, "pid_max_min"))
  41                        continue;
  42
  43                strncpy(addr, line, len < 100 ? len : 100);
  44                c = strchr(addr, ' ');
  45                *c = '\0';
  46                return strtoul(addr, &c, 16);
  47        }
  48        fclose(fp);
  49        printf("Could not find pix_max. Exiting..\n");
  50        exit(EXIT_FAILURE);
  51        return -1;
  52}
  53
  54static void perf_user_event_attr_set(struct perf_event_attr *attr, __u64 addr, __u64 len)
  55{
  56        memset(attr, 0, sizeof(struct perf_event_attr));
  57        attr->type           = PERF_TYPE_BREAKPOINT;
  58        attr->size           = sizeof(struct perf_event_attr);
  59        attr->bp_type        = HW_BREAKPOINT_R;
  60        attr->bp_addr        = addr;
  61        attr->bp_len         = len;
  62        attr->exclude_kernel = 1;
  63        attr->exclude_hv     = 1;
  64}
  65
  66static void perf_kernel_event_attr_set(struct perf_event_attr *attr)
  67{
  68        memset(attr, 0, sizeof(struct perf_event_attr));
  69        attr->type           = PERF_TYPE_BREAKPOINT;
  70        attr->size           = sizeof(struct perf_event_attr);
  71        attr->bp_type        = HW_BREAKPOINT_R;
  72        attr->bp_addr        = pid_max_addr();
  73        attr->bp_len         = sizeof(unsigned long);
  74        attr->exclude_user   = 1;
  75        attr->exclude_hv     = 1;
  76}
  77
  78static int perf_cpu_event_open(int cpu, __u64 addr, __u64 len)
  79{
  80        struct perf_event_attr attr;
  81
  82        perf_user_event_attr_set(&attr, addr, len);
  83        return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
  84}
  85
  86static int perf_thread_event_open(pid_t child_pid, __u64 addr, __u64 len)
  87{
  88        struct perf_event_attr attr;
  89
  90        perf_user_event_attr_set(&attr, addr, len);
  91        return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
  92}
  93
  94static int perf_thread_cpu_event_open(pid_t child_pid, int cpu, __u64 addr, __u64 len)
  95{
  96        struct perf_event_attr attr;
  97
  98        perf_user_event_attr_set(&attr, addr, len);
  99        return syscall(__NR_perf_event_open, &attr, child_pid, cpu, -1, 0);
 100}
 101
 102static int perf_thread_kernel_event_open(pid_t child_pid)
 103{
 104        struct perf_event_attr attr;
 105
 106        perf_kernel_event_attr_set(&attr);
 107        return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
 108}
 109
 110static int perf_cpu_kernel_event_open(int cpu)
 111{
 112        struct perf_event_attr attr;
 113
 114        perf_kernel_event_attr_set(&attr);
 115        return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
 116}
 117
 118static int child(void)
 119{
 120        int ret;
 121
 122        ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
 123        if (ret) {
 124                printf("Error: PTRACE_TRACEME failed\n");
 125                return 0;
 126        }
 127        kill(getpid(), SIGUSR1); /* --> parent (SIGUSR1) */
 128
 129        return 0;
 130}
 131
 132static void ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
 133                                     __u64 addr, int len)
 134{
 135        info->version = 1;
 136        info->trigger_type = type;
 137        info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
 138        info->addr = addr;
 139        info->addr2 = addr + len;
 140        info->condition_value = 0;
 141        if (!len)
 142                info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
 143        else
 144                info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
 145}
 146
 147static int ptrace_open(pid_t child_pid, __u64 wp_addr, int len)
 148{
 149        struct ppc_hw_breakpoint info;
 150
 151        ptrace_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
 152        return ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
 153}
 154
 155static int test1(pid_t child_pid)
 156{
 157        int perf_fd;
 158        int ptrace_fd;
 159        int ret = 0;
 160
 161        /* Test:
 162         * if (new per thread event by ptrace)
 163         *      if (existing cpu event by perf)
 164         *              if (addr range overlaps)
 165         *                      fail;
 166         */
 167
 168        perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
 169        if (perf_fd < 0)
 170                return -1;
 171
 172        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 173        if (ptrace_fd > 0 || errno != ENOSPC)
 174                ret = -1;
 175
 176        close(perf_fd);
 177        return ret;
 178}
 179
 180static int test2(pid_t child_pid)
 181{
 182        int perf_fd;
 183        int ptrace_fd;
 184        int ret = 0;
 185
 186        /* Test:
 187         * if (new per thread event by ptrace)
 188         *      if (existing cpu event by perf)
 189         *              if (addr range does not overlaps)
 190         *                      allow;
 191         */
 192
 193        perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
 194        if (perf_fd < 0)
 195                return -1;
 196
 197        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
 198        if (ptrace_fd < 0) {
 199                ret = -1;
 200                goto perf_close;
 201        }
 202        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 203
 204perf_close:
 205        close(perf_fd);
 206        return ret;
 207}
 208
 209static int test3(pid_t child_pid)
 210{
 211        int perf_fd;
 212        int ptrace_fd;
 213        int ret = 0;
 214
 215        /* Test:
 216         * if (new per thread event by ptrace)
 217         *      if (existing thread event by perf on the same thread)
 218         *              if (addr range overlaps)
 219         *                      fail;
 220         */
 221        perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
 222                                         sizeof(*perf_data1));
 223        if (perf_fd < 0)
 224                return -1;
 225
 226        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 227        if (ptrace_fd > 0 || errno != ENOSPC)
 228                ret = -1;
 229
 230        close(perf_fd);
 231        return ret;
 232}
 233
 234static int test4(pid_t child_pid)
 235{
 236        int perf_fd;
 237        int ptrace_fd;
 238        int ret = 0;
 239
 240        /* Test:
 241         * if (new per thread event by ptrace)
 242         *      if (existing thread event by perf on the same thread)
 243         *              if (addr range does not overlaps)
 244         *                      fail;
 245         */
 246        perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
 247                                         sizeof(*perf_data2));
 248        if (perf_fd < 0)
 249                return -1;
 250
 251        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
 252        if (ptrace_fd < 0) {
 253                ret = -1;
 254                goto perf_close;
 255        }
 256        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 257
 258perf_close:
 259        close(perf_fd);
 260        return ret;
 261}
 262
 263static int test5(pid_t child_pid)
 264{
 265        int perf_fd;
 266        int ptrace_fd;
 267        int cpid;
 268        int ret = 0;
 269
 270        /* Test:
 271         * if (new per thread event by ptrace)
 272         *      if (existing thread event by perf on the different thread)
 273         *              allow;
 274         */
 275        cpid = fork();
 276        if (!cpid) {
 277                /* Temporary Child */
 278                pause();
 279                exit(EXIT_SUCCESS);
 280        }
 281
 282        perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
 283        if (perf_fd < 0) {
 284                ret = -1;
 285                goto kill_child;
 286        }
 287
 288        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 289        if (ptrace_fd < 0) {
 290                ret = -1;
 291                goto perf_close;
 292        }
 293
 294        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 295perf_close:
 296        close(perf_fd);
 297kill_child:
 298        kill(cpid, SIGINT);
 299        return ret;
 300}
 301
 302static int test6(pid_t child_pid)
 303{
 304        int perf_fd;
 305        int ptrace_fd;
 306        int ret = 0;
 307
 308        /* Test:
 309         * if (new per thread kernel event by perf)
 310         *      if (existing thread event by ptrace on the same thread)
 311         *              allow;
 312         * -- OR --
 313         * if (new per cpu kernel event by perf)
 314         *      if (existing thread event by ptrace)
 315         *              allow;
 316         */
 317        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 318        if (ptrace_fd < 0)
 319                return -1;
 320
 321        perf_fd = perf_thread_kernel_event_open(child_pid);
 322        if (perf_fd < 0) {
 323                ret = -1;
 324                goto ptrace_close;
 325        }
 326        close(perf_fd);
 327
 328        perf_fd = perf_cpu_kernel_event_open(0);
 329        if (perf_fd < 0) {
 330                ret = -1;
 331                goto ptrace_close;
 332        }
 333        close(perf_fd);
 334
 335ptrace_close:
 336        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 337        return ret;
 338}
 339
 340static int test7(pid_t child_pid)
 341{
 342        int perf_fd;
 343        int ptrace_fd;
 344        int ret = 0;
 345
 346        /* Test:
 347         * if (new per thread event by perf)
 348         *      if (existing thread event by ptrace on the same thread)
 349         *              if (addr range overlaps)
 350         *                      fail;
 351         */
 352        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 353        if (ptrace_fd < 0)
 354                return -1;
 355
 356        perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
 357                                         sizeof(*perf_data1));
 358        if (perf_fd > 0 || errno != ENOSPC)
 359                ret = -1;
 360
 361        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 362        return ret;
 363}
 364
 365static int test8(pid_t child_pid)
 366{
 367        int perf_fd;
 368        int ptrace_fd;
 369        int ret = 0;
 370
 371        /* Test:
 372         * if (new per thread event by perf)
 373         *      if (existing thread event by ptrace on the same thread)
 374         *              if (addr range does not overlaps)
 375         *                      allow;
 376         */
 377        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
 378        if (ptrace_fd < 0)
 379                return -1;
 380
 381        perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
 382                                         sizeof(*perf_data2));
 383        if (perf_fd < 0) {
 384                ret = -1;
 385                goto ptrace_close;
 386        }
 387        close(perf_fd);
 388
 389ptrace_close:
 390        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 391        return ret;
 392}
 393
 394static int test9(pid_t child_pid)
 395{
 396        int perf_fd;
 397        int ptrace_fd;
 398        int cpid;
 399        int ret = 0;
 400
 401        /* Test:
 402         * if (new per thread event by perf)
 403         *      if (existing thread event by ptrace on the other thread)
 404         *              allow;
 405         */
 406        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 407        if (ptrace_fd < 0)
 408                return -1;
 409
 410        cpid = fork();
 411        if (!cpid) {
 412                /* Temporary Child */
 413                pause();
 414                exit(EXIT_SUCCESS);
 415        }
 416
 417        perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
 418        if (perf_fd < 0) {
 419                ret = -1;
 420                goto kill_child;
 421        }
 422        close(perf_fd);
 423
 424kill_child:
 425        kill(cpid, SIGINT);
 426        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 427        return ret;
 428}
 429
 430static int test10(pid_t child_pid)
 431{
 432        int perf_fd;
 433        int ptrace_fd;
 434        int ret = 0;
 435
 436        /* Test:
 437         * if (new per cpu event by perf)
 438         *      if (existing thread event by ptrace on the same thread)
 439         *              if (addr range overlaps)
 440         *                      fail;
 441         */
 442        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 443        if (ptrace_fd < 0)
 444                return -1;
 445
 446        perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
 447        if (perf_fd > 0 || errno != ENOSPC)
 448                ret = -1;
 449
 450        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 451        return ret;
 452}
 453
 454static int test11(pid_t child_pid)
 455{
 456        int perf_fd;
 457        int ptrace_fd;
 458        int ret = 0;
 459
 460        /* Test:
 461         * if (new per cpu event by perf)
 462         *      if (existing thread event by ptrace on the same thread)
 463         *              if (addr range does not overlap)
 464         *                      allow;
 465         */
 466        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
 467        if (ptrace_fd < 0)
 468                return -1;
 469
 470        perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
 471        if (perf_fd < 0) {
 472                ret = -1;
 473                goto ptrace_close;
 474        }
 475        close(perf_fd);
 476
 477ptrace_close:
 478        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 479        return ret;
 480}
 481
 482static int test12(pid_t child_pid)
 483{
 484        int perf_fd;
 485        int ptrace_fd;
 486        int ret = 0;
 487
 488        /* Test:
 489         * if (new per thread and per cpu event by perf)
 490         *      if (existing thread event by ptrace on the same thread)
 491         *              if (addr range overlaps)
 492         *                      fail;
 493         */
 494        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 495        if (ptrace_fd < 0)
 496                return -1;
 497
 498        perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data1, sizeof(*perf_data1));
 499        if (perf_fd > 0 || errno != ENOSPC)
 500                ret = -1;
 501
 502        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 503        return ret;
 504}
 505
 506static int test13(pid_t child_pid)
 507{
 508        int perf_fd;
 509        int ptrace_fd;
 510        int ret = 0;
 511
 512        /* Test:
 513         * if (new per thread and per cpu event by perf)
 514         *      if (existing thread event by ptrace on the same thread)
 515         *              if (addr range does not overlap)
 516         *                      allow;
 517         */
 518        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
 519        if (ptrace_fd < 0)
 520                return -1;
 521
 522        perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data2, sizeof(*perf_data2));
 523        if (perf_fd < 0) {
 524                ret = -1;
 525                goto ptrace_close;
 526        }
 527        close(perf_fd);
 528
 529ptrace_close:
 530        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 531        return ret;
 532}
 533
 534static int test14(pid_t child_pid)
 535{
 536        int perf_fd;
 537        int ptrace_fd;
 538        int cpid;
 539        int ret = 0;
 540
 541        /* Test:
 542         * if (new per thread and per cpu event by perf)
 543         *      if (existing thread event by ptrace on the other thread)
 544         *              allow;
 545         */
 546        ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
 547        if (ptrace_fd < 0)
 548                return -1;
 549
 550        cpid = fork();
 551        if (!cpid) {
 552                /* Temporary Child */
 553                pause();
 554                exit(EXIT_SUCCESS);
 555        }
 556
 557        perf_fd = perf_thread_cpu_event_open(cpid, 0, (__u64)perf_data1,
 558                                             sizeof(*perf_data1));
 559        if (perf_fd < 0) {
 560                ret = -1;
 561                goto kill_child;
 562        }
 563        close(perf_fd);
 564
 565kill_child:
 566        kill(cpid, SIGINT);
 567        ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
 568        return ret;
 569}
 570
 571static int do_test(const char *msg, int (*fun)(pid_t arg), pid_t arg)
 572{
 573        int ret;
 574
 575        ret = fun(arg);
 576        if (ret)
 577                printf("%s: Error\n", msg);
 578        else
 579                printf("%s: Ok\n", msg);
 580        return ret;
 581}
 582
 583char *desc[14] = {
 584        "perf cpu event -> ptrace thread event (Overlapping)",
 585        "perf cpu event -> ptrace thread event (Non-overlapping)",
 586        "perf thread event -> ptrace same thread event (Overlapping)",
 587        "perf thread event -> ptrace same thread event (Non-overlapping)",
 588        "perf thread event -> ptrace other thread event",
 589        "ptrace thread event -> perf kernel event",
 590        "ptrace thread event -> perf same thread event (Overlapping)",
 591        "ptrace thread event -> perf same thread event (Non-overlapping)",
 592        "ptrace thread event -> perf other thread event",
 593        "ptrace thread event -> perf cpu event (Overlapping)",
 594        "ptrace thread event -> perf cpu event (Non-overlapping)",
 595        "ptrace thread event -> perf same thread & cpu event (Overlapping)",
 596        "ptrace thread event -> perf same thread & cpu event (Non-overlapping)",
 597        "ptrace thread event -> perf other thread & cpu event",
 598};
 599
 600static int test(pid_t child_pid)
 601{
 602        int ret = TEST_PASS;
 603
 604        ret |= do_test(desc[0], test1, child_pid);
 605        ret |= do_test(desc[1], test2, child_pid);
 606        ret |= do_test(desc[2], test3, child_pid);
 607        ret |= do_test(desc[3], test4, child_pid);
 608        ret |= do_test(desc[4], test5, child_pid);
 609        ret |= do_test(desc[5], test6, child_pid);
 610        ret |= do_test(desc[6], test7, child_pid);
 611        ret |= do_test(desc[7], test8, child_pid);
 612        ret |= do_test(desc[8], test9, child_pid);
 613        ret |= do_test(desc[9], test10, child_pid);
 614        ret |= do_test(desc[10], test11, child_pid);
 615        ret |= do_test(desc[11], test12, child_pid);
 616        ret |= do_test(desc[12], test13, child_pid);
 617        ret |= do_test(desc[13], test14, child_pid);
 618
 619        return ret;
 620}
 621
 622static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
 623{
 624        if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
 625                perror("Can't get breakpoint info");
 626                exit(-1);
 627        }
 628}
 629
 630static int ptrace_perf_hwbreak(void)
 631{
 632        int ret;
 633        pid_t child_pid;
 634        struct ppc_debug_info dbginfo;
 635
 636        child_pid = fork();
 637        if (!child_pid)
 638                return child();
 639
 640        /* parent */
 641        wait(NULL); /* <-- child (SIGUSR1) */
 642
 643        get_dbginfo(child_pid, &dbginfo);
 644        SKIP_IF(dbginfo.num_data_bps <= 1);
 645
 646        ret = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
 647        SKIP_IF(ret < 0);
 648        close(ret);
 649
 650        ret = test(child_pid);
 651
 652        ptrace(PTRACE_CONT, child_pid, NULL, 0);
 653        return ret;
 654}
 655
 656int main(int argc, char *argv[])
 657{
 658        return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak");
 659}
 660
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.