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

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

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

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php