brintos

brintos / linux-shallow public Read only

0
0
Text · 7.8 KiB · 3faeb5b Raw
295 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Inspired by breakpoint overflow test done by4 * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests5 * (git://github.com/deater/perf_event_tests)6 */7 8/*9 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select10 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.11 */12#define __SANE_USERSPACE_TYPES__13 14#include <stdlib.h>15#include <stdio.h>16#include <unistd.h>17#include <string.h>18#include <sys/ioctl.h>19#include <time.h>20#include <fcntl.h>21#include <signal.h>22#include <sys/mman.h>23#include <linux/compiler.h>24#include <linux/hw_breakpoint.h>25 26#include "tests.h"27#include "debug.h"28#include "event.h"29#include "parse-events.h"30#include "perf-sys.h"31#include "cloexec.h"32 33static int fd1;34static int fd2;35static int fd3;36static int overflows;37static int overflows_2;38 39volatile long the_var;40 41 42/*43 * Use ASM to ensure watchpoint and breakpoint can be triggered44 * at one instruction.45 */46#if defined (__x86_64__)47extern void __test_function(volatile long *ptr);48asm (49	".pushsection .text;"50	".globl __test_function\n"51	".type __test_function, @function;"52	"__test_function:\n"53	"incq (%rdi)\n"54	"ret\n"55	".popsection\n");56#else57static void __test_function(volatile long *ptr)58{59	*ptr = 0x1234;60}61#endif62 63static noinline int test_function(void)64{65	__test_function(&the_var);66	the_var++;67	return time(NULL);68}69 70static void sig_handler_2(int signum __maybe_unused,71			  siginfo_t *oh __maybe_unused,72			  void *uc __maybe_unused)73{74	overflows_2++;75	if (overflows_2 > 10) {76		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);77		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);78		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);79	}80}81 82static void sig_handler(int signum __maybe_unused,83			siginfo_t *oh __maybe_unused,84			void *uc __maybe_unused)85{86	overflows++;87 88	if (overflows > 10) {89		/*90		 * This should be executed only once during91		 * this test, if we are here for the 10th92		 * time, consider this the recursive issue.93		 *94		 * We can get out of here by disable events,95		 * so no new SIGIO is delivered.96		 */97		ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);98		ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);99		ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);100	}101}102 103static int __event(bool is_x, void *addr, int sig)104{105	struct perf_event_attr pe;106	int fd;107 108	memset(&pe, 0, sizeof(struct perf_event_attr));109	pe.type = PERF_TYPE_BREAKPOINT;110	pe.size = sizeof(struct perf_event_attr);111 112	pe.config = 0;113	pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;114	pe.bp_addr = (unsigned long) addr;115	pe.bp_len = is_x ? default_breakpoint_len() : sizeof(long);116 117	pe.sample_period = 1;118	pe.sample_type = PERF_SAMPLE_IP;119	pe.wakeup_events = 1;120 121	pe.disabled = 1;122	pe.exclude_kernel = 1;123	pe.exclude_hv = 1;124 125	fd = sys_perf_event_open(&pe, 0, -1, -1,126				 perf_event_open_cloexec_flag());127	if (fd < 0) {128		pr_debug("failed opening event %llx\n", pe.config);129		return TEST_FAIL;130	}131 132	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);133	fcntl(fd, F_SETSIG, sig);134	fcntl(fd, F_SETOWN, getpid());135 136	ioctl(fd, PERF_EVENT_IOC_RESET, 0);137 138	return fd;139}140 141static int bp_event(void *addr, int sig)142{143	return __event(true, addr, sig);144}145 146static int wp_event(void *addr, int sig)147{148	return __event(false, addr, sig);149}150 151static long long bp_count(int fd)152{153	long long count;154	int ret;155 156	ret = read(fd, &count, sizeof(long long));157	if (ret != sizeof(long long)) {158		pr_debug("failed to read: %d\n", ret);159		return TEST_FAIL;160	}161 162	return count;163}164 165static int test__bp_signal(struct test_suite *test __maybe_unused, int subtest __maybe_unused)166{167	struct sigaction sa;168	long long count1, count2, count3;169 170	if (!BP_SIGNAL_IS_SUPPORTED) {171		pr_debug("Test not supported on this architecture");172		return TEST_SKIP;173	}174 175	/* setup SIGIO signal handler */176	memset(&sa, 0, sizeof(struct sigaction));177	sa.sa_sigaction = (void *) sig_handler;178	sa.sa_flags = SA_SIGINFO;179 180	if (sigaction(SIGIO, &sa, NULL) < 0) {181		pr_debug("failed setting up signal handler\n");182		return TEST_FAIL;183	}184 185	sa.sa_sigaction = (void *) sig_handler_2;186	if (sigaction(SIGUSR1, &sa, NULL) < 0) {187		pr_debug("failed setting up signal handler 2\n");188		return TEST_FAIL;189	}190 191	/*192	 * We create following events:193	 *194	 * fd1 - breakpoint event on __test_function with SIGIO195	 *       signal configured. We should get signal196	 *       notification each time the breakpoint is hit197	 *198	 * fd2 - breakpoint event on sig_handler with SIGUSR1199	 *       configured. We should get SIGUSR1 each time when200	 *       breakpoint is hit201	 *202	 * fd3 - watchpoint event on __test_function with SIGIO203	 *       configured.204	 *205	 * Following processing should happen:206	 *   Exec:               Action:                       Result:207	 *   incq (%rdi)       - fd1 event breakpoint hit   -> count1 == 1208	 *                     - SIGIO is delivered209	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 1210	 *                     - SIGUSR1 is delivered211	 *   sig_handler_2                                  -> overflows_2 == 1  (nested signal)212	 *   sys_rt_sigreturn  - return from sig_handler_2213	 *   overflows++                                    -> overflows = 1214	 *   sys_rt_sigreturn  - return from sig_handler215	 *   incq (%rdi)       - fd3 event watchpoint hit   -> count3 == 1       (wp and bp in one insn)216	 *                     - SIGIO is delivered217	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 2218	 *                     - SIGUSR1 is delivered219	 *   sig_handler_2                                  -> overflows_2 == 2  (nested signal)220	 *   sys_rt_sigreturn  - return from sig_handler_2221	 *   overflows++                                    -> overflows = 2222	 *   sys_rt_sigreturn  - return from sig_handler223	 *   the_var++         - fd3 event watchpoint hit   -> count3 == 2       (standalone watchpoint)224	 *                     - SIGIO is delivered225	 *   sig_handler       - fd2 event breakpoint hit   -> count2 == 3226	 *                     - SIGUSR1 is delivered227	 *   sig_handler_2                                  -> overflows_2 == 3  (nested signal)228	 *   sys_rt_sigreturn  - return from sig_handler_2229	 *   overflows++                                    -> overflows == 3230	 *   sys_rt_sigreturn  - return from sig_handler231	 *232	 * The test case check following error conditions:233	 * - we get stuck in signal handler because of debug234	 *   exception being triggered recursively due to235	 *   the wrong RF EFLAG management236	 *237	 * - we never trigger the sig_handler breakpoint due238	 *   to the wrong RF EFLAG management239	 *240	 */241 242	fd1 = bp_event(__test_function, SIGIO);243	fd2 = bp_event(sig_handler, SIGUSR1);244	fd3 = wp_event((void *)&the_var, SIGIO);245 246	ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);247	ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);248	ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);249 250	/*251	 * Kick off the test by triggering 'fd1'252	 * breakpoint.253	 */254	test_function();255 256	ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);257	ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);258	ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);259 260	count1 = bp_count(fd1);261	count2 = bp_count(fd2);262	count3 = bp_count(fd3);263 264	close(fd1);265	close(fd2);266	close(fd3);267 268	pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",269		 count1, count2, count3, overflows, overflows_2);270 271	if (count1 != 1) {272		if (count1 == 11)273			pr_debug("failed: RF EFLAG recursion issue detected\n");274		else275			pr_debug("failed: wrong count for bp1: %lld, expected 1\n", count1);276	}277 278	if (overflows != 3)279		pr_debug("failed: wrong overflow (%d) hit, expected 3\n", overflows);280 281	if (overflows_2 != 3)282		pr_debug("failed: wrong overflow_2 (%d) hit, expected 3\n", overflows_2);283 284	if (count2 != 3)285		pr_debug("failed: wrong count for bp2 (%lld), expected 3\n", count2);286 287	if (count3 != 2)288		pr_debug("failed: wrong count for bp3 (%lld), expected 2\n", count3);289 290	return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?291		TEST_OK : TEST_FAIL;292}293 294DEFINE_SUITE("Breakpoint overflow signal handler", bp_signal);295