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