1*da9a1c10SChristophe Leroy /* 2*da9a1c10SChristophe Leroy * ptrace for 32-bit processes running on a 64-bit kernel. 3*da9a1c10SChristophe Leroy * 4*da9a1c10SChristophe Leroy * PowerPC version 5*da9a1c10SChristophe Leroy * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 6*da9a1c10SChristophe Leroy * 7*da9a1c10SChristophe Leroy * Derived from "arch/m68k/kernel/ptrace.c" 8*da9a1c10SChristophe Leroy * Copyright (C) 1994 by Hamish Macdonald 9*da9a1c10SChristophe Leroy * Taken from linux/kernel/ptrace.c and modified for M680x0. 10*da9a1c10SChristophe Leroy * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds 11*da9a1c10SChristophe Leroy * 12*da9a1c10SChristophe Leroy * Modified by Cort Dougan (cort@hq.fsmlabs.com) 13*da9a1c10SChristophe Leroy * and Paul Mackerras (paulus@samba.org). 14*da9a1c10SChristophe Leroy * 15*da9a1c10SChristophe Leroy * This file is subject to the terms and conditions of the GNU General 16*da9a1c10SChristophe Leroy * Public License. See the file COPYING in the main directory of 17*da9a1c10SChristophe Leroy * this archive for more details. 18*da9a1c10SChristophe Leroy */ 19*da9a1c10SChristophe Leroy 20*da9a1c10SChristophe Leroy #include <linux/kernel.h> 21*da9a1c10SChristophe Leroy #include <linux/sched.h> 22*da9a1c10SChristophe Leroy #include <linux/mm.h> 23*da9a1c10SChristophe Leroy #include <linux/smp.h> 24*da9a1c10SChristophe Leroy #include <linux/errno.h> 25*da9a1c10SChristophe Leroy #include <linux/ptrace.h> 26*da9a1c10SChristophe Leroy #include <linux/regset.h> 27*da9a1c10SChristophe Leroy #include <linux/user.h> 28*da9a1c10SChristophe Leroy #include <linux/security.h> 29*da9a1c10SChristophe Leroy #include <linux/signal.h> 30*da9a1c10SChristophe Leroy #include <linux/compat.h> 31*da9a1c10SChristophe Leroy 32*da9a1c10SChristophe Leroy #include <linux/uaccess.h> 33*da9a1c10SChristophe Leroy #include <asm/page.h> 34*da9a1c10SChristophe Leroy #include <asm/pgtable.h> 35*da9a1c10SChristophe Leroy #include <asm/switch_to.h> 36*da9a1c10SChristophe Leroy 37*da9a1c10SChristophe Leroy /* 38*da9a1c10SChristophe Leroy * does not yet catch signals sent when the child dies. 39*da9a1c10SChristophe Leroy * in exit.c or in signal.c. 40*da9a1c10SChristophe Leroy */ 41*da9a1c10SChristophe Leroy 42*da9a1c10SChristophe Leroy /* Macros to workout the correct index for the FPR in the thread struct */ 43*da9a1c10SChristophe Leroy #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1) 44*da9a1c10SChristophe Leroy #define FPRHALF(i) (((i) - PT_FPR0) & 1) 45*da9a1c10SChristophe Leroy #define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) * 2 + FPRHALF(i) 46*da9a1c10SChristophe Leroy 47*da9a1c10SChristophe Leroy long compat_arch_ptrace(struct task_struct *child, compat_long_t request, 48*da9a1c10SChristophe Leroy compat_ulong_t caddr, compat_ulong_t cdata) 49*da9a1c10SChristophe Leroy { 50*da9a1c10SChristophe Leroy unsigned long addr = caddr; 51*da9a1c10SChristophe Leroy unsigned long data = cdata; 52*da9a1c10SChristophe Leroy int ret; 53*da9a1c10SChristophe Leroy 54*da9a1c10SChristophe Leroy switch (request) { 55*da9a1c10SChristophe Leroy /* 56*da9a1c10SChristophe Leroy * Read 4 bytes of the other process' storage 57*da9a1c10SChristophe Leroy * data is a pointer specifying where the user wants the 58*da9a1c10SChristophe Leroy * 4 bytes copied into 59*da9a1c10SChristophe Leroy * addr is a pointer in the user's storage that contains an 8 byte 60*da9a1c10SChristophe Leroy * address in the other process of the 4 bytes that is to be read 61*da9a1c10SChristophe Leroy * (this is run in a 32-bit process looking at a 64-bit process) 62*da9a1c10SChristophe Leroy * when I and D space are separate, these will need to be fixed. 63*da9a1c10SChristophe Leroy */ 64*da9a1c10SChristophe Leroy case PPC_PTRACE_PEEKTEXT_3264: 65*da9a1c10SChristophe Leroy case PPC_PTRACE_PEEKDATA_3264: { 66*da9a1c10SChristophe Leroy u32 tmp; 67*da9a1c10SChristophe Leroy int copied; 68*da9a1c10SChristophe Leroy u32 __user * addrOthers; 69*da9a1c10SChristophe Leroy 70*da9a1c10SChristophe Leroy ret = -EIO; 71*da9a1c10SChristophe Leroy 72*da9a1c10SChristophe Leroy /* Get the addr in the other process that we want to read */ 73*da9a1c10SChristophe Leroy if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) 74*da9a1c10SChristophe Leroy break; 75*da9a1c10SChristophe Leroy 76*da9a1c10SChristophe Leroy copied = ptrace_access_vm(child, (u64)addrOthers, &tmp, 77*da9a1c10SChristophe Leroy sizeof(tmp), FOLL_FORCE); 78*da9a1c10SChristophe Leroy if (copied != sizeof(tmp)) 79*da9a1c10SChristophe Leroy break; 80*da9a1c10SChristophe Leroy ret = put_user(tmp, (u32 __user *)data); 81*da9a1c10SChristophe Leroy break; 82*da9a1c10SChristophe Leroy } 83*da9a1c10SChristophe Leroy 84*da9a1c10SChristophe Leroy /* Read a register (specified by ADDR) out of the "user area" */ 85*da9a1c10SChristophe Leroy case PTRACE_PEEKUSR: { 86*da9a1c10SChristophe Leroy int index; 87*da9a1c10SChristophe Leroy unsigned long tmp; 88*da9a1c10SChristophe Leroy 89*da9a1c10SChristophe Leroy ret = -EIO; 90*da9a1c10SChristophe Leroy /* convert to index and check */ 91*da9a1c10SChristophe Leroy index = (unsigned long) addr >> 2; 92*da9a1c10SChristophe Leroy if ((addr & 3) || (index > PT_FPSCR32)) 93*da9a1c10SChristophe Leroy break; 94*da9a1c10SChristophe Leroy 95*da9a1c10SChristophe Leroy CHECK_FULL_REGS(child->thread.regs); 96*da9a1c10SChristophe Leroy if (index < PT_FPR0) { 97*da9a1c10SChristophe Leroy ret = ptrace_get_reg(child, index, &tmp); 98*da9a1c10SChristophe Leroy if (ret) 99*da9a1c10SChristophe Leroy break; 100*da9a1c10SChristophe Leroy } else { 101*da9a1c10SChristophe Leroy flush_fp_to_thread(child); 102*da9a1c10SChristophe Leroy /* 103*da9a1c10SChristophe Leroy * the user space code considers the floating point 104*da9a1c10SChristophe Leroy * to be an array of unsigned int (32 bits) - the 105*da9a1c10SChristophe Leroy * index passed in is based on this assumption. 106*da9a1c10SChristophe Leroy */ 107*da9a1c10SChristophe Leroy tmp = ((unsigned int *)child->thread.fp_state.fpr) 108*da9a1c10SChristophe Leroy [FPRINDEX(index)]; 109*da9a1c10SChristophe Leroy } 110*da9a1c10SChristophe Leroy ret = put_user((unsigned int)tmp, (u32 __user *)data); 111*da9a1c10SChristophe Leroy break; 112*da9a1c10SChristophe Leroy } 113*da9a1c10SChristophe Leroy 114*da9a1c10SChristophe Leroy /* 115*da9a1c10SChristophe Leroy * Read 4 bytes out of the other process' pt_regs area 116*da9a1c10SChristophe Leroy * data is a pointer specifying where the user wants the 117*da9a1c10SChristophe Leroy * 4 bytes copied into 118*da9a1c10SChristophe Leroy * addr is the offset into the other process' pt_regs structure 119*da9a1c10SChristophe Leroy * that is to be read 120*da9a1c10SChristophe Leroy * (this is run in a 32-bit process looking at a 64-bit process) 121*da9a1c10SChristophe Leroy */ 122*da9a1c10SChristophe Leroy case PPC_PTRACE_PEEKUSR_3264: { 123*da9a1c10SChristophe Leroy u32 index; 124*da9a1c10SChristophe Leroy u32 reg32bits; 125*da9a1c10SChristophe Leroy u64 tmp; 126*da9a1c10SChristophe Leroy u32 numReg; 127*da9a1c10SChristophe Leroy u32 part; 128*da9a1c10SChristophe Leroy 129*da9a1c10SChristophe Leroy ret = -EIO; 130*da9a1c10SChristophe Leroy /* Determine which register the user wants */ 131*da9a1c10SChristophe Leroy index = (u64)addr >> 2; 132*da9a1c10SChristophe Leroy numReg = index / 2; 133*da9a1c10SChristophe Leroy /* Determine which part of the register the user wants */ 134*da9a1c10SChristophe Leroy if (index % 2) 135*da9a1c10SChristophe Leroy part = 1; /* want the 2nd half of the register (right-most). */ 136*da9a1c10SChristophe Leroy else 137*da9a1c10SChristophe Leroy part = 0; /* want the 1st half of the register (left-most). */ 138*da9a1c10SChristophe Leroy 139*da9a1c10SChristophe Leroy /* Validate the input - check to see if address is on the wrong boundary 140*da9a1c10SChristophe Leroy * or beyond the end of the user area 141*da9a1c10SChristophe Leroy */ 142*da9a1c10SChristophe Leroy if ((addr & 3) || numReg > PT_FPSCR) 143*da9a1c10SChristophe Leroy break; 144*da9a1c10SChristophe Leroy 145*da9a1c10SChristophe Leroy CHECK_FULL_REGS(child->thread.regs); 146*da9a1c10SChristophe Leroy if (numReg >= PT_FPR0) { 147*da9a1c10SChristophe Leroy flush_fp_to_thread(child); 148*da9a1c10SChristophe Leroy /* get 64 bit FPR */ 149*da9a1c10SChristophe Leroy tmp = child->thread.fp_state.fpr[numReg - PT_FPR0][0]; 150*da9a1c10SChristophe Leroy } else { /* register within PT_REGS struct */ 151*da9a1c10SChristophe Leroy unsigned long tmp2; 152*da9a1c10SChristophe Leroy ret = ptrace_get_reg(child, numReg, &tmp2); 153*da9a1c10SChristophe Leroy if (ret) 154*da9a1c10SChristophe Leroy break; 155*da9a1c10SChristophe Leroy tmp = tmp2; 156*da9a1c10SChristophe Leroy } 157*da9a1c10SChristophe Leroy reg32bits = ((u32*)&tmp)[part]; 158*da9a1c10SChristophe Leroy ret = put_user(reg32bits, (u32 __user *)data); 159*da9a1c10SChristophe Leroy break; 160*da9a1c10SChristophe Leroy } 161*da9a1c10SChristophe Leroy 162*da9a1c10SChristophe Leroy /* 163*da9a1c10SChristophe Leroy * Write 4 bytes into the other process' storage 164*da9a1c10SChristophe Leroy * data is the 4 bytes that the user wants written 165*da9a1c10SChristophe Leroy * addr is a pointer in the user's storage that contains an 166*da9a1c10SChristophe Leroy * 8 byte address in the other process where the 4 bytes 167*da9a1c10SChristophe Leroy * that is to be written 168*da9a1c10SChristophe Leroy * (this is run in a 32-bit process looking at a 64-bit process) 169*da9a1c10SChristophe Leroy * when I and D space are separate, these will need to be fixed. 170*da9a1c10SChristophe Leroy */ 171*da9a1c10SChristophe Leroy case PPC_PTRACE_POKETEXT_3264: 172*da9a1c10SChristophe Leroy case PPC_PTRACE_POKEDATA_3264: { 173*da9a1c10SChristophe Leroy u32 tmp = data; 174*da9a1c10SChristophe Leroy u32 __user * addrOthers; 175*da9a1c10SChristophe Leroy 176*da9a1c10SChristophe Leroy /* Get the addr in the other process that we want to write into */ 177*da9a1c10SChristophe Leroy ret = -EIO; 178*da9a1c10SChristophe Leroy if (get_user(addrOthers, (u32 __user * __user *)addr) != 0) 179*da9a1c10SChristophe Leroy break; 180*da9a1c10SChristophe Leroy ret = 0; 181*da9a1c10SChristophe Leroy if (ptrace_access_vm(child, (u64)addrOthers, &tmp, 182*da9a1c10SChristophe Leroy sizeof(tmp), 183*da9a1c10SChristophe Leroy FOLL_FORCE | FOLL_WRITE) == sizeof(tmp)) 184*da9a1c10SChristophe Leroy break; 185*da9a1c10SChristophe Leroy ret = -EIO; 186*da9a1c10SChristophe Leroy break; 187*da9a1c10SChristophe Leroy } 188*da9a1c10SChristophe Leroy 189*da9a1c10SChristophe Leroy /* write the word at location addr in the USER area */ 190*da9a1c10SChristophe Leroy case PTRACE_POKEUSR: { 191*da9a1c10SChristophe Leroy unsigned long index; 192*da9a1c10SChristophe Leroy 193*da9a1c10SChristophe Leroy ret = -EIO; 194*da9a1c10SChristophe Leroy /* convert to index and check */ 195*da9a1c10SChristophe Leroy index = (unsigned long) addr >> 2; 196*da9a1c10SChristophe Leroy if ((addr & 3) || (index > PT_FPSCR32)) 197*da9a1c10SChristophe Leroy break; 198*da9a1c10SChristophe Leroy 199*da9a1c10SChristophe Leroy CHECK_FULL_REGS(child->thread.regs); 200*da9a1c10SChristophe Leroy if (index < PT_FPR0) { 201*da9a1c10SChristophe Leroy ret = ptrace_put_reg(child, index, data); 202*da9a1c10SChristophe Leroy } else { 203*da9a1c10SChristophe Leroy flush_fp_to_thread(child); 204*da9a1c10SChristophe Leroy /* 205*da9a1c10SChristophe Leroy * the user space code considers the floating point 206*da9a1c10SChristophe Leroy * to be an array of unsigned int (32 bits) - the 207*da9a1c10SChristophe Leroy * index passed in is based on this assumption. 208*da9a1c10SChristophe Leroy */ 209*da9a1c10SChristophe Leroy ((unsigned int *)child->thread.fp_state.fpr) 210*da9a1c10SChristophe Leroy [FPRINDEX(index)] = data; 211*da9a1c10SChristophe Leroy ret = 0; 212*da9a1c10SChristophe Leroy } 213*da9a1c10SChristophe Leroy break; 214*da9a1c10SChristophe Leroy } 215*da9a1c10SChristophe Leroy 216*da9a1c10SChristophe Leroy /* 217*da9a1c10SChristophe Leroy * Write 4 bytes into the other process' pt_regs area 218*da9a1c10SChristophe Leroy * data is the 4 bytes that the user wants written 219*da9a1c10SChristophe Leroy * addr is the offset into the other process' pt_regs structure 220*da9a1c10SChristophe Leroy * that is to be written into 221*da9a1c10SChristophe Leroy * (this is run in a 32-bit process looking at a 64-bit process) 222*da9a1c10SChristophe Leroy */ 223*da9a1c10SChristophe Leroy case PPC_PTRACE_POKEUSR_3264: { 224*da9a1c10SChristophe Leroy u32 index; 225*da9a1c10SChristophe Leroy u32 numReg; 226*da9a1c10SChristophe Leroy 227*da9a1c10SChristophe Leroy ret = -EIO; 228*da9a1c10SChristophe Leroy /* Determine which register the user wants */ 229*da9a1c10SChristophe Leroy index = (u64)addr >> 2; 230*da9a1c10SChristophe Leroy numReg = index / 2; 231*da9a1c10SChristophe Leroy 232*da9a1c10SChristophe Leroy /* 233*da9a1c10SChristophe Leroy * Validate the input - check to see if address is on the 234*da9a1c10SChristophe Leroy * wrong boundary or beyond the end of the user area 235*da9a1c10SChristophe Leroy */ 236*da9a1c10SChristophe Leroy if ((addr & 3) || (numReg > PT_FPSCR)) 237*da9a1c10SChristophe Leroy break; 238*da9a1c10SChristophe Leroy CHECK_FULL_REGS(child->thread.regs); 239*da9a1c10SChristophe Leroy if (numReg < PT_FPR0) { 240*da9a1c10SChristophe Leroy unsigned long freg; 241*da9a1c10SChristophe Leroy ret = ptrace_get_reg(child, numReg, &freg); 242*da9a1c10SChristophe Leroy if (ret) 243*da9a1c10SChristophe Leroy break; 244*da9a1c10SChristophe Leroy if (index % 2) 245*da9a1c10SChristophe Leroy freg = (freg & ~0xfffffffful) | (data & 0xfffffffful); 246*da9a1c10SChristophe Leroy else 247*da9a1c10SChristophe Leroy freg = (freg & 0xfffffffful) | (data << 32); 248*da9a1c10SChristophe Leroy ret = ptrace_put_reg(child, numReg, freg); 249*da9a1c10SChristophe Leroy } else { 250*da9a1c10SChristophe Leroy u64 *tmp; 251*da9a1c10SChristophe Leroy flush_fp_to_thread(child); 252*da9a1c10SChristophe Leroy /* get 64 bit FPR ... */ 253*da9a1c10SChristophe Leroy tmp = &child->thread.fp_state.fpr[numReg - PT_FPR0][0]; 254*da9a1c10SChristophe Leroy /* ... write the 32 bit part we want */ 255*da9a1c10SChristophe Leroy ((u32 *)tmp)[index % 2] = data; 256*da9a1c10SChristophe Leroy ret = 0; 257*da9a1c10SChristophe Leroy } 258*da9a1c10SChristophe Leroy break; 259*da9a1c10SChristophe Leroy } 260*da9a1c10SChristophe Leroy 261*da9a1c10SChristophe Leroy case PTRACE_GET_DEBUGREG: { 262*da9a1c10SChristophe Leroy #ifndef CONFIG_PPC_ADV_DEBUG_REGS 263*da9a1c10SChristophe Leroy unsigned long dabr_fake; 264*da9a1c10SChristophe Leroy #endif 265*da9a1c10SChristophe Leroy ret = -EINVAL; 266*da9a1c10SChristophe Leroy /* We only support one DABR and no IABRS at the moment */ 267*da9a1c10SChristophe Leroy if (addr > 0) 268*da9a1c10SChristophe Leroy break; 269*da9a1c10SChristophe Leroy #ifdef CONFIG_PPC_ADV_DEBUG_REGS 270*da9a1c10SChristophe Leroy ret = put_user(child->thread.debug.dac1, (u32 __user *)data); 271*da9a1c10SChristophe Leroy #else 272*da9a1c10SChristophe Leroy dabr_fake = ( 273*da9a1c10SChristophe Leroy (child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) | 274*da9a1c10SChristophe Leroy (child->thread.hw_brk.type & HW_BRK_TYPE_DABR)); 275*da9a1c10SChristophe Leroy ret = put_user(dabr_fake, (u32 __user *)data); 276*da9a1c10SChristophe Leroy #endif 277*da9a1c10SChristophe Leroy break; 278*da9a1c10SChristophe Leroy } 279*da9a1c10SChristophe Leroy 280*da9a1c10SChristophe Leroy case PTRACE_GETREGS: /* Get all pt_regs from the child. */ 281*da9a1c10SChristophe Leroy return copy_regset_to_user( 282*da9a1c10SChristophe Leroy child, task_user_regset_view(current), 0, 283*da9a1c10SChristophe Leroy 0, PT_REGS_COUNT * sizeof(compat_long_t), 284*da9a1c10SChristophe Leroy compat_ptr(data)); 285*da9a1c10SChristophe Leroy 286*da9a1c10SChristophe Leroy case PTRACE_SETREGS: /* Set all gp regs in the child. */ 287*da9a1c10SChristophe Leroy return copy_regset_from_user( 288*da9a1c10SChristophe Leroy child, task_user_regset_view(current), 0, 289*da9a1c10SChristophe Leroy 0, PT_REGS_COUNT * sizeof(compat_long_t), 290*da9a1c10SChristophe Leroy compat_ptr(data)); 291*da9a1c10SChristophe Leroy 292*da9a1c10SChristophe Leroy case PTRACE_GETFPREGS: 293*da9a1c10SChristophe Leroy case PTRACE_SETFPREGS: 294*da9a1c10SChristophe Leroy case PTRACE_GETVRREGS: 295*da9a1c10SChristophe Leroy case PTRACE_SETVRREGS: 296*da9a1c10SChristophe Leroy case PTRACE_GETVSRREGS: 297*da9a1c10SChristophe Leroy case PTRACE_SETVSRREGS: 298*da9a1c10SChristophe Leroy case PTRACE_GETREGS64: 299*da9a1c10SChristophe Leroy case PTRACE_SETREGS64: 300*da9a1c10SChristophe Leroy case PTRACE_KILL: 301*da9a1c10SChristophe Leroy case PTRACE_SINGLESTEP: 302*da9a1c10SChristophe Leroy case PTRACE_DETACH: 303*da9a1c10SChristophe Leroy case PTRACE_SET_DEBUGREG: 304*da9a1c10SChristophe Leroy case PTRACE_SYSCALL: 305*da9a1c10SChristophe Leroy case PTRACE_CONT: 306*da9a1c10SChristophe Leroy case PPC_PTRACE_GETHWDBGINFO: 307*da9a1c10SChristophe Leroy case PPC_PTRACE_SETHWDEBUG: 308*da9a1c10SChristophe Leroy case PPC_PTRACE_DELHWDEBUG: 309*da9a1c10SChristophe Leroy ret = arch_ptrace(child, request, addr, data); 310*da9a1c10SChristophe Leroy break; 311*da9a1c10SChristophe Leroy 312*da9a1c10SChristophe Leroy default: 313*da9a1c10SChristophe Leroy ret = compat_ptrace_request(child, request, addr, data); 314*da9a1c10SChristophe Leroy break; 315*da9a1c10SChristophe Leroy } 316*da9a1c10SChristophe Leroy 317*da9a1c10SChristophe Leroy return ret; 318*da9a1c10SChristophe Leroy } 319