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 */
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 
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 
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 */
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 
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 
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 
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 */
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 
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 
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 
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 */
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 
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 
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 
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 */
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 
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 
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 
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 */
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 
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 
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 
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 */
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 */
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 
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