diff options
Diffstat (limited to 'tools/perf/tests/bp_signal.c')
-rw-r--r-- | tools/perf/tests/bp_signal.c | 140 |
1 files changed, 118 insertions, 22 deletions
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c index fb80c9eb6a95..e7664fe3bd33 100644 --- a/tools/perf/tests/bp_signal.c +++ b/tools/perf/tests/bp_signal.c | |||
@@ -29,14 +29,59 @@ | |||
29 | 29 | ||
30 | static int fd1; | 30 | static int fd1; |
31 | static int fd2; | 31 | static int fd2; |
32 | static int fd3; | ||
32 | static int overflows; | 33 | static int overflows; |
34 | static int overflows_2; | ||
35 | |||
36 | volatile long the_var; | ||
37 | |||
38 | |||
39 | /* | ||
40 | * Use ASM to ensure watchpoint and breakpoint can be triggered | ||
41 | * at one instruction. | ||
42 | */ | ||
43 | #if defined (__x86_64__) | ||
44 | extern void __test_function(volatile long *ptr); | ||
45 | asm ( | ||
46 | ".globl __test_function\n" | ||
47 | "__test_function:\n" | ||
48 | "incq (%rdi)\n" | ||
49 | "ret\n"); | ||
50 | #elif defined (__aarch64__) | ||
51 | extern void __test_function(volatile long *ptr); | ||
52 | asm ( | ||
53 | ".globl __test_function\n" | ||
54 | "__test_function:\n" | ||
55 | "str x30, [x0]\n" | ||
56 | "ret\n"); | ||
57 | |||
58 | #else | ||
59 | static void __test_function(volatile long *ptr) | ||
60 | { | ||
61 | *ptr = 0x1234; | ||
62 | } | ||
63 | #endif | ||
33 | 64 | ||
34 | __attribute__ ((noinline)) | 65 | __attribute__ ((noinline)) |
35 | static int test_function(void) | 66 | static int test_function(void) |
36 | { | 67 | { |
68 | __test_function(&the_var); | ||
69 | the_var++; | ||
37 | return time(NULL); | 70 | return time(NULL); |
38 | } | 71 | } |
39 | 72 | ||
73 | static void sig_handler_2(int signum __maybe_unused, | ||
74 | siginfo_t *oh __maybe_unused, | ||
75 | void *uc __maybe_unused) | ||
76 | { | ||
77 | overflows_2++; | ||
78 | if (overflows_2 > 10) { | ||
79 | ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); | ||
80 | ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); | ||
81 | ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0); | ||
82 | } | ||
83 | } | ||
84 | |||
40 | static void sig_handler(int signum __maybe_unused, | 85 | static void sig_handler(int signum __maybe_unused, |
41 | siginfo_t *oh __maybe_unused, | 86 | siginfo_t *oh __maybe_unused, |
42 | void *uc __maybe_unused) | 87 | void *uc __maybe_unused) |
@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused, | |||
54 | */ | 99 | */ |
55 | ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); | 100 | ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); |
56 | ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); | 101 | ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); |
102 | ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0); | ||
57 | } | 103 | } |
58 | } | 104 | } |
59 | 105 | ||
60 | static int bp_event(void *fn, int setup_signal) | 106 | static int __event(bool is_x, void *addr, int sig) |
61 | { | 107 | { |
62 | struct perf_event_attr pe; | 108 | struct perf_event_attr pe; |
63 | int fd; | 109 | int fd; |
@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal) | |||
67 | pe.size = sizeof(struct perf_event_attr); | 113 | pe.size = sizeof(struct perf_event_attr); |
68 | 114 | ||
69 | pe.config = 0; | 115 | pe.config = 0; |
70 | pe.bp_type = HW_BREAKPOINT_X; | 116 | pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W; |
71 | pe.bp_addr = (unsigned long) fn; | 117 | pe.bp_addr = (unsigned long) addr; |
72 | pe.bp_len = sizeof(long); | 118 | pe.bp_len = sizeof(long); |
73 | 119 | ||
74 | pe.sample_period = 1; | 120 | pe.sample_period = 1; |
@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal) | |||
86 | return TEST_FAIL; | 132 | return TEST_FAIL; |
87 | } | 133 | } |
88 | 134 | ||
89 | if (setup_signal) { | 135 | fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); |
90 | fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); | 136 | fcntl(fd, F_SETSIG, sig); |
91 | fcntl(fd, F_SETSIG, SIGIO); | 137 | fcntl(fd, F_SETOWN, getpid()); |
92 | fcntl(fd, F_SETOWN, getpid()); | ||
93 | } | ||
94 | 138 | ||
95 | ioctl(fd, PERF_EVENT_IOC_RESET, 0); | 139 | ioctl(fd, PERF_EVENT_IOC_RESET, 0); |
96 | 140 | ||
97 | return fd; | 141 | return fd; |
98 | } | 142 | } |
99 | 143 | ||
144 | static int bp_event(void *addr, int sig) | ||
145 | { | ||
146 | return __event(true, addr, sig); | ||
147 | } | ||
148 | |||
149 | static int wp_event(void *addr, int sig) | ||
150 | { | ||
151 | return __event(false, addr, sig); | ||
152 | } | ||
153 | |||
100 | static long long bp_count(int fd) | 154 | static long long bp_count(int fd) |
101 | { | 155 | { |
102 | long long count; | 156 | long long count; |
@@ -114,7 +168,7 @@ static long long bp_count(int fd) | |||
114 | int test__bp_signal(int subtest __maybe_unused) | 168 | int test__bp_signal(int subtest __maybe_unused) |
115 | { | 169 | { |
116 | struct sigaction sa; | 170 | struct sigaction sa; |
117 | long long count1, count2; | 171 | long long count1, count2, count3; |
118 | 172 | ||
119 | /* setup SIGIO signal handler */ | 173 | /* setup SIGIO signal handler */ |
120 | memset(&sa, 0, sizeof(struct sigaction)); | 174 | memset(&sa, 0, sizeof(struct sigaction)); |
@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused) | |||
126 | return TEST_FAIL; | 180 | return TEST_FAIL; |
127 | } | 181 | } |
128 | 182 | ||
183 | sa.sa_sigaction = (void *) sig_handler_2; | ||
184 | if (sigaction(SIGUSR1, &sa, NULL) < 0) { | ||
185 | pr_debug("failed setting up signal handler 2\n"); | ||
186 | return TEST_FAIL; | ||
187 | } | ||
188 | |||
129 | /* | 189 | /* |
130 | * We create following events: | 190 | * We create following events: |
131 | * | 191 | * |
132 | * fd1 - breakpoint event on test_function with SIGIO | 192 | * fd1 - breakpoint event on __test_function with SIGIO |
133 | * signal configured. We should get signal | 193 | * signal configured. We should get signal |
134 | * notification each time the breakpoint is hit | 194 | * notification each time the breakpoint is hit |
135 | * | 195 | * |
136 | * fd2 - breakpoint event on sig_handler without SIGIO | 196 | * fd2 - breakpoint event on sig_handler with SIGUSR1 |
197 | * configured. We should get SIGUSR1 each time when | ||
198 | * breakpoint is hit | ||
199 | * | ||
200 | * fd3 - watchpoint event on __test_function with SIGIO | ||
137 | * configured. | 201 | * configured. |
138 | * | 202 | * |
139 | * Following processing should happen: | 203 | * Following processing should happen: |
140 | * - execute test_function | 204 | * Exec: Action: Result: |
141 | * - fd1 event breakpoint hit -> count1 == 1 | 205 | * incq (%rdi) - fd1 event breakpoint hit -> count1 == 1 |
142 | * - SIGIO is delivered -> overflows == 1 | 206 | * - SIGIO is delivered |
143 | * - fd2 event breakpoint hit -> count2 == 1 | 207 | * sig_handler - fd2 event breakpoint hit -> count2 == 1 |
208 | * - SIGUSR1 is delivered | ||
209 | * sig_handler_2 -> overflows_2 == 1 (nested signal) | ||
210 | * sys_rt_sigreturn - return from sig_handler_2 | ||
211 | * overflows++ -> overflows = 1 | ||
212 | * sys_rt_sigreturn - return from sig_handler | ||
213 | * incq (%rdi) - fd3 event watchpoint hit -> count3 == 1 (wp and bp in one insn) | ||
214 | * - SIGIO is delivered | ||
215 | * sig_handler - fd2 event breakpoint hit -> count2 == 2 | ||
216 | * - SIGUSR1 is delivered | ||
217 | * sig_handler_2 -> overflows_2 == 2 (nested signal) | ||
218 | * sys_rt_sigreturn - return from sig_handler_2 | ||
219 | * overflows++ -> overflows = 2 | ||
220 | * sys_rt_sigreturn - return from sig_handler | ||
221 | * the_var++ - fd3 event watchpoint hit -> count3 == 2 (standalone watchpoint) | ||
222 | * - SIGIO is delivered | ||
223 | * sig_handler - fd2 event breakpoint hit -> count2 == 3 | ||
224 | * - SIGUSR1 is delivered | ||
225 | * sig_handler_2 -> overflows_2 == 3 (nested signal) | ||
226 | * sys_rt_sigreturn - return from sig_handler_2 | ||
227 | * overflows++ -> overflows == 3 | ||
228 | * sys_rt_sigreturn - return from sig_handler | ||
144 | * | 229 | * |
145 | * The test case check following error conditions: | 230 | * The test case check following error conditions: |
146 | * - we get stuck in signal handler because of debug | 231 | * - we get stuck in signal handler because of debug |
@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused) | |||
152 | * | 237 | * |
153 | */ | 238 | */ |
154 | 239 | ||
155 | fd1 = bp_event(test_function, 1); | 240 | fd1 = bp_event(__test_function, SIGIO); |
156 | fd2 = bp_event(sig_handler, 0); | 241 | fd2 = bp_event(sig_handler, SIGUSR1); |
242 | fd3 = wp_event((void *)&the_var, SIGIO); | ||
157 | 243 | ||
158 | ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); | 244 | ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); |
159 | ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); | 245 | ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); |
246 | ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0); | ||
160 | 247 | ||
161 | /* | 248 | /* |
162 | * Kick off the test by trigering 'fd1' | 249 | * Kick off the test by trigering 'fd1' |
@@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused) | |||
166 | 253 | ||
167 | ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); | 254 | ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); |
168 | ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); | 255 | ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); |
256 | ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0); | ||
169 | 257 | ||
170 | count1 = bp_count(fd1); | 258 | count1 = bp_count(fd1); |
171 | count2 = bp_count(fd2); | 259 | count2 = bp_count(fd2); |
260 | count3 = bp_count(fd3); | ||
172 | 261 | ||
173 | close(fd1); | 262 | close(fd1); |
174 | close(fd2); | 263 | close(fd2); |
264 | close(fd3); | ||
175 | 265 | ||
176 | pr_debug("count1 %lld, count2 %lld, overflow %d\n", | 266 | pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n", |
177 | count1, count2, overflows); | 267 | count1, count2, count3, overflows, overflows_2); |
178 | 268 | ||
179 | if (count1 != 1) { | 269 | if (count1 != 1) { |
180 | if (count1 == 11) | 270 | if (count1 == 11) |
@@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused) | |||
183 | pr_debug("failed: wrong count for bp1%lld\n", count1); | 273 | pr_debug("failed: wrong count for bp1%lld\n", count1); |
184 | } | 274 | } |
185 | 275 | ||
186 | if (overflows != 1) | 276 | if (overflows != 3) |
187 | pr_debug("failed: wrong overflow hit\n"); | 277 | pr_debug("failed: wrong overflow hit\n"); |
188 | 278 | ||
189 | if (count2 != 1) | 279 | if (overflows_2 != 3) |
280 | pr_debug("failed: wrong overflow_2 hit\n"); | ||
281 | |||
282 | if (count2 != 3) | ||
190 | pr_debug("failed: wrong count for bp2\n"); | 283 | pr_debug("failed: wrong count for bp2\n"); |
191 | 284 | ||
192 | return count1 == 1 && overflows == 1 && count2 == 1 ? | 285 | if (count3 != 2) |
286 | pr_debug("failed: wrong count for bp3\n"); | ||
287 | |||
288 | return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ? | ||
193 | TEST_OK : TEST_FAIL; | 289 | TEST_OK : TEST_FAIL; |
194 | } | 290 | } |