810 lines · c
1/* SPDX-License-Identifier: GPL-2.0-or-later */2/*3 * Ptrace interface test helper functions4 *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 034#define TEST_FAIL 135 36struct fpr_regs {37 __u64 fpr[32];38 __u64 fpscr;39};40 41struct tm_spr_regs {42 unsigned long tm_tfhar;43 unsigned long tm_texasr;44 unsigned long tm_tfiar;45};46 47#ifndef NT_PPC_TAR48#define NT_PPC_TAR 0x10349#define NT_PPC_PPR 0x10450#define NT_PPC_DSCR 0x10551#define NT_PPC_EBB 0x10652#define NT_PPC_PMU 0x10753#define NT_PPC_TM_CGPR 0x10854#define NT_PPC_TM_CFPR 0x10955#define NT_PPC_TM_CVMX 0x10a56#define NT_PPC_TM_CVSX 0x10b57#define NT_PPC_TM_SPR 0x10c58#define NT_PPC_TM_CTAR 0x10d59#define NT_PPC_TM_CPPR 0x10e60#define NT_PPC_TM_CDSCR 0x10f61#endif62 63/* Basic ptrace operations */64int 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 81int 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 93int 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 105int 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 125long 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 */144int 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;184fail:185 free(reg);186 return TEST_FAIL;187}188 189int 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;228fail:229 free(reg);230 return TEST_FAIL;231}232 233int 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 275fail:276 free(reg);277 return TEST_FAIL;278}279 280int 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;319fail:320 free(reg);321 return TEST_FAIL;322}323 324/* FPR */325int 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 344int 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 367int 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 391int 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 */419int 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 444long 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 FPSCR450#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(PTRACE_PEEKUSER, child, addr, (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(PTRACE_PEEKUSER, child, addr, (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 483int 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(PTRACE_POKEUSER, child, addr, *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(PTRACE_POKEUSER, child, addr, addr);500 if (!ret) {501 printf("ptrace(PTRACE_POKEUSR) succeeded unexpectedly!\n");502 return -1;503 }504 505 return 0;506}507 508int 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 536int 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 565int 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 */597int 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 609int 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 627int 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 639int 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 */657int 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 669int 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 686int 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 698int 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 */716int 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 */746inline unsigned long get_tfiar(void)747{748 return mfspr(SPRN_TFIAR);749}750 751void 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 809void store_gpr(unsigned long *addr);810