1 /*
2 * Ptrace interface test helper functions
3 *
4 * Copyright (C) 2015 Anshuman Khandual, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11 #include <inttypes.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <malloc.h>
16 #include <errno.h>
17 #include <time.h>
18 #include <sys/ptrace.h>
19 #include <sys/ioctl.h>
20 #include <sys/uio.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <sys/signal.h>
24 #include <sys/ipc.h>
25 #include <sys/shm.h>
26 #include <sys/user.h>
27 #include <linux/elf.h>
28 #include <linux/types.h>
29 #include <linux/auxvec.h>
30 #include "reg.h"
31 #include "utils.h"
32
33 #define TEST_PASS 0
34 #define TEST_FAIL 1
35
36 struct fpr_regs {
37 unsigned long fpr[32];
38 unsigned long fpscr;
39 };
40
41 struct tm_spr_regs {
42 unsigned long tm_tfhar;
43 unsigned long tm_texasr;
44 unsigned long tm_tfiar;
45 };
46
47 #ifndef NT_PPC_TAR
48 #define NT_PPC_TAR 0x103
49 #define NT_PPC_PPR 0x104
50 #define NT_PPC_DSCR 0x105
51 #define NT_PPC_EBB 0x106
52 #define NT_PPC_PMU 0x107
53 #define NT_PPC_TM_CGPR 0x108
54 #define NT_PPC_TM_CFPR 0x109
55 #define NT_PPC_TM_CVMX 0x10a
56 #define NT_PPC_TM_CVSX 0x10b
57 #define NT_PPC_TM_SPR 0x10c
58 #define NT_PPC_TM_CTAR 0x10d
59 #define NT_PPC_TM_CPPR 0x10e
60 #define NT_PPC_TM_CDSCR 0x10f
61 #endif
62
63 /* Basic ptrace operations */
start_trace(pid_t child)64 int start_trace(pid_t child)
65 {
66 int ret;
67
68 ret = ptrace(PTRACE_ATTACH, child, NULL, NULL);
69 if (ret) {
70 perror("ptrace(PTRACE_ATTACH) failed");
71 return TEST_FAIL;
72 }
73 ret = waitpid(child, NULL, 0);
74 if (ret != child) {
75 perror("waitpid() failed");
76 return TEST_FAIL;
77 }
78 return TEST_PASS;
79 }
80
stop_trace(pid_t child)81 int stop_trace(pid_t child)
82 {
83 int ret;
84
85 ret = ptrace(PTRACE_DETACH, child, NULL, NULL);
86 if (ret) {
87 perror("ptrace(PTRACE_DETACH) failed");
88 return TEST_FAIL;
89 }
90 return TEST_PASS;
91 }
92
cont_trace(pid_t child)93 int cont_trace(pid_t child)
94 {
95 int ret;
96
97 ret = ptrace(PTRACE_CONT, child, NULL, NULL);
98 if (ret) {
99 perror("ptrace(PTRACE_CONT) failed");
100 return TEST_FAIL;
101 }
102 return TEST_PASS;
103 }
104
105 /* TAR, PPR, DSCR */
show_tar_registers(pid_t child,unsigned long * out)106 int show_tar_registers(pid_t child, unsigned long *out)
107 {
108 struct iovec iov;
109 unsigned long *reg;
110 int ret;
111
112 reg = malloc(sizeof(unsigned long));
113 if (!reg) {
114 perror("malloc() failed");
115 return TEST_FAIL;
116 }
117 iov.iov_base = (u64 *) reg;
118 iov.iov_len = sizeof(unsigned long);
119
120 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TAR, &iov);
121 if (ret) {
122 perror("ptrace(PTRACE_GETREGSET) failed");
123 goto fail;
124 }
125 if (out)
126 out[0] = *reg;
127
128 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_PPR, &iov);
129 if (ret) {
130 perror("ptrace(PTRACE_GETREGSET) failed");
131 goto fail;
132 }
133 if (out)
134 out[1] = *reg;
135
136 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_DSCR, &iov);
137 if (ret) {
138 perror("ptrace(PTRACE_GETREGSET) failed");
139 goto fail;
140 }
141 if (out)
142 out[2] = *reg;
143
144 free(reg);
145 return TEST_PASS;
146 fail:
147 free(reg);
148 return TEST_FAIL;
149 }
150
write_tar_registers(pid_t child,unsigned long tar,unsigned long ppr,unsigned long dscr)151 int write_tar_registers(pid_t child, unsigned long tar,
152 unsigned long ppr, unsigned long dscr)
153 {
154 struct iovec iov;
155 unsigned long *reg;
156 int ret;
157
158 reg = malloc(sizeof(unsigned long));
159 if (!reg) {
160 perror("malloc() failed");
161 return TEST_FAIL;
162 }
163
164 iov.iov_base = (u64 *) reg;
165 iov.iov_len = sizeof(unsigned long);
166
167 *reg = tar;
168 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TAR, &iov);
169 if (ret) {
170 perror("ptrace(PTRACE_SETREGSET) failed");
171 goto fail;
172 }
173
174 *reg = ppr;
175 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_PPR, &iov);
176 if (ret) {
177 perror("ptrace(PTRACE_SETREGSET) failed");
178 goto fail;
179 }
180
181 *reg = dscr;
182 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_DSCR, &iov);
183 if (ret) {
184 perror("ptrace(PTRACE_SETREGSET) failed");
185 goto fail;
186 }
187
188 free(reg);
189 return TEST_PASS;
190 fail:
191 free(reg);
192 return TEST_FAIL;
193 }
194
show_tm_checkpointed_state(pid_t child,unsigned long * out)195 int show_tm_checkpointed_state(pid_t child, unsigned long *out)
196 {
197 struct iovec iov;
198 unsigned long *reg;
199 int ret;
200
201 reg = malloc(sizeof(unsigned long));
202 if (!reg) {
203 perror("malloc() failed");
204 return TEST_FAIL;
205 }
206
207 iov.iov_base = (u64 *) reg;
208 iov.iov_len = sizeof(unsigned long);
209
210 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CTAR, &iov);
211 if (ret) {
212 perror("ptrace(PTRACE_GETREGSET) failed");
213 goto fail;
214 }
215 if (out)
216 out[0] = *reg;
217
218 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CPPR, &iov);
219 if (ret) {
220 perror("ptrace(PTRACE_GETREGSET) failed");
221 goto fail;
222 }
223 if (out)
224 out[1] = *reg;
225
226 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CDSCR, &iov);
227 if (ret) {
228 perror("ptrace(PTRACE_GETREGSET) failed");
229 goto fail;
230 }
231 if (out)
232 out[2] = *reg;
233
234 free(reg);
235 return TEST_PASS;
236
237 fail:
238 free(reg);
239 return TEST_FAIL;
240 }
241
write_ckpt_tar_registers(pid_t child,unsigned long tar,unsigned long ppr,unsigned long dscr)242 int write_ckpt_tar_registers(pid_t child, unsigned long tar,
243 unsigned long ppr, unsigned long dscr)
244 {
245 struct iovec iov;
246 unsigned long *reg;
247 int ret;
248
249 reg = malloc(sizeof(unsigned long));
250 if (!reg) {
251 perror("malloc() failed");
252 return TEST_FAIL;
253 }
254
255 iov.iov_base = (u64 *) reg;
256 iov.iov_len = sizeof(unsigned long);
257
258 *reg = tar;
259 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CTAR, &iov);
260 if (ret) {
261 perror("ptrace(PTRACE_GETREGSET) failed");
262 goto fail;
263 }
264
265 *reg = ppr;
266 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CPPR, &iov);
267 if (ret) {
268 perror("ptrace(PTRACE_GETREGSET) failed");
269 goto fail;
270 }
271
272 *reg = dscr;
273 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CDSCR, &iov);
274 if (ret) {
275 perror("ptrace(PTRACE_GETREGSET) failed");
276 goto fail;
277 }
278
279 free(reg);
280 return TEST_PASS;
281 fail:
282 free(reg);
283 return TEST_FAIL;
284 }
285
286 /* FPR */
show_fpr(pid_t child,unsigned long * fpr)287 int show_fpr(pid_t child, unsigned long *fpr)
288 {
289 struct fpr_regs *regs;
290 int ret, i;
291
292 regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
293 ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs);
294 if (ret) {
295 perror("ptrace(PTRACE_GETREGSET) failed");
296 return TEST_FAIL;
297 }
298
299 if (fpr) {
300 for (i = 0; i < 32; i++)
301 fpr[i] = regs->fpr[i];
302 }
303 return TEST_PASS;
304 }
305
write_fpr(pid_t child,unsigned long val)306 int write_fpr(pid_t child, unsigned long val)
307 {
308 struct fpr_regs *regs;
309 int ret, i;
310
311 regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
312 ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs);
313 if (ret) {
314 perror("ptrace(PTRACE_GETREGSET) failed");
315 return TEST_FAIL;
316 }
317
318 for (i = 0; i < 32; i++)
319 regs->fpr[i] = val;
320
321 ret = ptrace(PTRACE_SETFPREGS, child, NULL, regs);
322 if (ret) {
323 perror("ptrace(PTRACE_GETREGSET) failed");
324 return TEST_FAIL;
325 }
326 return TEST_PASS;
327 }
328
show_ckpt_fpr(pid_t child,unsigned long * fpr)329 int show_ckpt_fpr(pid_t child, unsigned long *fpr)
330 {
331 struct fpr_regs *regs;
332 struct iovec iov;
333 int ret, i;
334
335 regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
336 iov.iov_base = regs;
337 iov.iov_len = sizeof(struct fpr_regs);
338
339 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
340 if (ret) {
341 perror("ptrace(PTRACE_GETREGSET) failed");
342 return TEST_FAIL;
343 }
344
345 if (fpr) {
346 for (i = 0; i < 32; i++)
347 fpr[i] = regs->fpr[i];
348 }
349
350 return TEST_PASS;
351 }
352
write_ckpt_fpr(pid_t child,unsigned long val)353 int write_ckpt_fpr(pid_t child, unsigned long val)
354 {
355 struct fpr_regs *regs;
356 struct iovec iov;
357 int ret, i;
358
359 regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs));
360 iov.iov_base = regs;
361 iov.iov_len = sizeof(struct fpr_regs);
362
363 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov);
364 if (ret) {
365 perror("ptrace(PTRACE_GETREGSET) failed");
366 return TEST_FAIL;
367 }
368
369 for (i = 0; i < 32; i++)
370 regs->fpr[i] = val;
371
372 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CFPR, &iov);
373 if (ret) {
374 perror("ptrace(PTRACE_GETREGSET) failed");
375 return TEST_FAIL;
376 }
377 return TEST_PASS;
378 }
379
380 /* GPR */
show_gpr(pid_t child,unsigned long * gpr)381 int show_gpr(pid_t child, unsigned long *gpr)
382 {
383 struct pt_regs *regs;
384 int ret, i;
385
386 regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
387 if (!regs) {
388 perror("malloc() failed");
389 return TEST_FAIL;
390 }
391
392 ret = ptrace(PTRACE_GETREGS, child, NULL, regs);
393 if (ret) {
394 perror("ptrace(PTRACE_GETREGSET) failed");
395 return TEST_FAIL;
396 }
397
398 if (gpr) {
399 for (i = 14; i < 32; i++)
400 gpr[i-14] = regs->gpr[i];
401 }
402
403 return TEST_PASS;
404 }
405
write_gpr(pid_t child,unsigned long val)406 int write_gpr(pid_t child, unsigned long val)
407 {
408 struct pt_regs *regs;
409 int i, ret;
410
411 regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
412 if (!regs) {
413 perror("malloc() failed");
414 return TEST_FAIL;
415 }
416
417 ret = ptrace(PTRACE_GETREGS, child, NULL, regs);
418 if (ret) {
419 perror("ptrace(PTRACE_GETREGSET) failed");
420 return TEST_FAIL;
421 }
422
423 for (i = 14; i < 32; i++)
424 regs->gpr[i] = val;
425
426 ret = ptrace(PTRACE_SETREGS, child, NULL, regs);
427 if (ret) {
428 perror("ptrace(PTRACE_GETREGSET) failed");
429 return TEST_FAIL;
430 }
431 return TEST_PASS;
432 }
433
show_ckpt_gpr(pid_t child,unsigned long * gpr)434 int show_ckpt_gpr(pid_t child, unsigned long *gpr)
435 {
436 struct pt_regs *regs;
437 struct iovec iov;
438 int ret, i;
439
440 regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
441 if (!regs) {
442 perror("malloc() failed");
443 return TEST_FAIL;
444 }
445
446 iov.iov_base = (u64 *) regs;
447 iov.iov_len = sizeof(struct pt_regs);
448
449 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
450 if (ret) {
451 perror("ptrace(PTRACE_GETREGSET) failed");
452 return TEST_FAIL;
453 }
454
455 if (gpr) {
456 for (i = 14; i < 32; i++)
457 gpr[i-14] = regs->gpr[i];
458 }
459
460 return TEST_PASS;
461 }
462
write_ckpt_gpr(pid_t child,unsigned long val)463 int write_ckpt_gpr(pid_t child, unsigned long val)
464 {
465 struct pt_regs *regs;
466 struct iovec iov;
467 int ret, i;
468
469 regs = (struct pt_regs *) malloc(sizeof(struct pt_regs));
470 if (!regs) {
471 perror("malloc() failed\n");
472 return TEST_FAIL;
473 }
474 iov.iov_base = (u64 *) regs;
475 iov.iov_len = sizeof(struct pt_regs);
476
477 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov);
478 if (ret) {
479 perror("ptrace(PTRACE_GETREGSET) failed");
480 return TEST_FAIL;
481 }
482
483 for (i = 14; i < 32; i++)
484 regs->gpr[i] = val;
485
486 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CGPR, &iov);
487 if (ret) {
488 perror("ptrace(PTRACE_GETREGSET) failed");
489 return TEST_FAIL;
490 }
491 return TEST_PASS;
492 }
493
494 /* VMX */
show_vmx(pid_t child,unsigned long vmx[][2])495 int show_vmx(pid_t child, unsigned long vmx[][2])
496 {
497 int ret;
498
499 ret = ptrace(PTRACE_GETVRREGS, child, 0, vmx);
500 if (ret) {
501 perror("ptrace(PTRACE_GETVRREGS) failed");
502 return TEST_FAIL;
503 }
504 return TEST_PASS;
505 }
506
show_vmx_ckpt(pid_t child,unsigned long vmx[][2])507 int show_vmx_ckpt(pid_t child, unsigned long vmx[][2])
508 {
509 unsigned long regs[34][2];
510 struct iovec iov;
511 int ret;
512
513 iov.iov_base = (u64 *) regs;
514 iov.iov_len = sizeof(regs);
515 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVMX, &iov);
516 if (ret) {
517 perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVMX) failed");
518 return TEST_FAIL;
519 }
520 memcpy(vmx, regs, sizeof(regs));
521 return TEST_PASS;
522 }
523
524
write_vmx(pid_t child,unsigned long vmx[][2])525 int write_vmx(pid_t child, unsigned long vmx[][2])
526 {
527 int ret;
528
529 ret = ptrace(PTRACE_SETVRREGS, child, 0, vmx);
530 if (ret) {
531 perror("ptrace(PTRACE_SETVRREGS) failed");
532 return TEST_FAIL;
533 }
534 return TEST_PASS;
535 }
536
write_vmx_ckpt(pid_t child,unsigned long vmx[][2])537 int write_vmx_ckpt(pid_t child, unsigned long vmx[][2])
538 {
539 unsigned long regs[34][2];
540 struct iovec iov;
541 int ret;
542
543 memcpy(regs, vmx, sizeof(regs));
544 iov.iov_base = (u64 *) regs;
545 iov.iov_len = sizeof(regs);
546 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVMX, &iov);
547 if (ret) {
548 perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVMX) failed");
549 return TEST_FAIL;
550 }
551 return TEST_PASS;
552 }
553
554 /* VSX */
show_vsx(pid_t child,unsigned long * vsx)555 int show_vsx(pid_t child, unsigned long *vsx)
556 {
557 int ret;
558
559 ret = ptrace(PTRACE_GETVSRREGS, child, 0, vsx);
560 if (ret) {
561 perror("ptrace(PTRACE_GETVSRREGS) failed");
562 return TEST_FAIL;
563 }
564 return TEST_PASS;
565 }
566
show_vsx_ckpt(pid_t child,unsigned long * vsx)567 int show_vsx_ckpt(pid_t child, unsigned long *vsx)
568 {
569 unsigned long regs[32];
570 struct iovec iov;
571 int ret;
572
573 iov.iov_base = (u64 *) regs;
574 iov.iov_len = sizeof(regs);
575 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVSX, &iov);
576 if (ret) {
577 perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVSX) failed");
578 return TEST_FAIL;
579 }
580 memcpy(vsx, regs, sizeof(regs));
581 return TEST_PASS;
582 }
583
write_vsx(pid_t child,unsigned long * vsx)584 int write_vsx(pid_t child, unsigned long *vsx)
585 {
586 int ret;
587
588 ret = ptrace(PTRACE_SETVSRREGS, child, 0, vsx);
589 if (ret) {
590 perror("ptrace(PTRACE_SETVSRREGS) failed");
591 return TEST_FAIL;
592 }
593 return TEST_PASS;
594 }
595
write_vsx_ckpt(pid_t child,unsigned long * vsx)596 int write_vsx_ckpt(pid_t child, unsigned long *vsx)
597 {
598 unsigned long regs[32];
599 struct iovec iov;
600 int ret;
601
602 memcpy(regs, vsx, sizeof(regs));
603 iov.iov_base = (u64 *) regs;
604 iov.iov_len = sizeof(regs);
605 ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVSX, &iov);
606 if (ret) {
607 perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVSX) failed");
608 return TEST_FAIL;
609 }
610 return TEST_PASS;
611 }
612
613 /* TM SPR */
show_tm_spr(pid_t child,struct tm_spr_regs * out)614 int show_tm_spr(pid_t child, struct tm_spr_regs *out)
615 {
616 struct tm_spr_regs *regs;
617 struct iovec iov;
618 int ret;
619
620 regs = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs));
621 if (!regs) {
622 perror("malloc() failed");
623 return TEST_FAIL;
624 }
625
626 iov.iov_base = (u64 *) regs;
627 iov.iov_len = sizeof(struct tm_spr_regs);
628
629 ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov);
630 if (ret) {
631 perror("ptrace(PTRACE_GETREGSET) failed");
632 return TEST_FAIL;
633 }
634
635 if (out)
636 memcpy(out, regs, sizeof(struct tm_spr_regs));
637
638 return TEST_PASS;
639 }
640
641
642
643 /* Analyse TEXASR after TM failure */
get_tfiar(void)644 inline unsigned long get_tfiar(void)
645 {
646 unsigned long ret;
647
648 asm volatile("mfspr %0,%1" : "=r" (ret) : "i" (SPRN_TFIAR));
649 return ret;
650 }
651
analyse_texasr(unsigned long texasr)652 void analyse_texasr(unsigned long texasr)
653 {
654 printf("TEXASR: %16lx\t", texasr);
655
656 if (texasr & TEXASR_FP)
657 printf("TEXASR_FP ");
658
659 if (texasr & TEXASR_DA)
660 printf("TEXASR_DA ");
661
662 if (texasr & TEXASR_NO)
663 printf("TEXASR_NO ");
664
665 if (texasr & TEXASR_FO)
666 printf("TEXASR_FO ");
667
668 if (texasr & TEXASR_SIC)
669 printf("TEXASR_SIC ");
670
671 if (texasr & TEXASR_NTC)
672 printf("TEXASR_NTC ");
673
674 if (texasr & TEXASR_TC)
675 printf("TEXASR_TC ");
676
677 if (texasr & TEXASR_TIC)
678 printf("TEXASR_TIC ");
679
680 if (texasr & TEXASR_IC)
681 printf("TEXASR_IC ");
682
683 if (texasr & TEXASR_IFC)
684 printf("TEXASR_IFC ");
685
686 if (texasr & TEXASR_ABT)
687 printf("TEXASR_ABT ");
688
689 if (texasr & TEXASR_SPD)
690 printf("TEXASR_SPD ");
691
692 if (texasr & TEXASR_HV)
693 printf("TEXASR_HV ");
694
695 if (texasr & TEXASR_PR)
696 printf("TEXASR_PR ");
697
698 if (texasr & TEXASR_FS)
699 printf("TEXASR_FS ");
700
701 if (texasr & TEXASR_TE)
702 printf("TEXASR_TE ");
703
704 if (texasr & TEXASR_ROT)
705 printf("TEXASR_ROT ");
706
707 printf("TFIAR :%lx\n", get_tfiar());
708 }
709
710 void store_gpr(unsigned long *addr);
711 void store_fpr(float *addr);
712