1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Ptrace test for GPR/FPR registers 4 * 5 * Copyright (C) 2015 Anshuman Khandual, IBM Corporation. 6 */ 7 #include "ptrace.h" 8 #include "ptrace-gpr.h" 9 #include "reg.h" 10 #include <time.h> 11 12 /* Tracer and Tracee Shared Data */ 13 int shm_id; 14 int *cptr, *pptr; 15 16 extern void gpr_child_loop(int *read_flag, int *write_flag, 17 unsigned long *gpr_buf, double *fpr_buf); 18 19 unsigned long child_gpr_val, parent_gpr_val; 20 double child_fpr_val, parent_fpr_val; 21 22 static int child(void) 23 { 24 unsigned long gpr_buf[32]; 25 double fpr_buf[32]; 26 int i; 27 28 cptr = (int *)shmat(shm_id, NULL, 0); 29 memset(gpr_buf, 0, sizeof(gpr_buf)); 30 memset(fpr_buf, 0, sizeof(fpr_buf)); 31 32 for (i = 0; i < 32; i++) { 33 gpr_buf[i] = child_gpr_val; 34 fpr_buf[i] = child_fpr_val; 35 } 36 37 gpr_child_loop(&cptr[0], &cptr[1], gpr_buf, fpr_buf); 38 39 shmdt((void *)cptr); 40 41 FAIL_IF(validate_gpr(gpr_buf, parent_gpr_val)); 42 FAIL_IF(validate_fpr_double(fpr_buf, parent_fpr_val)); 43 44 return 0; 45 } 46 47 int trace_gpr(pid_t child) 48 { 49 __u64 tmp, fpr[32], *peeked_fprs; 50 unsigned long gpr[18]; 51 52 FAIL_IF(start_trace(child)); 53 54 // Check child GPRs match what we expect using GETREGS 55 FAIL_IF(show_gpr(child, gpr)); 56 FAIL_IF(validate_gpr(gpr, child_gpr_val)); 57 58 // Check child FPRs match what we expect using GETFPREGS 59 FAIL_IF(show_fpr(child, fpr)); 60 memcpy(&tmp, &child_fpr_val, sizeof(tmp)); 61 FAIL_IF(validate_fpr(fpr, tmp)); 62 63 // Check child FPRs match what we expect using PEEKUSR 64 peeked_fprs = peek_fprs(child); 65 FAIL_IF(!peeked_fprs); 66 FAIL_IF(validate_fpr(peeked_fprs, tmp)); 67 free(peeked_fprs); 68 69 // Write child GPRs using SETREGS 70 FAIL_IF(write_gpr(child, parent_gpr_val)); 71 72 // Write child FPRs using SETFPREGS 73 memcpy(&tmp, &parent_fpr_val, sizeof(tmp)); 74 FAIL_IF(write_fpr(child, tmp)); 75 76 // Check child FPRs match what we just set, using PEEKUSR 77 peeked_fprs = peek_fprs(child); 78 FAIL_IF(!peeked_fprs); 79 FAIL_IF(validate_fpr(peeked_fprs, tmp)); 80 81 // Write child FPRs using POKEUSR 82 FAIL_IF(poke_fprs(child, (unsigned long *)peeked_fprs)); 83 84 // Child will check its FPRs match before exiting 85 FAIL_IF(stop_trace(child)); 86 87 return TEST_PASS; 88 } 89 90 #ifndef __LONG_WIDTH__ 91 #define __LONG_WIDTH__ (sizeof(long) * 8) 92 #endif 93 94 static uint64_t rand_reg(void) 95 { 96 uint64_t result; 97 long r; 98 99 r = random(); 100 101 // Small values are typical 102 result = r & 0xffff; 103 if (r & 0x10000) 104 return result; 105 106 // Pointers tend to have high bits set 107 result |= random() << (__LONG_WIDTH__ - 31); 108 if (r & 0x100000) 109 return result; 110 111 // And sometimes we want a full 64-bit value 112 result ^= random() << 16; 113 114 return result; 115 } 116 117 int ptrace_gpr(void) 118 { 119 unsigned long seed; 120 int ret, status; 121 pid_t pid; 122 123 seed = getpid() ^ time(NULL); 124 printf("srand(%lu)\n", seed); 125 srand(seed); 126 127 child_gpr_val = rand_reg(); 128 child_fpr_val = rand_reg(); 129 parent_gpr_val = rand_reg(); 130 parent_fpr_val = rand_reg(); 131 132 shm_id = shmget(IPC_PRIVATE, sizeof(int) * 2, 0777|IPC_CREAT); 133 pid = fork(); 134 if (pid < 0) { 135 perror("fork() failed"); 136 return TEST_FAIL; 137 } 138 if (pid == 0) 139 exit(child()); 140 141 if (pid) { 142 pptr = (int *)shmat(shm_id, NULL, 0); 143 while (!pptr[1]) 144 asm volatile("" : : : "memory"); 145 146 ret = trace_gpr(pid); 147 if (ret) { 148 kill(pid, SIGTERM); 149 shmdt((void *)pptr); 150 shmctl(shm_id, IPC_RMID, NULL); 151 return TEST_FAIL; 152 } 153 154 pptr[0] = 1; 155 shmdt((void *)pptr); 156 157 ret = wait(&status); 158 shmctl(shm_id, IPC_RMID, NULL); 159 if (ret != pid) { 160 printf("Child's exit status not captured\n"); 161 return TEST_FAIL; 162 } 163 164 return (WIFEXITED(status) && WEXITSTATUS(status)) ? TEST_FAIL : 165 TEST_PASS; 166 } 167 168 return TEST_PASS; 169 } 170 171 int main(int argc, char *argv[]) 172 { 173 return test_harness(ptrace_gpr, "ptrace_gpr"); 174 } 175