~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/powerpc/ptrace/ptrace-hwbreak.c

Version: ~ [ linux-5.13-rc5 ] ~ [ linux-5.12.9 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.42 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.124 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.193 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.235 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.271 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.271 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 
  3 /*
  4  * Ptrace test for hw breakpoints
  5  *
  6  * Based on tools/testing/selftests/breakpoints/breakpoint_test.c
  7  *
  8  * This test forks and the parent then traces the child doing various
  9  * types of ptrace enabled breakpoints
 10  *
 11  * Copyright (C) 2018 Michael Neuling, IBM Corporation.
 12  */
 13 
 14 #include <sys/ptrace.h>
 15 #include <unistd.h>
 16 #include <stddef.h>
 17 #include <sys/user.h>
 18 #include <stdio.h>
 19 #include <stdlib.h>
 20 #include <signal.h>
 21 #include <sys/types.h>
 22 #include <sys/wait.h>
 23 #include <sys/syscall.h>
 24 #include <linux/limits.h>
 25 #include "ptrace.h"
 26 
 27 #define SPRN_PVR        0x11F
 28 #define PVR_8xx         0x00500000
 29 
 30 bool is_8xx;
 31 
 32 /*
 33  * Use volatile on all global var so that compiler doesn't
 34  * optimise their load/stores. Otherwise selftest can fail.
 35  */
 36 static volatile __u64 glvar;
 37 
 38 #define DAWR_MAX_LEN 512
 39 static volatile __u8 big_var[DAWR_MAX_LEN] __attribute__((aligned(512)));
 40 
 41 #define A_LEN 6
 42 #define B_LEN 6
 43 struct gstruct {
 44         __u8 a[A_LEN]; /* double word aligned */
 45         __u8 b[B_LEN]; /* double word unaligned */
 46 };
 47 static volatile struct gstruct gstruct __attribute__((aligned(512)));
 48 
 49 static volatile char cwd[PATH_MAX] __attribute__((aligned(8)));
 50 
 51 static void get_dbginfo(pid_t child_pid, struct ppc_debug_info *dbginfo)
 52 {
 53         if (ptrace(PPC_PTRACE_GETHWDBGINFO, child_pid, NULL, dbginfo)) {
 54                 perror("Can't get breakpoint info");
 55                 exit(-1);
 56         }
 57 }
 58 
 59 static bool dawr_present(struct ppc_debug_info *dbginfo)
 60 {
 61         return !!(dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_DAWR);
 62 }
 63 
 64 static void write_var(int len)
 65 {
 66         __u8 *pcvar;
 67         __u16 *psvar;
 68         __u32 *pivar;
 69         __u64 *plvar;
 70 
 71         switch (len) {
 72         case 1:
 73                 pcvar = (__u8 *)&glvar;
 74                 *pcvar = 0xff;
 75                 break;
 76         case 2:
 77                 psvar = (__u16 *)&glvar;
 78                 *psvar = 0xffff;
 79                 break;
 80         case 4:
 81                 pivar = (__u32 *)&glvar;
 82                 *pivar = 0xffffffff;
 83                 break;
 84         case 8:
 85                 plvar = (__u64 *)&glvar;
 86                 *plvar = 0xffffffffffffffffLL;
 87                 break;
 88         }
 89 }
 90 
 91 static void read_var(int len)
 92 {
 93         __u8 cvar __attribute__((unused));
 94         __u16 svar __attribute__((unused));
 95         __u32 ivar __attribute__((unused));
 96         __u64 lvar __attribute__((unused));
 97 
 98         switch (len) {
 99         case 1:
100                 cvar = (__u8)glvar;
101                 break;
102         case 2:
103                 svar = (__u16)glvar;
104                 break;
105         case 4:
106                 ivar = (__u32)glvar;
107                 break;
108         case 8:
109                 lvar = (__u64)glvar;
110                 break;
111         }
112 }
113 
114 static void test_workload(void)
115 {
116         __u8 cvar __attribute__((unused));
117         __u32 ivar __attribute__((unused));
118         int len = 0;
119 
120         if (ptrace(PTRACE_TRACEME, 0, NULL, 0)) {
121                 perror("Child can't be traced?");
122                 exit(-1);
123         }
124 
125         /* Wake up father so that it sets up the first test */
126         kill(getpid(), SIGUSR1);
127 
128         /* PTRACE_SET_DEBUGREG, WO test */
129         for (len = 1; len <= sizeof(glvar); len <<= 1)
130                 write_var(len);
131 
132         /* PTRACE_SET_DEBUGREG, RO test */
133         for (len = 1; len <= sizeof(glvar); len <<= 1)
134                 read_var(len);
135 
136         /* PTRACE_SET_DEBUGREG, RW test */
137         for (len = 1; len <= sizeof(glvar); len <<= 1) {
138                 if (rand() % 2)
139                         read_var(len);
140                 else
141                         write_var(len);
142         }
143 
144         /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
145         syscall(__NR_getcwd, &cwd, PATH_MAX);
146 
147         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
148         write_var(1);
149 
150         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
151         read_var(1);
152 
153         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
154         if (rand() % 2)
155                 write_var(1);
156         else
157                 read_var(1);
158 
159         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
160         syscall(__NR_getcwd, &cwd, PATH_MAX);
161 
162         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
163         gstruct.a[rand() % A_LEN] = 'a';
164 
165         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
166         cvar = gstruct.a[rand() % A_LEN];
167 
168         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
169         if (rand() % 2)
170                 gstruct.a[rand() % A_LEN] = 'a';
171         else
172                 cvar = gstruct.a[rand() % A_LEN];
173 
174         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
175         gstruct.b[rand() % B_LEN] = 'b';
176 
177         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
178         cvar = gstruct.b[rand() % B_LEN];
179 
180         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
181         if (rand() % 2)
182                 gstruct.b[rand() % B_LEN] = 'b';
183         else
184                 cvar = gstruct.b[rand() % B_LEN];
185 
186         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
187         if (rand() % 2)
188                 *((int *)(gstruct.a + 4)) = 10;
189         else
190                 ivar = *((int *)(gstruct.a + 4));
191 
192         /* PPC_PTRACE_SETHWDEBUG. DAWR_MAX_LEN. RW test */
193         if (rand() % 2)
194                 big_var[rand() % DAWR_MAX_LEN] = 'a';
195         else
196                 cvar = big_var[rand() % DAWR_MAX_LEN];
197 
198         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
199         gstruct.a[rand() % A_LEN] = 'a';
200 
201         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
202         cvar = gstruct.b[rand() % B_LEN];
203 
204         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
205         gstruct.a[rand() % A_LEN] = 'a';
206 
207         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
208         cvar = gstruct.a[rand() % A_LEN];
209 }
210 
211 static void check_success(pid_t child_pid, const char *name, const char *type,
212                           unsigned long saddr, int len)
213 {
214         int status;
215         siginfo_t siginfo;
216         unsigned long eaddr = (saddr + len - 1) | 0x7;
217 
218         saddr &= ~0x7;
219 
220         /* Wait for the child to SIGTRAP */
221         wait(&status);
222 
223         ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &siginfo);
224 
225         if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP ||
226             (unsigned long)siginfo.si_addr < saddr ||
227             (unsigned long)siginfo.si_addr > eaddr) {
228                 printf("%s, %s, len: %d: Fail\n", name, type, len);
229                 exit(-1);
230         }
231 
232         printf("%s, %s, len: %d: Ok\n", name, type, len);
233 
234         if (!is_8xx) {
235                 /*
236                  * For ptrace registered watchpoint, signal is generated
237                  * before executing load/store. Singlestep the instruction
238                  * and then continue the test.
239                  */
240                 ptrace(PTRACE_SINGLESTEP, child_pid, NULL, 0);
241                 wait(NULL);
242         }
243 }
244 
245 static void ptrace_set_debugreg(pid_t child_pid, unsigned long wp_addr)
246 {
247         if (ptrace(PTRACE_SET_DEBUGREG, child_pid, 0, wp_addr)) {
248                 perror("PTRACE_SET_DEBUGREG failed");
249                 exit(-1);
250         }
251 }
252 
253 static int ptrace_sethwdebug(pid_t child_pid, struct ppc_hw_breakpoint *info)
254 {
255         int wh = ptrace(PPC_PTRACE_SETHWDEBUG, child_pid, 0, info);
256 
257         if (wh <= 0) {
258                 perror("PPC_PTRACE_SETHWDEBUG failed");
259                 exit(-1);
260         }
261         return wh;
262 }
263 
264 static void ptrace_delhwdebug(pid_t child_pid, int wh)
265 {
266         if (ptrace(PPC_PTRACE_DELHWDEBUG, child_pid, 0, wh) < 0) {
267                 perror("PPC_PTRACE_DELHWDEBUG failed");
268                 exit(-1);
269         }
270 }
271 
272 #define DABR_READ_SHIFT         0
273 #define DABR_WRITE_SHIFT        1
274 #define DABR_TRANSLATION_SHIFT  2
275 
276 static int test_set_debugreg(pid_t child_pid)
277 {
278         unsigned long wp_addr = (unsigned long)&glvar;
279         char *name = "PTRACE_SET_DEBUGREG";
280         int len;
281 
282         /* PTRACE_SET_DEBUGREG, WO test*/
283         wp_addr &= ~0x7UL;
284         wp_addr |= (1UL << DABR_WRITE_SHIFT);
285         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
286         for (len = 1; len <= sizeof(glvar); len <<= 1) {
287                 ptrace_set_debugreg(child_pid, wp_addr);
288                 ptrace(PTRACE_CONT, child_pid, NULL, 0);
289                 check_success(child_pid, name, "WO", wp_addr, len);
290         }
291 
292         /* PTRACE_SET_DEBUGREG, RO test */
293         wp_addr &= ~0x7UL;
294         wp_addr |= (1UL << DABR_READ_SHIFT);
295         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
296         for (len = 1; len <= sizeof(glvar); len <<= 1) {
297                 ptrace_set_debugreg(child_pid, wp_addr);
298                 ptrace(PTRACE_CONT, child_pid, NULL, 0);
299                 check_success(child_pid, name, "RO", wp_addr, len);
300         }
301 
302         /* PTRACE_SET_DEBUGREG, RW test */
303         wp_addr &= ~0x7UL;
304         wp_addr |= (1Ul << DABR_READ_SHIFT);
305         wp_addr |= (1UL << DABR_WRITE_SHIFT);
306         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
307         for (len = 1; len <= sizeof(glvar); len <<= 1) {
308                 ptrace_set_debugreg(child_pid, wp_addr);
309                 ptrace(PTRACE_CONT, child_pid, NULL, 0);
310                 check_success(child_pid, name, "RW", wp_addr, len);
311         }
312 
313         ptrace_set_debugreg(child_pid, 0);
314         return 0;
315 }
316 
317 static int test_set_debugreg_kernel_userspace(pid_t child_pid)
318 {
319         unsigned long wp_addr = (unsigned long)cwd;
320         char *name = "PTRACE_SET_DEBUGREG";
321 
322         /* PTRACE_SET_DEBUGREG, Kernel Access Userspace test */
323         wp_addr &= ~0x7UL;
324         wp_addr |= (1Ul << DABR_READ_SHIFT);
325         wp_addr |= (1UL << DABR_WRITE_SHIFT);
326         wp_addr |= (1UL << DABR_TRANSLATION_SHIFT);
327         ptrace_set_debugreg(child_pid, wp_addr);
328         ptrace(PTRACE_CONT, child_pid, NULL, 0);
329         check_success(child_pid, name, "Kernel Access Userspace", wp_addr, 8);
330 
331         ptrace_set_debugreg(child_pid, 0);
332         return 0;
333 }
334 
335 static void get_ppc_hw_breakpoint(struct ppc_hw_breakpoint *info, int type,
336                                   unsigned long addr, int len)
337 {
338         info->version = 1;
339         info->trigger_type = type;
340         info->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
341         info->addr = (__u64)addr;
342         info->addr2 = (__u64)addr + len;
343         info->condition_value = 0;
344         if (!len)
345                 info->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
346         else
347                 info->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
348 }
349 
350 static void test_sethwdebug_exact(pid_t child_pid)
351 {
352         struct ppc_hw_breakpoint info;
353         unsigned long wp_addr = (unsigned long)&glvar;
354         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
355         int len = 1; /* hardcoded in kernel */
356         int wh;
357 
358         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, WO test */
359         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
360         wh = ptrace_sethwdebug(child_pid, &info);
361         ptrace(PTRACE_CONT, child_pid, NULL, 0);
362         check_success(child_pid, name, "WO", wp_addr, len);
363         ptrace_delhwdebug(child_pid, wh);
364 
365         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RO test */
366         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, 0);
367         wh = ptrace_sethwdebug(child_pid, &info);
368         ptrace(PTRACE_CONT, child_pid, NULL, 0);
369         check_success(child_pid, name, "RO", wp_addr, len);
370         ptrace_delhwdebug(child_pid, wh);
371 
372         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, RW test */
373         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, 0);
374         wh = ptrace_sethwdebug(child_pid, &info);
375         ptrace(PTRACE_CONT, child_pid, NULL, 0);
376         check_success(child_pid, name, "RW", wp_addr, len);
377         ptrace_delhwdebug(child_pid, wh);
378 }
379 
380 static void test_sethwdebug_exact_kernel_userspace(pid_t child_pid)
381 {
382         struct ppc_hw_breakpoint info;
383         unsigned long wp_addr = (unsigned long)&cwd;
384         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_EXACT";
385         int len = 1; /* hardcoded in kernel */
386         int wh;
387 
388         /* PPC_PTRACE_SETHWDEBUG, MODE_EXACT, Kernel Access Userspace test */
389         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, 0);
390         wh = ptrace_sethwdebug(child_pid, &info);
391         ptrace(PTRACE_CONT, child_pid, NULL, 0);
392         check_success(child_pid, name, "Kernel Access Userspace", wp_addr, len);
393         ptrace_delhwdebug(child_pid, wh);
394 }
395 
396 static void test_sethwdebug_range_aligned(pid_t child_pid)
397 {
398         struct ppc_hw_breakpoint info;
399         unsigned long wp_addr;
400         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED";
401         int len;
402         int wh;
403 
404         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, WO test */
405         wp_addr = (unsigned long)&gstruct.a;
406         len = A_LEN;
407         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
408         wh = ptrace_sethwdebug(child_pid, &info);
409         ptrace(PTRACE_CONT, child_pid, NULL, 0);
410         check_success(child_pid, name, "WO", wp_addr, len);
411         ptrace_delhwdebug(child_pid, wh);
412 
413         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RO test */
414         wp_addr = (unsigned long)&gstruct.a;
415         len = A_LEN;
416         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
417         wh = ptrace_sethwdebug(child_pid, &info);
418         ptrace(PTRACE_CONT, child_pid, NULL, 0);
419         check_success(child_pid, name, "RO", wp_addr, len);
420         ptrace_delhwdebug(child_pid, wh);
421 
422         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW ALIGNED, RW test */
423         wp_addr = (unsigned long)&gstruct.a;
424         len = A_LEN;
425         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
426         wh = ptrace_sethwdebug(child_pid, &info);
427         ptrace(PTRACE_CONT, child_pid, NULL, 0);
428         check_success(child_pid, name, "RW", wp_addr, len);
429         ptrace_delhwdebug(child_pid, wh);
430 }
431 
432 static void test_multi_sethwdebug_range(pid_t child_pid)
433 {
434         struct ppc_hw_breakpoint info1, info2;
435         unsigned long wp_addr1, wp_addr2;
436         char *name1 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED";
437         char *name2 = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED";
438         int len1, len2;
439         int wh1, wh2;
440 
441         wp_addr1 = (unsigned long)&gstruct.a;
442         wp_addr2 = (unsigned long)&gstruct.b;
443         len1 = A_LEN;
444         len2 = B_LEN;
445         get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
446         get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
447 
448         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW ALIGNED, WO test */
449         wh1 = ptrace_sethwdebug(child_pid, &info1);
450 
451         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DW UNALIGNED, RO test */
452         wh2 = ptrace_sethwdebug(child_pid, &info2);
453 
454         ptrace(PTRACE_CONT, child_pid, NULL, 0);
455         check_success(child_pid, name1, "WO", wp_addr1, len1);
456 
457         ptrace(PTRACE_CONT, child_pid, NULL, 0);
458         check_success(child_pid, name2, "RO", wp_addr2, len2);
459 
460         ptrace_delhwdebug(child_pid, wh1);
461         ptrace_delhwdebug(child_pid, wh2);
462 }
463 
464 static void test_multi_sethwdebug_range_dawr_overlap(pid_t child_pid)
465 {
466         struct ppc_hw_breakpoint info1, info2;
467         unsigned long wp_addr1, wp_addr2;
468         char *name = "PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap";
469         int len1, len2;
470         int wh1, wh2;
471 
472         wp_addr1 = (unsigned long)&gstruct.a;
473         wp_addr2 = (unsigned long)&gstruct.a;
474         len1 = A_LEN;
475         len2 = A_LEN;
476         get_ppc_hw_breakpoint(&info1, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr1, len1);
477         get_ppc_hw_breakpoint(&info2, PPC_BREAKPOINT_TRIGGER_READ, wp_addr2, len2);
478 
479         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, WO test */
480         wh1 = ptrace_sethwdebug(child_pid, &info1);
481 
482         /* PPC_PTRACE_SETHWDEBUG 2, MODE_RANGE, DAWR Overlap, RO test */
483         wh2 = ptrace_sethwdebug(child_pid, &info2);
484 
485         ptrace(PTRACE_CONT, child_pid, NULL, 0);
486         check_success(child_pid, name, "WO", wp_addr1, len1);
487 
488         ptrace(PTRACE_CONT, child_pid, NULL, 0);
489         check_success(child_pid, name, "RO", wp_addr2, len2);
490 
491         ptrace_delhwdebug(child_pid, wh1);
492         ptrace_delhwdebug(child_pid, wh2);
493 }
494 
495 static void test_sethwdebug_range_unaligned(pid_t child_pid)
496 {
497         struct ppc_hw_breakpoint info;
498         unsigned long wp_addr;
499         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED";
500         int len;
501         int wh;
502 
503         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, WO test */
504         wp_addr = (unsigned long)&gstruct.b;
505         len = B_LEN;
506         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
507         wh = ptrace_sethwdebug(child_pid, &info);
508         ptrace(PTRACE_CONT, child_pid, NULL, 0);
509         check_success(child_pid, name, "WO", wp_addr, len);
510         ptrace_delhwdebug(child_pid, wh);
511 
512         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RO test */
513         wp_addr = (unsigned long)&gstruct.b;
514         len = B_LEN;
515         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_READ, wp_addr, len);
516         wh = ptrace_sethwdebug(child_pid, &info);
517         ptrace(PTRACE_CONT, child_pid, NULL, 0);
518         check_success(child_pid, name, "RO", wp_addr, len);
519         ptrace_delhwdebug(child_pid, wh);
520 
521         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, RW test */
522         wp_addr = (unsigned long)&gstruct.b;
523         len = B_LEN;
524         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
525         wh = ptrace_sethwdebug(child_pid, &info);
526         ptrace(PTRACE_CONT, child_pid, NULL, 0);
527         check_success(child_pid, name, "RW", wp_addr, len);
528         ptrace_delhwdebug(child_pid, wh);
529 
530 }
531 
532 static void test_sethwdebug_range_unaligned_dar(pid_t child_pid)
533 {
534         struct ppc_hw_breakpoint info;
535         unsigned long wp_addr;
536         char *name = "PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE";
537         int len;
538         int wh;
539 
540         /* PPC_PTRACE_SETHWDEBUG, MODE_RANGE, DW UNALIGNED, DAR OUTSIDE, RW test */
541         wp_addr = (unsigned long)&gstruct.b;
542         len = B_LEN;
543         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_WRITE, wp_addr, len);
544         wh = ptrace_sethwdebug(child_pid, &info);
545         ptrace(PTRACE_CONT, child_pid, NULL, 0);
546         check_success(child_pid, name, "RW", wp_addr, len);
547         ptrace_delhwdebug(child_pid, wh);
548 }
549 
550 static void test_sethwdebug_dawr_max_range(pid_t child_pid)
551 {
552         struct ppc_hw_breakpoint info;
553         unsigned long wp_addr;
554         char *name = "PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN";
555         int len;
556         int wh;
557 
558         /* PPC_PTRACE_SETHWDEBUG, DAWR_MAX_LEN, RW test */
559         wp_addr = (unsigned long)big_var;
560         len = DAWR_MAX_LEN;
561         get_ppc_hw_breakpoint(&info, PPC_BREAKPOINT_TRIGGER_RW, wp_addr, len);
562         wh = ptrace_sethwdebug(child_pid, &info);
563         ptrace(PTRACE_CONT, child_pid, NULL, 0);
564         check_success(child_pid, name, "RW", wp_addr, len);
565         ptrace_delhwdebug(child_pid, wh);
566 }
567 
568 /* Set the breakpoints and check the child successfully trigger them */
569 static void
570 run_tests(pid_t child_pid, struct ppc_debug_info *dbginfo, bool dawr)
571 {
572         test_set_debugreg(child_pid);
573         test_set_debugreg_kernel_userspace(child_pid);
574         test_sethwdebug_exact(child_pid);
575         test_sethwdebug_exact_kernel_userspace(child_pid);
576         if (dbginfo->features & PPC_DEBUG_FEATURE_DATA_BP_RANGE) {
577                 test_sethwdebug_range_aligned(child_pid);
578                 if (dawr || is_8xx) {
579                         test_sethwdebug_range_unaligned(child_pid);
580                         test_sethwdebug_range_unaligned_dar(child_pid);
581                         test_sethwdebug_dawr_max_range(child_pid);
582                         if (dbginfo->num_data_bps > 1) {
583                                 test_multi_sethwdebug_range(child_pid);
584                                 test_multi_sethwdebug_range_dawr_overlap(child_pid);
585                         }
586                 }
587         }
588 }
589 
590 static int ptrace_hwbreak(void)
591 {
592         pid_t child_pid;
593         struct ppc_debug_info dbginfo;
594         bool dawr;
595 
596         child_pid = fork();
597         if (!child_pid) {
598                 test_workload();
599                 return 0;
600         }
601 
602         wait(NULL);
603 
604         get_dbginfo(child_pid, &dbginfo);
605         SKIP_IF(dbginfo.num_data_bps == 0);
606 
607         dawr = dawr_present(&dbginfo);
608         run_tests(child_pid, &dbginfo, dawr);
609 
610         /* Let the child exit first. */
611         ptrace(PTRACE_CONT, child_pid, NULL, 0);
612         wait(NULL);
613 
614         /*
615          * Testcases exits immediately with -1 on any failure. If
616          * it has reached here, it means all tests were successful.
617          */
618         return TEST_PASS;
619 }
620 
621 int main(int argc, char **argv, char **envp)
622 {
623         int pvr = 0;
624         asm __volatile__ ("mfspr %0,%1" : "=r"(pvr) : "i"(SPRN_PVR));
625         if (pvr == PVR_8xx)
626                 is_8xx = true;
627 
628         return test_harness(ptrace_hwbreak, "ptrace-hwbreak");
629 }
630 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp