Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 #include <stdio.h>
0003 #include <string.h>
0004 #include <signal.h>
0005 #include <stdlib.h>
0006 #include <unistd.h>
0007 #include <errno.h>
0008 #include <linux/hw_breakpoint.h>
0009 #include <linux/perf_event.h>
0010 #include <asm/unistd.h>
0011 #include <sys/ptrace.h>
0012 #include <sys/wait.h>
0013 #include "ptrace.h"
0014 
0015 char data[16];
0016 
0017 /* Overlapping address range */
0018 volatile __u64 *ptrace_data1 = (__u64 *)&data[0];
0019 volatile __u64 *perf_data1 = (__u64 *)&data[4];
0020 
0021 /* Non-overlapping address range */
0022 volatile __u64 *ptrace_data2 = (__u64 *)&data[0];
0023 volatile __u64 *perf_data2 = (__u64 *)&data[8];
0024 
0025 static unsigned long pid_max_addr(void)
0026 {
0027     FILE *fp;
0028     char *line, *c;
0029     char addr[100];
0030     size_t len = 0;
0031 
0032     fp = fopen("/proc/kallsyms", "r");
0033     if (!fp) {
0034         printf("Failed to read /proc/kallsyms. Exiting..\n");
0035         exit(EXIT_FAILURE);
0036     }
0037 
0038     while (getline(&line, &len, fp) != -1) {
0039         if (!strstr(line, "pid_max") || strstr(line, "pid_max_max") ||
0040             strstr(line, "pid_max_min"))
0041             continue;
0042 
0043         strncpy(addr, line, len < 100 ? len : 100);
0044         c = strchr(addr, ' ');
0045         *c = '\0';
0046         return strtoul(addr, &c, 16);
0047     }
0048     fclose(fp);
0049     printf("Could not find pix_max. Exiting..\n");
0050     exit(EXIT_FAILURE);
0051     return -1;
0052 }
0053 
0054 static void perf_user_event_attr_set(struct perf_event_attr *attr, __u64 addr, __u64 len)
0055 {
0056     memset(attr, 0, sizeof(struct perf_event_attr));
0057     attr->type           = PERF_TYPE_BREAKPOINT;
0058     attr->size           = sizeof(struct perf_event_attr);
0059     attr->bp_type        = HW_BREAKPOINT_R;
0060     attr->bp_addr        = addr;
0061     attr->bp_len         = len;
0062     attr->exclude_kernel = 1;
0063     attr->exclude_hv     = 1;
0064 }
0065 
0066 static void perf_kernel_event_attr_set(struct perf_event_attr *attr)
0067 {
0068     memset(attr, 0, sizeof(struct perf_event_attr));
0069     attr->type           = PERF_TYPE_BREAKPOINT;
0070     attr->size           = sizeof(struct perf_event_attr);
0071     attr->bp_type        = HW_BREAKPOINT_R;
0072     attr->bp_addr        = pid_max_addr();
0073     attr->bp_len         = sizeof(unsigned long);
0074     attr->exclude_user   = 1;
0075     attr->exclude_hv     = 1;
0076 }
0077 
0078 static int perf_cpu_event_open(int cpu, __u64 addr, __u64 len)
0079 {
0080     struct perf_event_attr attr;
0081 
0082     perf_user_event_attr_set(&attr, addr, len);
0083     return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
0084 }
0085 
0086 static int perf_thread_event_open(pid_t child_pid, __u64 addr, __u64 len)
0087 {
0088     struct perf_event_attr attr;
0089 
0090     perf_user_event_attr_set(&attr, addr, len);
0091     return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
0092 }
0093 
0094 static int perf_thread_cpu_event_open(pid_t child_pid, int cpu, __u64 addr, __u64 len)
0095 {
0096     struct perf_event_attr attr;
0097 
0098     perf_user_event_attr_set(&attr, addr, len);
0099     return syscall(__NR_perf_event_open, &attr, child_pid, cpu, -1, 0);
0100 }
0101 
0102 static int perf_thread_kernel_event_open(pid_t child_pid)
0103 {
0104     struct perf_event_attr attr;
0105 
0106     perf_kernel_event_attr_set(&attr);
0107     return syscall(__NR_perf_event_open, &attr, child_pid, -1, -1, 0);
0108 }
0109 
0110 static int perf_cpu_kernel_event_open(int cpu)
0111 {
0112     struct perf_event_attr attr;
0113 
0114     perf_kernel_event_attr_set(&attr);
0115     return syscall(__NR_perf_event_open, &attr, -1, cpu, -1, 0);
0116 }
0117 
0118 static int child(void)
0119 {
0120     int ret;
0121 
0122     ret = ptrace(PTRACE_TRACEME, 0, NULL, 0);
0123     if (ret) {
0124         printf("Error: PTRACE_TRACEME failed\n");
0125         return 0;
0126     }
0127     kill(getpid(), SIGUSR1); /* --> parent (SIGUSR1) */
0128 
0129     return 0;
0130 }
0131 
0132 static void ptrace_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
0133                      __u64 addr, int len)
0134 {
0135     info->version = 1;
0136     info->trigger_type = type;
0137     info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
0138     info->addr = addr;
0139     info->addr2 = addr + len;
0140     info->condition_value = 0;
0141     if (!len)
0142         info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
0143     else
0144         info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
0145 }
0146 
0147 static int ptrace_open(pid_t child_pid, __u64 wp_addr, int len)
0148 {
0149     struct ppc_hw_breakpoint info;
0150 
0151     ptrace_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
0152     return ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, &info);
0153 }
0154 
0155 static int test1(pid_t child_pid)
0156 {
0157     int perf_fd;
0158     int ptrace_fd;
0159     int ret = 0;
0160 
0161     /* Test:
0162      * if (new per thread event by ptrace)
0163      *  if (existing cpu event by perf)
0164      *      if (addr range overlaps)
0165      *          fail;
0166      */
0167 
0168     perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
0169     if (perf_fd < 0)
0170         return -1;
0171 
0172     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0173     if (ptrace_fd > 0 || errno != ENOSPC)
0174         ret = -1;
0175 
0176     close(perf_fd);
0177     return ret;
0178 }
0179 
0180 static int test2(pid_t child_pid)
0181 {
0182     int perf_fd;
0183     int ptrace_fd;
0184     int ret = 0;
0185 
0186     /* Test:
0187      * if (new per thread event by ptrace)
0188      *  if (existing cpu event by perf)
0189      *      if (addr range does not overlaps)
0190      *          allow;
0191      */
0192 
0193     perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
0194     if (perf_fd < 0)
0195         return -1;
0196 
0197     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0198     if (ptrace_fd < 0) {
0199         ret = -1;
0200         goto perf_close;
0201     }
0202     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0203 
0204 perf_close:
0205     close(perf_fd);
0206     return ret;
0207 }
0208 
0209 static int test3(pid_t child_pid)
0210 {
0211     int perf_fd;
0212     int ptrace_fd;
0213     int ret = 0;
0214 
0215     /* Test:
0216      * if (new per thread event by ptrace)
0217      *  if (existing thread event by perf on the same thread)
0218      *      if (addr range overlaps)
0219      *          fail;
0220      */
0221     perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
0222                      sizeof(*perf_data1));
0223     if (perf_fd < 0)
0224         return -1;
0225 
0226     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0227     if (ptrace_fd > 0 || errno != ENOSPC)
0228         ret = -1;
0229 
0230     close(perf_fd);
0231     return ret;
0232 }
0233 
0234 static int test4(pid_t child_pid)
0235 {
0236     int perf_fd;
0237     int ptrace_fd;
0238     int ret = 0;
0239 
0240     /* Test:
0241      * if (new per thread event by ptrace)
0242      *  if (existing thread event by perf on the same thread)
0243      *      if (addr range does not overlaps)
0244      *          fail;
0245      */
0246     perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
0247                      sizeof(*perf_data2));
0248     if (perf_fd < 0)
0249         return -1;
0250 
0251     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0252     if (ptrace_fd < 0) {
0253         ret = -1;
0254         goto perf_close;
0255     }
0256     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0257 
0258 perf_close:
0259     close(perf_fd);
0260     return ret;
0261 }
0262 
0263 static int test5(pid_t child_pid)
0264 {
0265     int perf_fd;
0266     int ptrace_fd;
0267     int cpid;
0268     int ret = 0;
0269 
0270     /* Test:
0271      * if (new per thread event by ptrace)
0272      *  if (existing thread event by perf on the different thread)
0273      *      allow;
0274      */
0275     cpid = fork();
0276     if (!cpid) {
0277         /* Temporary Child */
0278         pause();
0279         exit(EXIT_SUCCESS);
0280     }
0281 
0282     perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
0283     if (perf_fd < 0) {
0284         ret = -1;
0285         goto kill_child;
0286     }
0287 
0288     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0289     if (ptrace_fd < 0) {
0290         ret = -1;
0291         goto perf_close;
0292     }
0293 
0294     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0295 perf_close:
0296     close(perf_fd);
0297 kill_child:
0298     kill(cpid, SIGINT);
0299     return ret;
0300 }
0301 
0302 static int test6(pid_t child_pid)
0303 {
0304     int perf_fd;
0305     int ptrace_fd;
0306     int ret = 0;
0307 
0308     /* Test:
0309      * if (new per thread kernel event by perf)
0310      *  if (existing thread event by ptrace on the same thread)
0311      *      allow;
0312      * -- OR --
0313      * if (new per cpu kernel event by perf)
0314      *  if (existing thread event by ptrace)
0315      *      allow;
0316      */
0317     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0318     if (ptrace_fd < 0)
0319         return -1;
0320 
0321     perf_fd = perf_thread_kernel_event_open(child_pid);
0322     if (perf_fd < 0) {
0323         ret = -1;
0324         goto ptrace_close;
0325     }
0326     close(perf_fd);
0327 
0328     perf_fd = perf_cpu_kernel_event_open(0);
0329     if (perf_fd < 0) {
0330         ret = -1;
0331         goto ptrace_close;
0332     }
0333     close(perf_fd);
0334 
0335 ptrace_close:
0336     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0337     return ret;
0338 }
0339 
0340 static int test7(pid_t child_pid)
0341 {
0342     int perf_fd;
0343     int ptrace_fd;
0344     int ret = 0;
0345 
0346     /* Test:
0347      * if (new per thread event by perf)
0348      *  if (existing thread event by ptrace on the same thread)
0349      *      if (addr range overlaps)
0350      *          fail;
0351      */
0352     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0353     if (ptrace_fd < 0)
0354         return -1;
0355 
0356     perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data1,
0357                      sizeof(*perf_data1));
0358     if (perf_fd > 0 || errno != ENOSPC)
0359         ret = -1;
0360 
0361     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0362     return ret;
0363 }
0364 
0365 static int test8(pid_t child_pid)
0366 {
0367     int perf_fd;
0368     int ptrace_fd;
0369     int ret = 0;
0370 
0371     /* Test:
0372      * if (new per thread event by perf)
0373      *  if (existing thread event by ptrace on the same thread)
0374      *      if (addr range does not overlaps)
0375      *          allow;
0376      */
0377     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0378     if (ptrace_fd < 0)
0379         return -1;
0380 
0381     perf_fd = perf_thread_event_open(child_pid, (__u64)perf_data2,
0382                      sizeof(*perf_data2));
0383     if (perf_fd < 0) {
0384         ret = -1;
0385         goto ptrace_close;
0386     }
0387     close(perf_fd);
0388 
0389 ptrace_close:
0390     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0391     return ret;
0392 }
0393 
0394 static int test9(pid_t child_pid)
0395 {
0396     int perf_fd;
0397     int ptrace_fd;
0398     int cpid;
0399     int ret = 0;
0400 
0401     /* Test:
0402      * if (new per thread event by perf)
0403      *  if (existing thread event by ptrace on the other thread)
0404      *      allow;
0405      */
0406     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0407     if (ptrace_fd < 0)
0408         return -1;
0409 
0410     cpid = fork();
0411     if (!cpid) {
0412         /* Temporary Child */
0413         pause();
0414         exit(EXIT_SUCCESS);
0415     }
0416 
0417     perf_fd = perf_thread_event_open(cpid, (__u64)perf_data1, sizeof(*perf_data1));
0418     if (perf_fd < 0) {
0419         ret = -1;
0420         goto kill_child;
0421     }
0422     close(perf_fd);
0423 
0424 kill_child:
0425     kill(cpid, SIGINT);
0426     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0427     return ret;
0428 }
0429 
0430 static int test10(pid_t child_pid)
0431 {
0432     int perf_fd;
0433     int ptrace_fd;
0434     int ret = 0;
0435 
0436     /* Test:
0437      * if (new per cpu event by perf)
0438      *  if (existing thread event by ptrace on the same thread)
0439      *      if (addr range overlaps)
0440      *          fail;
0441      */
0442     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0443     if (ptrace_fd < 0)
0444         return -1;
0445 
0446     perf_fd = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
0447     if (perf_fd > 0 || errno != ENOSPC)
0448         ret = -1;
0449 
0450     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0451     return ret;
0452 }
0453 
0454 static int test11(pid_t child_pid)
0455 {
0456     int perf_fd;
0457     int ptrace_fd;
0458     int ret = 0;
0459 
0460     /* Test:
0461      * if (new per cpu event by perf)
0462      *  if (existing thread event by ptrace on the same thread)
0463      *      if (addr range does not overlap)
0464      *          allow;
0465      */
0466     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0467     if (ptrace_fd < 0)
0468         return -1;
0469 
0470     perf_fd = perf_cpu_event_open(0, (__u64)perf_data2, sizeof(*perf_data2));
0471     if (perf_fd < 0) {
0472         ret = -1;
0473         goto ptrace_close;
0474     }
0475     close(perf_fd);
0476 
0477 ptrace_close:
0478     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0479     return ret;
0480 }
0481 
0482 static int test12(pid_t child_pid)
0483 {
0484     int perf_fd;
0485     int ptrace_fd;
0486     int ret = 0;
0487 
0488     /* Test:
0489      * if (new per thread and per cpu event by perf)
0490      *  if (existing thread event by ptrace on the same thread)
0491      *      if (addr range overlaps)
0492      *          fail;
0493      */
0494     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0495     if (ptrace_fd < 0)
0496         return -1;
0497 
0498     perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data1, sizeof(*perf_data1));
0499     if (perf_fd > 0 || errno != ENOSPC)
0500         ret = -1;
0501 
0502     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0503     return ret;
0504 }
0505 
0506 static int test13(pid_t child_pid)
0507 {
0508     int perf_fd;
0509     int ptrace_fd;
0510     int ret = 0;
0511 
0512     /* Test:
0513      * if (new per thread and per cpu event by perf)
0514      *  if (existing thread event by ptrace on the same thread)
0515      *      if (addr range does not overlap)
0516      *          allow;
0517      */
0518     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data2, sizeof(*ptrace_data2));
0519     if (ptrace_fd < 0)
0520         return -1;
0521 
0522     perf_fd = perf_thread_cpu_event_open(child_pid, 0, (__u64)perf_data2, sizeof(*perf_data2));
0523     if (perf_fd < 0) {
0524         ret = -1;
0525         goto ptrace_close;
0526     }
0527     close(perf_fd);
0528 
0529 ptrace_close:
0530     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0531     return ret;
0532 }
0533 
0534 static int test14(pid_t child_pid)
0535 {
0536     int perf_fd;
0537     int ptrace_fd;
0538     int cpid;
0539     int ret = 0;
0540 
0541     /* Test:
0542      * if (new per thread and per cpu event by perf)
0543      *  if (existing thread event by ptrace on the other thread)
0544      *      allow;
0545      */
0546     ptrace_fd = ptrace_open(child_pid, (__u64)ptrace_data1, sizeof(*ptrace_data1));
0547     if (ptrace_fd < 0)
0548         return -1;
0549 
0550     cpid = fork();
0551     if (!cpid) {
0552         /* Temporary Child */
0553         pause();
0554         exit(EXIT_SUCCESS);
0555     }
0556 
0557     perf_fd = perf_thread_cpu_event_open(cpid, 0, (__u64)perf_data1,
0558                          sizeof(*perf_data1));
0559     if (perf_fd < 0) {
0560         ret = -1;
0561         goto kill_child;
0562     }
0563     close(perf_fd);
0564 
0565 kill_child:
0566     kill(cpid, SIGINT);
0567     ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, ptrace_fd);
0568     return ret;
0569 }
0570 
0571 static int do_test(const char *msg, int (*fun)(pid_t arg), pid_t arg)
0572 {
0573     int ret;
0574 
0575     ret = fun(arg);
0576     if (ret)
0577         printf("%s: Error\n", msg);
0578     else
0579         printf("%s: Ok\n", msg);
0580     return ret;
0581 }
0582 
0583 char *desc[14] = {
0584     "perf cpu event -> ptrace thread event (Overlapping)",
0585     "perf cpu event -> ptrace thread event (Non-overlapping)",
0586     "perf thread event -> ptrace same thread event (Overlapping)",
0587     "perf thread event -> ptrace same thread event (Non-overlapping)",
0588     "perf thread event -> ptrace other thread event",
0589     "ptrace thread event -> perf kernel event",
0590     "ptrace thread event -> perf same thread event (Overlapping)",
0591     "ptrace thread event -> perf same thread event (Non-overlapping)",
0592     "ptrace thread event -> perf other thread event",
0593     "ptrace thread event -> perf cpu event (Overlapping)",
0594     "ptrace thread event -> perf cpu event (Non-overlapping)",
0595     "ptrace thread event -> perf same thread & cpu event (Overlapping)",
0596     "ptrace thread event -> perf same thread & cpu event (Non-overlapping)",
0597     "ptrace thread event -> perf other thread & cpu event",
0598 };
0599 
0600 static int test(pid_t child_pid)
0601 {
0602     int ret = TEST_PASS;
0603 
0604     ret |= do_test(desc[0], test1, child_pid);
0605     ret |= do_test(desc[1], test2, child_pid);
0606     ret |= do_test(desc[2], test3, child_pid);
0607     ret |= do_test(desc[3], test4, child_pid);
0608     ret |= do_test(desc[4], test5, child_pid);
0609     ret |= do_test(desc[5], test6, child_pid);
0610     ret |= do_test(desc[6], test7, child_pid);
0611     ret |= do_test(desc[7], test8, child_pid);
0612     ret |= do_test(desc[8], test9, child_pid);
0613     ret |= do_test(desc[9], test10, child_pid);
0614     ret |= do_test(desc[10], test11, child_pid);
0615     ret |= do_test(desc[11], test12, child_pid);
0616     ret |= do_test(desc[12], test13, child_pid);
0617     ret |= do_test(desc[13], test14, child_pid);
0618 
0619     return ret;
0620 }
0621 
0622 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
0623 {
0624     if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
0625         perror("Can't get breakpoint info");
0626         exit(-1);
0627     }
0628 }
0629 
0630 static int ptrace_perf_hwbreak(void)
0631 {
0632     int ret;
0633     pid_t child_pid;
0634     struct ppc_debug_info dbginfo;
0635 
0636     child_pid = fork();
0637     if (!child_pid)
0638         return child();
0639 
0640     /* parent */
0641     wait(NULL); /* <-- child (SIGUSR1) */
0642 
0643     get_dbginfo(child_pid, &dbginfo);
0644     SKIP_IF(dbginfo.num_data_bps <= 1);
0645 
0646     ret = perf_cpu_event_open(0, (__u64)perf_data1, sizeof(*perf_data1));
0647     SKIP_IF(ret < 0);
0648     close(ret);
0649 
0650     ret = test(child_pid);
0651 
0652     ptrace(PTRACE_CONT, child_pid, NULL, 0);
0653     return ret;
0654 }
0655 
0656 int main(int argc, char *argv[])
0657 {
0658     return test_harness(ptrace_perf_hwbreak, "ptrace-perf-hwbreak");
0659 }