18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Inspired by breakpoint overflow test done by 48c2ecf20Sopenharmony_ci * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests 58c2ecf20Sopenharmony_ci * (git://github.com/deater/perf_event_tests) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select 108c2ecf20Sopenharmony_ci * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#define __SANE_USERSPACE_TYPES__ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <stdlib.h> 158c2ecf20Sopenharmony_ci#include <stdio.h> 168c2ecf20Sopenharmony_ci#include <unistd.h> 178c2ecf20Sopenharmony_ci#include <string.h> 188c2ecf20Sopenharmony_ci#include <sys/ioctl.h> 198c2ecf20Sopenharmony_ci#include <time.h> 208c2ecf20Sopenharmony_ci#include <fcntl.h> 218c2ecf20Sopenharmony_ci#include <signal.h> 228c2ecf20Sopenharmony_ci#include <sys/mman.h> 238c2ecf20Sopenharmony_ci#include <linux/compiler.h> 248c2ecf20Sopenharmony_ci#include <linux/hw_breakpoint.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "tests.h" 278c2ecf20Sopenharmony_ci#include "debug.h" 288c2ecf20Sopenharmony_ci#include "event.h" 298c2ecf20Sopenharmony_ci#include "perf-sys.h" 308c2ecf20Sopenharmony_ci#include "cloexec.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int fd1; 338c2ecf20Sopenharmony_cistatic int fd2; 348c2ecf20Sopenharmony_cistatic int fd3; 358c2ecf20Sopenharmony_cistatic int overflows; 368c2ecf20Sopenharmony_cistatic int overflows_2; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_civolatile long the_var; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Use ASM to ensure watchpoint and breakpoint can be triggered 438c2ecf20Sopenharmony_ci * at one instruction. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci#if defined (__x86_64__) 468c2ecf20Sopenharmony_ciextern void __test_function(volatile long *ptr); 478c2ecf20Sopenharmony_ciasm ( 488c2ecf20Sopenharmony_ci ".pushsection .text;" 498c2ecf20Sopenharmony_ci ".globl __test_function\n" 508c2ecf20Sopenharmony_ci ".type __test_function, @function;" 518c2ecf20Sopenharmony_ci "__test_function:\n" 528c2ecf20Sopenharmony_ci "incq (%rdi)\n" 538c2ecf20Sopenharmony_ci "ret\n" 548c2ecf20Sopenharmony_ci ".popsection\n"); 558c2ecf20Sopenharmony_ci#else 568c2ecf20Sopenharmony_cistatic void __test_function(volatile long *ptr) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci *ptr = 0x1234; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic noinline int test_function(void) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci __test_function(&the_var); 658c2ecf20Sopenharmony_ci the_var++; 668c2ecf20Sopenharmony_ci return time(NULL); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void sig_handler_2(int signum __maybe_unused, 708c2ecf20Sopenharmony_ci siginfo_t *oh __maybe_unused, 718c2ecf20Sopenharmony_ci void *uc __maybe_unused) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci overflows_2++; 748c2ecf20Sopenharmony_ci if (overflows_2 > 10) { 758c2ecf20Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 768c2ecf20Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 778c2ecf20Sopenharmony_ci ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0); 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic void sig_handler(int signum __maybe_unused, 828c2ecf20Sopenharmony_ci siginfo_t *oh __maybe_unused, 838c2ecf20Sopenharmony_ci void *uc __maybe_unused) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci overflows++; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (overflows > 10) { 888c2ecf20Sopenharmony_ci /* 898c2ecf20Sopenharmony_ci * This should be executed only once during 908c2ecf20Sopenharmony_ci * this test, if we are here for the 10th 918c2ecf20Sopenharmony_ci * time, consider this the recursive issue. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * We can get out of here by disable events, 948c2ecf20Sopenharmony_ci * so no new SIGIO is delivered. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 978c2ecf20Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 988c2ecf20Sopenharmony_ci ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int __event(bool is_x, void *addr, int sig) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct perf_event_attr pe; 1058c2ecf20Sopenharmony_ci int fd; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci memset(&pe, 0, sizeof(struct perf_event_attr)); 1088c2ecf20Sopenharmony_ci pe.type = PERF_TYPE_BREAKPOINT; 1098c2ecf20Sopenharmony_ci pe.size = sizeof(struct perf_event_attr); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci pe.config = 0; 1128c2ecf20Sopenharmony_ci pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W; 1138c2ecf20Sopenharmony_ci pe.bp_addr = (unsigned long) addr; 1148c2ecf20Sopenharmony_ci pe.bp_len = sizeof(long); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci pe.sample_period = 1; 1178c2ecf20Sopenharmony_ci pe.sample_type = PERF_SAMPLE_IP; 1188c2ecf20Sopenharmony_ci pe.wakeup_events = 1; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci pe.disabled = 1; 1218c2ecf20Sopenharmony_ci pe.exclude_kernel = 1; 1228c2ecf20Sopenharmony_ci pe.exclude_hv = 1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci fd = sys_perf_event_open(&pe, 0, -1, -1, 1258c2ecf20Sopenharmony_ci perf_event_open_cloexec_flag()); 1268c2ecf20Sopenharmony_ci if (fd < 0) { 1278c2ecf20Sopenharmony_ci pr_debug("failed opening event %llx\n", pe.config); 1288c2ecf20Sopenharmony_ci return TEST_FAIL; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); 1328c2ecf20Sopenharmony_ci fcntl(fd, F_SETSIG, sig); 1338c2ecf20Sopenharmony_ci fcntl(fd, F_SETOWN, getpid()); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ioctl(fd, PERF_EVENT_IOC_RESET, 0); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return fd; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int bp_event(void *addr, int sig) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci return __event(true, addr, sig); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int wp_event(void *addr, int sig) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return __event(false, addr, sig); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic long long bp_count(int fd) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci long long count; 1538c2ecf20Sopenharmony_ci int ret; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci ret = read(fd, &count, sizeof(long long)); 1568c2ecf20Sopenharmony_ci if (ret != sizeof(long long)) { 1578c2ecf20Sopenharmony_ci pr_debug("failed to read: %d\n", ret); 1588c2ecf20Sopenharmony_ci return TEST_FAIL; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return count; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ciint test__bp_signal(struct test *test __maybe_unused, int subtest __maybe_unused) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct sigaction sa; 1678c2ecf20Sopenharmony_ci long long count1, count2, count3; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* setup SIGIO signal handler */ 1708c2ecf20Sopenharmony_ci memset(&sa, 0, sizeof(struct sigaction)); 1718c2ecf20Sopenharmony_ci sa.sa_sigaction = (void *) sig_handler; 1728c2ecf20Sopenharmony_ci sa.sa_flags = SA_SIGINFO; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (sigaction(SIGIO, &sa, NULL) < 0) { 1758c2ecf20Sopenharmony_ci pr_debug("failed setting up signal handler\n"); 1768c2ecf20Sopenharmony_ci return TEST_FAIL; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci sa.sa_sigaction = (void *) sig_handler_2; 1808c2ecf20Sopenharmony_ci if (sigaction(SIGUSR1, &sa, NULL) < 0) { 1818c2ecf20Sopenharmony_ci pr_debug("failed setting up signal handler 2\n"); 1828c2ecf20Sopenharmony_ci return TEST_FAIL; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * We create following events: 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * fd1 - breakpoint event on __test_function with SIGIO 1898c2ecf20Sopenharmony_ci * signal configured. We should get signal 1908c2ecf20Sopenharmony_ci * notification each time the breakpoint is hit 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * fd2 - breakpoint event on sig_handler with SIGUSR1 1938c2ecf20Sopenharmony_ci * configured. We should get SIGUSR1 each time when 1948c2ecf20Sopenharmony_ci * breakpoint is hit 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * fd3 - watchpoint event on __test_function with SIGIO 1978c2ecf20Sopenharmony_ci * configured. 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * Following processing should happen: 2008c2ecf20Sopenharmony_ci * Exec: Action: Result: 2018c2ecf20Sopenharmony_ci * incq (%rdi) - fd1 event breakpoint hit -> count1 == 1 2028c2ecf20Sopenharmony_ci * - SIGIO is delivered 2038c2ecf20Sopenharmony_ci * sig_handler - fd2 event breakpoint hit -> count2 == 1 2048c2ecf20Sopenharmony_ci * - SIGUSR1 is delivered 2058c2ecf20Sopenharmony_ci * sig_handler_2 -> overflows_2 == 1 (nested signal) 2068c2ecf20Sopenharmony_ci * sys_rt_sigreturn - return from sig_handler_2 2078c2ecf20Sopenharmony_ci * overflows++ -> overflows = 1 2088c2ecf20Sopenharmony_ci * sys_rt_sigreturn - return from sig_handler 2098c2ecf20Sopenharmony_ci * incq (%rdi) - fd3 event watchpoint hit -> count3 == 1 (wp and bp in one insn) 2108c2ecf20Sopenharmony_ci * - SIGIO is delivered 2118c2ecf20Sopenharmony_ci * sig_handler - fd2 event breakpoint hit -> count2 == 2 2128c2ecf20Sopenharmony_ci * - SIGUSR1 is delivered 2138c2ecf20Sopenharmony_ci * sig_handler_2 -> overflows_2 == 2 (nested signal) 2148c2ecf20Sopenharmony_ci * sys_rt_sigreturn - return from sig_handler_2 2158c2ecf20Sopenharmony_ci * overflows++ -> overflows = 2 2168c2ecf20Sopenharmony_ci * sys_rt_sigreturn - return from sig_handler 2178c2ecf20Sopenharmony_ci * the_var++ - fd3 event watchpoint hit -> count3 == 2 (standalone watchpoint) 2188c2ecf20Sopenharmony_ci * - SIGIO is delivered 2198c2ecf20Sopenharmony_ci * sig_handler - fd2 event breakpoint hit -> count2 == 3 2208c2ecf20Sopenharmony_ci * - SIGUSR1 is delivered 2218c2ecf20Sopenharmony_ci * sig_handler_2 -> overflows_2 == 3 (nested signal) 2228c2ecf20Sopenharmony_ci * sys_rt_sigreturn - return from sig_handler_2 2238c2ecf20Sopenharmony_ci * overflows++ -> overflows == 3 2248c2ecf20Sopenharmony_ci * sys_rt_sigreturn - return from sig_handler 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * The test case check following error conditions: 2278c2ecf20Sopenharmony_ci * - we get stuck in signal handler because of debug 2288c2ecf20Sopenharmony_ci * exception being triggered receursively due to 2298c2ecf20Sopenharmony_ci * the wrong RF EFLAG management 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * - we never trigger the sig_handler breakpoint due 2328c2ecf20Sopenharmony_ci * to the rong RF EFLAG management 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci fd1 = bp_event(__test_function, SIGIO); 2378c2ecf20Sopenharmony_ci fd2 = bp_event(sig_handler, SIGUSR1); 2388c2ecf20Sopenharmony_ci fd3 = wp_event((void *)&the_var, SIGIO); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); 2418c2ecf20Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); 2428c2ecf20Sopenharmony_ci ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * Kick off the test by trigering 'fd1' 2468c2ecf20Sopenharmony_ci * breakpoint. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci test_function(); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 2518c2ecf20Sopenharmony_ci ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 2528c2ecf20Sopenharmony_ci ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci count1 = bp_count(fd1); 2558c2ecf20Sopenharmony_ci count2 = bp_count(fd2); 2568c2ecf20Sopenharmony_ci count3 = bp_count(fd3); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci close(fd1); 2598c2ecf20Sopenharmony_ci close(fd2); 2608c2ecf20Sopenharmony_ci close(fd3); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n", 2638c2ecf20Sopenharmony_ci count1, count2, count3, overflows, overflows_2); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (count1 != 1) { 2668c2ecf20Sopenharmony_ci if (count1 == 11) 2678c2ecf20Sopenharmony_ci pr_debug("failed: RF EFLAG recursion issue detected\n"); 2688c2ecf20Sopenharmony_ci else 2698c2ecf20Sopenharmony_ci pr_debug("failed: wrong count for bp1: %lld, expected 1\n", count1); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (overflows != 3) 2738c2ecf20Sopenharmony_ci pr_debug("failed: wrong overflow (%d) hit, expected 3\n", overflows); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (overflows_2 != 3) 2768c2ecf20Sopenharmony_ci pr_debug("failed: wrong overflow_2 (%d) hit, expected 3\n", overflows_2); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (count2 != 3) 2798c2ecf20Sopenharmony_ci pr_debug("failed: wrong count for bp2 (%lld), expected 3\n", count2); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (count3 != 2) 2828c2ecf20Sopenharmony_ci pr_debug("failed: wrong count for bp3 (%lld), expected 2\n", count3); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ? 2858c2ecf20Sopenharmony_ci TEST_OK : TEST_FAIL; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cibool test__bp_signal_is_supported(void) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * PowerPC and S390 do not support creation of instruction 2928c2ecf20Sopenharmony_ci * breakpoints using the perf_event interface. 2938c2ecf20Sopenharmony_ci * 2948c2ecf20Sopenharmony_ci * ARM requires explicit rounding down of the instruction 2958c2ecf20Sopenharmony_ci * pointer in Thumb mode, and then requires the single-step 2968c2ecf20Sopenharmony_ci * to be handled explicitly in the overflow handler to avoid 2978c2ecf20Sopenharmony_ci * stepping into the SIGIO handler and getting stuck on the 2988c2ecf20Sopenharmony_ci * breakpointed instruction. 2998c2ecf20Sopenharmony_ci * 3008c2ecf20Sopenharmony_ci * Since arm64 has the same issue with arm for the single-step 3018c2ecf20Sopenharmony_ci * handling, this case also gets stuck on the breakpointed 3028c2ecf20Sopenharmony_ci * instruction. 3038c2ecf20Sopenharmony_ci * 3048c2ecf20Sopenharmony_ci * Just disable the test for these architectures until these 3058c2ecf20Sopenharmony_ci * issues are resolved. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) || \ 3088c2ecf20Sopenharmony_ci defined(__aarch64__) 3098c2ecf20Sopenharmony_ci return false; 3108c2ecf20Sopenharmony_ci#else 3118c2ecf20Sopenharmony_ci return true; 3128c2ecf20Sopenharmony_ci#endif 3138c2ecf20Sopenharmony_ci} 314