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 | |
8 | #define __SANE_USERSPACE_TYPES__ |
9 | |
10 | #include <inttypes.h> |
11 | #include <unistd.h> |
12 | #include <stdlib.h> |
13 | #include <string.h> |
14 | #include <malloc.h> |
15 | #include <errno.h> |
16 | #include <time.h> |
17 | #include <sys/ptrace.h> |
18 | #include <sys/ioctl.h> |
19 | #include <sys/uio.h> |
20 | #include <sys/types.h> |
21 | #include <sys/wait.h> |
22 | #include <sys/signal.h> |
23 | #include <sys/ipc.h> |
24 | #include <sys/shm.h> |
25 | #include <sys/user.h> |
26 | #include <sys/syscall.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 | __u64 fpr[32]; |
38 | __u64 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 | int ptrace_read_regs(pid_t child, unsigned long type, unsigned long regs[], |
106 | int n) |
107 | { |
108 | struct iovec iov; |
109 | long ret; |
110 | |
111 | FAIL_IF(start_trace(child)); |
112 | |
113 | iov.iov_base = regs; |
114 | iov.iov_len = n * sizeof(unsigned long); |
115 | |
116 | ret = ptrace(PTRACE_GETREGSET, child, type, &iov); |
117 | if (ret) |
118 | return ret; |
119 | |
120 | FAIL_IF(stop_trace(child)); |
121 | |
122 | return TEST_PASS; |
123 | } |
124 | |
125 | long ptrace_write_regs(pid_t child, unsigned long type, unsigned long regs[], |
126 | int n) |
127 | { |
128 | struct iovec iov; |
129 | long ret; |
130 | |
131 | FAIL_IF(start_trace(child)); |
132 | |
133 | iov.iov_base = regs; |
134 | iov.iov_len = n * sizeof(unsigned long); |
135 | |
136 | ret = ptrace(PTRACE_SETREGSET, child, type, &iov); |
137 | |
138 | FAIL_IF(stop_trace(child)); |
139 | |
140 | return ret; |
141 | } |
142 | |
143 | /* TAR, PPR, DSCR */ |
144 | int show_tar_registers(pid_t child, unsigned long *out) |
145 | { |
146 | struct iovec iov; |
147 | unsigned long *reg; |
148 | int ret; |
149 | |
150 | reg = malloc(sizeof(unsigned long)); |
151 | if (!reg) { |
152 | perror("malloc() failed" ); |
153 | return TEST_FAIL; |
154 | } |
155 | iov.iov_base = (u64 *) reg; |
156 | iov.iov_len = sizeof(unsigned long); |
157 | |
158 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TAR, &iov); |
159 | if (ret) { |
160 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
161 | goto fail; |
162 | } |
163 | if (out) |
164 | out[0] = *reg; |
165 | |
166 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_PPR, &iov); |
167 | if (ret) { |
168 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
169 | goto fail; |
170 | } |
171 | if (out) |
172 | out[1] = *reg; |
173 | |
174 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_DSCR, &iov); |
175 | if (ret) { |
176 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
177 | goto fail; |
178 | } |
179 | if (out) |
180 | out[2] = *reg; |
181 | |
182 | free(reg); |
183 | return TEST_PASS; |
184 | fail: |
185 | free(reg); |
186 | return TEST_FAIL; |
187 | } |
188 | |
189 | int write_tar_registers(pid_t child, unsigned long tar, |
190 | unsigned long ppr, unsigned long dscr) |
191 | { |
192 | struct iovec iov; |
193 | unsigned long *reg; |
194 | int ret; |
195 | |
196 | reg = malloc(sizeof(unsigned long)); |
197 | if (!reg) { |
198 | perror("malloc() failed" ); |
199 | return TEST_FAIL; |
200 | } |
201 | |
202 | iov.iov_base = (u64 *) reg; |
203 | iov.iov_len = sizeof(unsigned long); |
204 | |
205 | *reg = tar; |
206 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TAR, &iov); |
207 | if (ret) { |
208 | perror("ptrace(PTRACE_SETREGSET) failed" ); |
209 | goto fail; |
210 | } |
211 | |
212 | *reg = ppr; |
213 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_PPR, &iov); |
214 | if (ret) { |
215 | perror("ptrace(PTRACE_SETREGSET) failed" ); |
216 | goto fail; |
217 | } |
218 | |
219 | *reg = dscr; |
220 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_DSCR, &iov); |
221 | if (ret) { |
222 | perror("ptrace(PTRACE_SETREGSET) failed" ); |
223 | goto fail; |
224 | } |
225 | |
226 | free(reg); |
227 | return TEST_PASS; |
228 | fail: |
229 | free(reg); |
230 | return TEST_FAIL; |
231 | } |
232 | |
233 | int show_tm_checkpointed_state(pid_t child, unsigned long *out) |
234 | { |
235 | struct iovec iov; |
236 | unsigned long *reg; |
237 | int ret; |
238 | |
239 | reg = malloc(sizeof(unsigned long)); |
240 | if (!reg) { |
241 | perror("malloc() failed" ); |
242 | return TEST_FAIL; |
243 | } |
244 | |
245 | iov.iov_base = (u64 *) reg; |
246 | iov.iov_len = sizeof(unsigned long); |
247 | |
248 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CTAR, &iov); |
249 | if (ret) { |
250 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
251 | goto fail; |
252 | } |
253 | if (out) |
254 | out[0] = *reg; |
255 | |
256 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CPPR, &iov); |
257 | if (ret) { |
258 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
259 | goto fail; |
260 | } |
261 | if (out) |
262 | out[1] = *reg; |
263 | |
264 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CDSCR, &iov); |
265 | if (ret) { |
266 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
267 | goto fail; |
268 | } |
269 | if (out) |
270 | out[2] = *reg; |
271 | |
272 | free(reg); |
273 | return TEST_PASS; |
274 | |
275 | fail: |
276 | free(reg); |
277 | return TEST_FAIL; |
278 | } |
279 | |
280 | int write_ckpt_tar_registers(pid_t child, unsigned long tar, |
281 | unsigned long ppr, unsigned long dscr) |
282 | { |
283 | struct iovec iov; |
284 | unsigned long *reg; |
285 | int ret; |
286 | |
287 | reg = malloc(sizeof(unsigned long)); |
288 | if (!reg) { |
289 | perror("malloc() failed" ); |
290 | return TEST_FAIL; |
291 | } |
292 | |
293 | iov.iov_base = (u64 *) reg; |
294 | iov.iov_len = sizeof(unsigned long); |
295 | |
296 | *reg = tar; |
297 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CTAR, &iov); |
298 | if (ret) { |
299 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
300 | goto fail; |
301 | } |
302 | |
303 | *reg = ppr; |
304 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CPPR, &iov); |
305 | if (ret) { |
306 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
307 | goto fail; |
308 | } |
309 | |
310 | *reg = dscr; |
311 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CDSCR, &iov); |
312 | if (ret) { |
313 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
314 | goto fail; |
315 | } |
316 | |
317 | free(reg); |
318 | return TEST_PASS; |
319 | fail: |
320 | free(reg); |
321 | return TEST_FAIL; |
322 | } |
323 | |
324 | /* FPR */ |
325 | int show_fpr(pid_t child, __u64 *fpr) |
326 | { |
327 | struct fpr_regs *regs; |
328 | int ret, i; |
329 | |
330 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); |
331 | ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs); |
332 | if (ret) { |
333 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
334 | return TEST_FAIL; |
335 | } |
336 | |
337 | if (fpr) { |
338 | for (i = 0; i < 32; i++) |
339 | fpr[i] = regs->fpr[i]; |
340 | } |
341 | return TEST_PASS; |
342 | } |
343 | |
344 | int write_fpr(pid_t child, __u64 val) |
345 | { |
346 | struct fpr_regs *regs; |
347 | int ret, i; |
348 | |
349 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); |
350 | ret = ptrace(PTRACE_GETFPREGS, child, NULL, regs); |
351 | if (ret) { |
352 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
353 | return TEST_FAIL; |
354 | } |
355 | |
356 | for (i = 0; i < 32; i++) |
357 | regs->fpr[i] = val; |
358 | |
359 | ret = ptrace(PTRACE_SETFPREGS, child, NULL, regs); |
360 | if (ret) { |
361 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
362 | return TEST_FAIL; |
363 | } |
364 | return TEST_PASS; |
365 | } |
366 | |
367 | int show_ckpt_fpr(pid_t child, __u64 *fpr) |
368 | { |
369 | struct fpr_regs *regs; |
370 | struct iovec iov; |
371 | int ret, i; |
372 | |
373 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); |
374 | iov.iov_base = regs; |
375 | iov.iov_len = sizeof(struct fpr_regs); |
376 | |
377 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov); |
378 | if (ret) { |
379 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
380 | return TEST_FAIL; |
381 | } |
382 | |
383 | if (fpr) { |
384 | for (i = 0; i < 32; i++) |
385 | fpr[i] = regs->fpr[i]; |
386 | } |
387 | |
388 | return TEST_PASS; |
389 | } |
390 | |
391 | int write_ckpt_fpr(pid_t child, unsigned long val) |
392 | { |
393 | struct fpr_regs *regs; |
394 | struct iovec iov; |
395 | int ret, i; |
396 | |
397 | regs = (struct fpr_regs *) malloc(sizeof(struct fpr_regs)); |
398 | iov.iov_base = regs; |
399 | iov.iov_len = sizeof(struct fpr_regs); |
400 | |
401 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CFPR, &iov); |
402 | if (ret) { |
403 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
404 | return TEST_FAIL; |
405 | } |
406 | |
407 | for (i = 0; i < 32; i++) |
408 | regs->fpr[i] = val; |
409 | |
410 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CFPR, &iov); |
411 | if (ret) { |
412 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
413 | return TEST_FAIL; |
414 | } |
415 | return TEST_PASS; |
416 | } |
417 | |
418 | /* GPR */ |
419 | int show_gpr(pid_t child, unsigned long *gpr) |
420 | { |
421 | struct pt_regs *regs; |
422 | int ret, i; |
423 | |
424 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); |
425 | if (!regs) { |
426 | perror("malloc() failed" ); |
427 | return TEST_FAIL; |
428 | } |
429 | |
430 | ret = ptrace(PTRACE_GETREGS, child, NULL, regs); |
431 | if (ret) { |
432 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
433 | return TEST_FAIL; |
434 | } |
435 | |
436 | if (gpr) { |
437 | for (i = 14; i < 32; i++) |
438 | gpr[i-14] = regs->gpr[i]; |
439 | } |
440 | |
441 | return TEST_PASS; |
442 | } |
443 | |
444 | long sys_ptrace(enum __ptrace_request request, pid_t pid, unsigned long addr, unsigned long data) |
445 | { |
446 | return syscall(__NR_ptrace, request, pid, (void *)addr, data); |
447 | } |
448 | |
449 | // 33 because of FPSCR |
450 | #define PT_NUM_FPRS (33 * (sizeof(__u64) / sizeof(unsigned long))) |
451 | |
452 | __u64 *peek_fprs(pid_t child) |
453 | { |
454 | unsigned long *fprs, *p, addr; |
455 | long ret; |
456 | int i; |
457 | |
458 | fprs = malloc(sizeof(unsigned long) * PT_NUM_FPRS); |
459 | if (!fprs) { |
460 | perror("malloc() failed" ); |
461 | return NULL; |
462 | } |
463 | |
464 | for (i = 0, p = fprs; i < PT_NUM_FPRS; i++, p++) { |
465 | addr = sizeof(unsigned long) * (PT_FPR0 + i); |
466 | ret = sys_ptrace(request: PTRACE_PEEKUSER, pid: child, addr, data: (unsigned long)p); |
467 | if (ret) { |
468 | perror("ptrace(PTRACE_PEEKUSR) failed" ); |
469 | return NULL; |
470 | } |
471 | } |
472 | |
473 | addr = sizeof(unsigned long) * (PT_FPR0 + i); |
474 | ret = sys_ptrace(request: PTRACE_PEEKUSER, pid: child, addr, data: (unsigned long)&addr); |
475 | if (!ret) { |
476 | printf("ptrace(PTRACE_PEEKUSR) succeeded unexpectedly!\n" ); |
477 | return NULL; |
478 | } |
479 | |
480 | return (__u64 *)fprs; |
481 | } |
482 | |
483 | int poke_fprs(pid_t child, unsigned long *fprs) |
484 | { |
485 | unsigned long *p, addr; |
486 | long ret; |
487 | int i; |
488 | |
489 | for (i = 0, p = fprs; i < PT_NUM_FPRS; i++, p++) { |
490 | addr = sizeof(unsigned long) * (PT_FPR0 + i); |
491 | ret = sys_ptrace(request: PTRACE_POKEUSER, pid: child, addr, data: *p); |
492 | if (ret) { |
493 | perror("ptrace(PTRACE_POKEUSR) failed" ); |
494 | return -1; |
495 | } |
496 | } |
497 | |
498 | addr = sizeof(unsigned long) * (PT_FPR0 + i); |
499 | ret = sys_ptrace(request: PTRACE_POKEUSER, pid: child, addr, data: addr); |
500 | if (!ret) { |
501 | printf("ptrace(PTRACE_POKEUSR) succeeded unexpectedly!\n" ); |
502 | return -1; |
503 | } |
504 | |
505 | return 0; |
506 | } |
507 | |
508 | int write_gpr(pid_t child, unsigned long val) |
509 | { |
510 | struct pt_regs *regs; |
511 | int i, ret; |
512 | |
513 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); |
514 | if (!regs) { |
515 | perror("malloc() failed" ); |
516 | return TEST_FAIL; |
517 | } |
518 | |
519 | ret = ptrace(PTRACE_GETREGS, child, NULL, regs); |
520 | if (ret) { |
521 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
522 | return TEST_FAIL; |
523 | } |
524 | |
525 | for (i = 14; i < 32; i++) |
526 | regs->gpr[i] = val; |
527 | |
528 | ret = ptrace(PTRACE_SETREGS, child, NULL, regs); |
529 | if (ret) { |
530 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
531 | return TEST_FAIL; |
532 | } |
533 | return TEST_PASS; |
534 | } |
535 | |
536 | int show_ckpt_gpr(pid_t child, unsigned long *gpr) |
537 | { |
538 | struct pt_regs *regs; |
539 | struct iovec iov; |
540 | int ret, i; |
541 | |
542 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); |
543 | if (!regs) { |
544 | perror("malloc() failed" ); |
545 | return TEST_FAIL; |
546 | } |
547 | |
548 | iov.iov_base = (u64 *) regs; |
549 | iov.iov_len = sizeof(struct pt_regs); |
550 | |
551 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov); |
552 | if (ret) { |
553 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
554 | return TEST_FAIL; |
555 | } |
556 | |
557 | if (gpr) { |
558 | for (i = 14; i < 32; i++) |
559 | gpr[i-14] = regs->gpr[i]; |
560 | } |
561 | |
562 | return TEST_PASS; |
563 | } |
564 | |
565 | int write_ckpt_gpr(pid_t child, unsigned long val) |
566 | { |
567 | struct pt_regs *regs; |
568 | struct iovec iov; |
569 | int ret, i; |
570 | |
571 | regs = (struct pt_regs *) malloc(sizeof(struct pt_regs)); |
572 | if (!regs) { |
573 | perror("malloc() failed\n" ); |
574 | return TEST_FAIL; |
575 | } |
576 | iov.iov_base = (u64 *) regs; |
577 | iov.iov_len = sizeof(struct pt_regs); |
578 | |
579 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CGPR, &iov); |
580 | if (ret) { |
581 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
582 | return TEST_FAIL; |
583 | } |
584 | |
585 | for (i = 14; i < 32; i++) |
586 | regs->gpr[i] = val; |
587 | |
588 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CGPR, &iov); |
589 | if (ret) { |
590 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
591 | return TEST_FAIL; |
592 | } |
593 | return TEST_PASS; |
594 | } |
595 | |
596 | /* VMX */ |
597 | int show_vmx(pid_t child, unsigned long vmx[][2]) |
598 | { |
599 | int ret; |
600 | |
601 | ret = ptrace(PTRACE_GETVRREGS, child, 0, vmx); |
602 | if (ret) { |
603 | perror("ptrace(PTRACE_GETVRREGS) failed" ); |
604 | return TEST_FAIL; |
605 | } |
606 | return TEST_PASS; |
607 | } |
608 | |
609 | int show_vmx_ckpt(pid_t child, unsigned long vmx[][2]) |
610 | { |
611 | unsigned long regs[34][2]; |
612 | struct iovec iov; |
613 | int ret; |
614 | |
615 | iov.iov_base = (u64 *) regs; |
616 | iov.iov_len = sizeof(regs); |
617 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVMX, &iov); |
618 | if (ret) { |
619 | perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVMX) failed" ); |
620 | return TEST_FAIL; |
621 | } |
622 | memcpy(vmx, regs, sizeof(regs)); |
623 | return TEST_PASS; |
624 | } |
625 | |
626 | |
627 | int write_vmx(pid_t child, unsigned long vmx[][2]) |
628 | { |
629 | int ret; |
630 | |
631 | ret = ptrace(PTRACE_SETVRREGS, child, 0, vmx); |
632 | if (ret) { |
633 | perror("ptrace(PTRACE_SETVRREGS) failed" ); |
634 | return TEST_FAIL; |
635 | } |
636 | return TEST_PASS; |
637 | } |
638 | |
639 | int write_vmx_ckpt(pid_t child, unsigned long vmx[][2]) |
640 | { |
641 | unsigned long regs[34][2]; |
642 | struct iovec iov; |
643 | int ret; |
644 | |
645 | memcpy(regs, vmx, sizeof(regs)); |
646 | iov.iov_base = (u64 *) regs; |
647 | iov.iov_len = sizeof(regs); |
648 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVMX, &iov); |
649 | if (ret) { |
650 | perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVMX) failed" ); |
651 | return TEST_FAIL; |
652 | } |
653 | return TEST_PASS; |
654 | } |
655 | |
656 | /* VSX */ |
657 | int show_vsx(pid_t child, unsigned long *vsx) |
658 | { |
659 | int ret; |
660 | |
661 | ret = ptrace(PTRACE_GETVSRREGS, child, 0, vsx); |
662 | if (ret) { |
663 | perror("ptrace(PTRACE_GETVSRREGS) failed" ); |
664 | return TEST_FAIL; |
665 | } |
666 | return TEST_PASS; |
667 | } |
668 | |
669 | int show_vsx_ckpt(pid_t child, unsigned long *vsx) |
670 | { |
671 | unsigned long regs[32]; |
672 | struct iovec iov; |
673 | int ret; |
674 | |
675 | iov.iov_base = (u64 *) regs; |
676 | iov.iov_len = sizeof(regs); |
677 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_CVSX, &iov); |
678 | if (ret) { |
679 | perror("ptrace(PTRACE_GETREGSET, NT_PPC_TM_CVSX) failed" ); |
680 | return TEST_FAIL; |
681 | } |
682 | memcpy(vsx, regs, sizeof(regs)); |
683 | return TEST_PASS; |
684 | } |
685 | |
686 | int write_vsx(pid_t child, unsigned long *vsx) |
687 | { |
688 | int ret; |
689 | |
690 | ret = ptrace(PTRACE_SETVSRREGS, child, 0, vsx); |
691 | if (ret) { |
692 | perror("ptrace(PTRACE_SETVSRREGS) failed" ); |
693 | return TEST_FAIL; |
694 | } |
695 | return TEST_PASS; |
696 | } |
697 | |
698 | int write_vsx_ckpt(pid_t child, unsigned long *vsx) |
699 | { |
700 | unsigned long regs[32]; |
701 | struct iovec iov; |
702 | int ret; |
703 | |
704 | memcpy(regs, vsx, sizeof(regs)); |
705 | iov.iov_base = (u64 *) regs; |
706 | iov.iov_len = sizeof(regs); |
707 | ret = ptrace(PTRACE_SETREGSET, child, NT_PPC_TM_CVSX, &iov); |
708 | if (ret) { |
709 | perror("ptrace(PTRACE_SETREGSET, NT_PPC_TM_CVSX) failed" ); |
710 | return TEST_FAIL; |
711 | } |
712 | return TEST_PASS; |
713 | } |
714 | |
715 | /* TM SPR */ |
716 | int show_tm_spr(pid_t child, struct tm_spr_regs *out) |
717 | { |
718 | struct tm_spr_regs *regs; |
719 | struct iovec iov; |
720 | int ret; |
721 | |
722 | regs = (struct tm_spr_regs *) malloc(sizeof(struct tm_spr_regs)); |
723 | if (!regs) { |
724 | perror("malloc() failed" ); |
725 | return TEST_FAIL; |
726 | } |
727 | |
728 | iov.iov_base = (u64 *) regs; |
729 | iov.iov_len = sizeof(struct tm_spr_regs); |
730 | |
731 | ret = ptrace(PTRACE_GETREGSET, child, NT_PPC_TM_SPR, &iov); |
732 | if (ret) { |
733 | perror("ptrace(PTRACE_GETREGSET) failed" ); |
734 | return TEST_FAIL; |
735 | } |
736 | |
737 | if (out) |
738 | memcpy(out, regs, sizeof(struct tm_spr_regs)); |
739 | |
740 | return TEST_PASS; |
741 | } |
742 | |
743 | |
744 | |
745 | /* Analyse TEXASR after TM failure */ |
746 | inline unsigned long get_tfiar(void) |
747 | { |
748 | return mfspr(SPRN_TFIAR); |
749 | } |
750 | |
751 | void analyse_texasr(unsigned long texasr) |
752 | { |
753 | printf("TEXASR: %16lx\t" , texasr); |
754 | |
755 | if (texasr & TEXASR_FP) |
756 | printf("TEXASR_FP " ); |
757 | |
758 | if (texasr & TEXASR_DA) |
759 | printf("TEXASR_DA " ); |
760 | |
761 | if (texasr & TEXASR_NO) |
762 | printf("TEXASR_NO " ); |
763 | |
764 | if (texasr & TEXASR_FO) |
765 | printf("TEXASR_FO " ); |
766 | |
767 | if (texasr & TEXASR_SIC) |
768 | printf("TEXASR_SIC " ); |
769 | |
770 | if (texasr & TEXASR_NTC) |
771 | printf("TEXASR_NTC " ); |
772 | |
773 | if (texasr & TEXASR_TC) |
774 | printf("TEXASR_TC " ); |
775 | |
776 | if (texasr & TEXASR_TIC) |
777 | printf("TEXASR_TIC " ); |
778 | |
779 | if (texasr & TEXASR_IC) |
780 | printf("TEXASR_IC " ); |
781 | |
782 | if (texasr & TEXASR_IFC) |
783 | printf("TEXASR_IFC " ); |
784 | |
785 | if (texasr & TEXASR_ABT) |
786 | printf("TEXASR_ABT " ); |
787 | |
788 | if (texasr & TEXASR_SPD) |
789 | printf("TEXASR_SPD " ); |
790 | |
791 | if (texasr & TEXASR_HV) |
792 | printf("TEXASR_HV " ); |
793 | |
794 | if (texasr & TEXASR_PR) |
795 | printf("TEXASR_PR " ); |
796 | |
797 | if (texasr & TEXASR_FS) |
798 | printf("TEXASR_FS " ); |
799 | |
800 | if (texasr & TEXASR_TE) |
801 | printf("TEXASR_TE " ); |
802 | |
803 | if (texasr & TEXASR_ROT) |
804 | printf("TEXASR_ROT " ); |
805 | |
806 | printf("TFIAR :%lx\n" , get_tfiar()); |
807 | } |
808 | |
809 | void store_gpr(unsigned long *addr); |
810 | |