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