aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@redhat.com>2013-03-10 14:41:10 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-03-15 12:06:10 -0400
commit5a6bef47b418676546ab86d25631c3cfb9ffaf2a (patch)
treefe4a133db664100f4a0e463e192e4a09a845d3df /tools
parent45fa534cffb246872de0cb8af207bea4a09aeb2f (diff)
perf tests: Test breakpoint overflow signal handler
Adding automated test for breakpoint event signal handler checking if it's executed properly. The test is related to the proper handling of the RF EFLAGS bit on x86_64, but it's generic for all archs. First we check the signal handler is properly called and that the following debug exception return to user space wouldn't trigger recursive breakpoint. This is related to x86_64 RF EFLAGS bit being managed in a wrong way. Second we check that we can set breakpoint in signal handler, which is not possible on x86_64 if the signal handler is executed with RF EFLAG set. This test is inpired by overflow tests done by Vince Weaver. Signed-off-by: Jiri Olsa <jolsa@redhat.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Link: http://lkml.kernel.org/r/1362940871-24486-6-git-send-email-jolsa@redhat.com [ committer note: s/pr_err/pr_debug/g i.e. print just OK or FAILED in non verbose mode ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile1
-rw-r--r--tools/perf/tests/bp_signal.c186
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/tests.h1
4 files changed, 192 insertions, 0 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 3dcd6273a90b..21e0b4b04465 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -511,6 +511,7 @@ LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
511LIB_OBJS += $(OUTPUT)tests/pmu.o 511LIB_OBJS += $(OUTPUT)tests/pmu.o
512LIB_OBJS += $(OUTPUT)tests/hists_link.o 512LIB_OBJS += $(OUTPUT)tests/hists_link.o
513LIB_OBJS += $(OUTPUT)tests/python-use.o 513LIB_OBJS += $(OUTPUT)tests/python-use.o
514LIB_OBJS += $(OUTPUT)tests/bp_signal.o
514 515
515BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 516BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
516BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 517BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
new file mode 100644
index 000000000000..68daa289e94c
--- /dev/null
+++ b/tools/perf/tests/bp_signal.c
@@ -0,0 +1,186 @@
1/*
2 * Inspired by breakpoint overflow test done by
3 * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests
4 * (git://github.com/deater/perf_event_tests)
5 */
6
7#include <stdlib.h>
8#include <stdio.h>
9#include <unistd.h>
10#include <string.h>
11#include <sys/ioctl.h>
12#include <time.h>
13#include <fcntl.h>
14#include <signal.h>
15#include <sys/mman.h>
16#include <linux/compiler.h>
17#include <linux/hw_breakpoint.h>
18
19#include "tests.h"
20#include "debug.h"
21#include "perf.h"
22
23static int fd1;
24static int fd2;
25static int overflows;
26
27__attribute__ ((noinline))
28static int test_function(void)
29{
30 return time(NULL);
31}
32
33static void sig_handler(int signum __maybe_unused,
34 siginfo_t *oh __maybe_unused,
35 void *uc __maybe_unused)
36{
37 overflows++;
38
39 if (overflows > 10) {
40 /*
41 * This should be executed only once during
42 * this test, if we are here for the 10th
43 * time, consider this the recursive issue.
44 *
45 * We can get out of here by disable events,
46 * so no new SIGIO is delivered.
47 */
48 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
49 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
50 }
51}
52
53static int bp_event(void *fn, int setup_signal)
54{
55 struct perf_event_attr pe;
56 int fd;
57
58 memset(&pe, 0, sizeof(struct perf_event_attr));
59 pe.type = PERF_TYPE_BREAKPOINT;
60 pe.size = sizeof(struct perf_event_attr);
61
62 pe.config = 0;
63 pe.bp_type = HW_BREAKPOINT_X;
64 pe.bp_addr = (unsigned long) fn;
65 pe.bp_len = sizeof(long);
66
67 pe.sample_period = 1;
68 pe.sample_type = PERF_SAMPLE_IP;
69 pe.wakeup_events = 1;
70
71 pe.disabled = 1;
72 pe.exclude_kernel = 1;
73 pe.exclude_hv = 1;
74
75 fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
76 if (fd < 0) {
77 pr_debug("failed opening event %llx\n", pe.config);
78 return TEST_FAIL;
79 }
80
81 if (setup_signal) {
82 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
83 fcntl(fd, F_SETSIG, SIGIO);
84 fcntl(fd, F_SETOWN, getpid());
85 }
86
87 ioctl(fd, PERF_EVENT_IOC_RESET, 0);
88
89 return fd;
90}
91
92static long long bp_count(int fd)
93{
94 long long count;
95 int ret;
96
97 ret = read(fd, &count, sizeof(long long));
98 if (ret != sizeof(long long)) {
99 pr_debug("failed to read: %d\n", ret);
100 return TEST_FAIL;
101 }
102
103 return count;
104}
105
106int test__bp_signal(void)
107{
108 struct sigaction sa;
109 long long count1, count2;
110
111 /* setup SIGIO signal handler */
112 memset(&sa, 0, sizeof(struct sigaction));
113 sa.sa_sigaction = (void *) sig_handler;
114 sa.sa_flags = SA_SIGINFO;
115
116 if (sigaction(SIGIO, &sa, NULL) < 0) {
117 pr_debug("failed setting up signal handler\n");
118 return TEST_FAIL;
119 }
120
121 /*
122 * We create following events:
123 *
124 * fd1 - breakpoint event on test_function with SIGIO
125 * signal configured. We should get signal
126 * notification each time the breakpoint is hit
127 *
128 * fd2 - breakpoint event on sig_handler without SIGIO
129 * configured.
130 *
131 * Following processing should happen:
132 * - execute test_function
133 * - fd1 event breakpoint hit -> count1 == 1
134 * - SIGIO is delivered -> overflows == 1
135 * - fd2 event breakpoint hit -> count2 == 1
136 *
137 * The test case check following error conditions:
138 * - we get stuck in signal handler because of debug
139 * exception being triggered receursively due to
140 * the wrong RF EFLAG management
141 *
142 * - we never trigger the sig_handler breakpoint due
143 * to the rong RF EFLAG management
144 *
145 */
146
147 fd1 = bp_event(test_function, 1);
148 fd2 = bp_event(sig_handler, 0);
149
150 ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
151 ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
152
153 /*
154 * Kick off the test by trigering 'fd1'
155 * breakpoint.
156 */
157 test_function();
158
159 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
160 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
161
162 count1 = bp_count(fd1);
163 count2 = bp_count(fd2);
164
165 close(fd1);
166 close(fd2);
167
168 pr_debug("count1 %lld, count2 %lld, overflow %d\n",
169 count1, count2, overflows);
170
171 if (count1 != 1) {
172 if (count1 == 11)
173 pr_debug("failed: RF EFLAG recursion issue detected\n");
174 else
175 pr_debug("failed: wrong count for bp1%lld\n", count1);
176 }
177
178 if (overflows != 1)
179 pr_debug("failed: wrong overflow hit\n");
180
181 if (count2 != 1)
182 pr_debug("failed: wrong count for bp2\n");
183
184 return count1 == 1 && overflows == 1 && count2 == 1 ?
185 TEST_OK : TEST_FAIL;
186}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index acb98e0e39f2..37b108bf973c 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -78,6 +78,10 @@ static struct test {
78 .func = test__python_use, 78 .func = test__python_use,
79 }, 79 },
80 { 80 {
81 .desc = "Test breakpoint overflow signal handler",
82 .func = test__bp_signal,
83 },
84 {
81 .func = NULL, 85 .func = NULL,
82 }, 86 },
83}; 87};
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 5de0be1ff4b6..05d0e58064a3 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -23,5 +23,6 @@ int test__dso_data(void);
23int test__parse_events(void); 23int test__parse_events(void);
24int test__hists_link(void); 24int test__hists_link(void);
25int test__python_use(void); 25int test__python_use(void);
26int test__bp_signal(void);
26 27
27#endif /* TESTS_H */ 28#endif /* TESTS_H */