1/* 2 * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus 3 */ 4/* 5 * linux/arch/ppc/kernel/ptrace.c 6 * 7 * PowerPC version 8 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 9 * 10 * Derived from "arch/m68k/kernel/ptrace.c" 11 * Copyright (C) 1994 by Hamish Macdonald 12 * Taken from linux/kernel/ptrace.c and modified for M680x0. 13 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds 14 * 15 * Modified by Cort Dougan (cort@hq.fsmlabs.com) 16 * and Paul Mackerras (paulus@linuxcare.com.au). 17 * 18 * This file is subject to the terms and conditions of the GNU General 19 * Public License. Please read the COPYING file for all license details. 20 */ 21 22#include <linux/kernel.h> 23#include <linux/sched.h> 24#include <linux/mm.h> 25#include <linux/smp.h> 26#include <linux/smp_lock.h> 27#include <linux/errno.h> 28#include <linux/ptrace.h> 29#include <linux/user.h> 30 31#include <asm/uaccess.h> 32#include <asm/page.h> 33#include <asm/pgtable.h> 34#include <asm/system.h> 35 36/* 37 * Set of msr bits that gdb can change on behalf of a process. 38 */ 39#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1) 40 41/* 42 * does not yet catch signals sent when the child dies. 43 * in exit.c or in signal.c. 44 */ 45 46/* 47 * Get contents of register REGNO in task TASK. 48 */ 49static inline unsigned long get_reg(struct task_struct *task, int regno) 50{ 51 if (regno < sizeof(struct pt_regs) / sizeof(unsigned long) 52 && task->thread.regs != NULL) 53 return ((unsigned long *)task->thread.regs)[regno]; 54 return (0); 55} 56 57/* 58 * Write contents of register REGNO in task TASK. 59 */ 60static inline int put_reg(struct task_struct *task, int regno, 61 unsigned long data) 62{ 63 if (regno <= PT_MQ && task->thread.regs != NULL) { 64 if (regno == PT_MSR) 65 data = (data & MSR_DEBUGCHANGE) 66 | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); 67 ((unsigned long *)task->thread.regs)[regno] = data; 68 return 0; 69 } 70 return -EIO; 71} 72 73#ifdef CONFIG_ALTIVEC 74/* 75 * Get contents of AltiVec register state in task TASK 76 */ 77static inline int get_vrregs(unsigned long *data, struct task_struct *task) 78{ 79 int i, j; 80 81 if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long))) 82 return -EFAULT; 83 84 /* copy AltiVec registers VR[0] .. VR[31] */ 85 for (i = 0; i < 32; i++) 86 for (j = 0; j < 4; j++, data++) 87 if (__put_user(task->thread.vr[i].u[j], data)) 88 return -EFAULT; 89 90 /* copy VSCR */ 91 for (i = 0; i < 4; i++, data++) 92 if (__put_user(task->thread.vscr.u[i], data)) 93 return -EFAULT; 94 95 /* copy VRSAVE */ 96 if (__put_user(task->thread.vrsave, data)) 97 return -EFAULT; 98 99 return 0; 100} 101 102/* 103 * Write contents of AltiVec register state into task TASK. 104 */ 105static inline int set_vrregs(struct task_struct *task, unsigned long *data) 106{ 107 int i, j; 108 109 if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long))) 110 return -EFAULT; 111 112 /* copy AltiVec registers VR[0] .. VR[31] */ 113 for (i = 0; i < 32; i++) 114 for (j = 0; j < 4; j++, data++) 115 if (__get_user(task->thread.vr[i].u[j], data)) 116 return -EFAULT; 117 118 /* copy VSCR */ 119 for (i = 0; i < 4; i++, data++) 120 if (__get_user(task->thread.vscr.u[i], data)) 121 return -EFAULT; 122 123 /* copy VRSAVE */ 124 if (__get_user(task->thread.vrsave, data)) 125 return -EFAULT; 126 127 return 0; 128} 129#endif 130 131static inline void 132set_single_step(struct task_struct *task) 133{ 134 struct pt_regs *regs = task->thread.regs; 135 136 if (regs != NULL) 137 regs->msr |= MSR_SE; 138} 139 140static inline void 141clear_single_step(struct task_struct *task) 142{ 143 struct pt_regs *regs = task->thread.regs; 144 145 if (regs != NULL) 146 regs->msr &= ~MSR_SE; 147} 148 149/* 150 * Called by kernel/ptrace.c when detaching.. 151 * 152 * Make sure single step bits etc are not set. 153 */ 154void ptrace_disable(struct task_struct *child) 155{ 156 /* make sure the single step bit is not set. */ 157 clear_single_step(child); 158} 159 160int sys_ptrace(long request, long pid, long addr, long data) 161{ 162 struct task_struct *child; 163 int ret = -EPERM; 164 165 lock_kernel(); 166 if (request == PTRACE_TRACEME) { 167 /* are we already being traced? */ 168 if (current->ptrace & PT_PTRACED) 169 goto out; 170 /* set the ptrace bit in the process flags. */ 171 current->ptrace |= PT_PTRACED; 172 ret = 0; 173 goto out; 174 } 175 ret = -ESRCH; 176 read_lock(&tasklist_lock); 177 child = find_task_by_pid(pid); 178 if (child) 179 get_task_struct(child); 180 read_unlock(&tasklist_lock); 181 if (!child) 182 goto out; 183 184 ret = -EPERM; 185 if (pid == 1) /* you may not mess with init */ 186 goto out_tsk; 187 188 if (request == PTRACE_ATTACH) { 189 ret = ptrace_attach(child); 190 goto out_tsk; 191 } 192 193 ret = ptrace_check_attach(child, request == PTRACE_KILL); 194 if (ret < 0) 195 goto out_tsk; 196 197 switch (request) { 198 /* when I and D space are separate, these will need to be fixed. */ 199 case PTRACE_PEEKTEXT: /* read word at location addr. */ 200 case PTRACE_PEEKDATA: { 201 unsigned long tmp; 202 int copied; 203 204 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); 205 ret = -EIO; 206 if (copied != sizeof(tmp)) 207 break; 208 ret = put_user(tmp,(unsigned long *) data); 209 break; 210 } 211 212 /* read the word at location addr in the USER area. */ 213 case PTRACE_PEEKUSR: { 214 unsigned long index, tmp; 215 216 ret = -EIO; 217 /* convert to index and check */ 218 index = (unsigned long) addr >> 2; 219 if ((addr & 3) || index > PT_FPSCR) 220 break; 221 222 if (index < PT_FPR0) { 223 tmp = get_reg(child, (int) index); 224 } else { 225 if (child->thread.regs != NULL 226 && child->thread.regs->msr & MSR_FP) 227 giveup_fpu(child); 228 tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; 229 } 230 ret = put_user(tmp,(unsigned long *) data); 231 break; 232 } 233 234 /* If I and D space are separate, this will have to be fixed. */ 235 case PTRACE_POKETEXT: /* write the word at location addr. */ 236 case PTRACE_POKEDATA: 237 ret = 0; 238 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) 239 break; 240 ret = -EIO; 241 break; 242 243 /* write the word at location addr in the USER area */ 244 case PTRACE_POKEUSR: { 245 unsigned long index; 246 247 ret = -EIO; 248 /* convert to index and check */ 249 index = (unsigned long) addr >> 2; 250 if ((addr & 3) || index > PT_FPSCR) 251 break; 252 253 if (index == PT_ORIG_R3) 254 break; 255 if (index < PT_FPR0) { 256 ret = put_reg(child, index, data); 257 } else { 258 if (child->thread.regs != NULL 259 && child->thread.regs->msr & MSR_FP) 260 giveup_fpu(child); 261 ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; 262 ret = 0; 263 } 264 break; 265 } 266 267 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 268 case PTRACE_CONT: { /* restart after signal. */ 269 ret = -EIO; 270 if ((unsigned long) data > _NSIG) 271 break; 272 if (request == PTRACE_SYSCALL) 273 child->ptrace |= PT_TRACESYS; 274 else 275 child->ptrace &= ~PT_TRACESYS; 276 child->exit_code = data; 277 /* make sure the single step bit is not set. */ 278 clear_single_step(child); 279 wake_up_process(child); 280 ret = 0; 281 break; 282 } 283 284/* 285 * make the child exit. Best I can do is send it a sigkill. 286 * perhaps it should be put in the status that it wants to 287 * exit. 288 */ 289 case PTRACE_KILL: { 290 ret = 0; 291 if (child->state == TASK_ZOMBIE) /* already dead */ 292 break; 293 child->exit_code = SIGKILL; 294 /* make sure the single step bit is not set. */ 295 clear_single_step(child); 296 wake_up_process(child); 297 break; 298 } 299 300 case PTRACE_SINGLESTEP: { /* set the trap flag. */ 301 ret = -EIO; 302 if ((unsigned long) data > _NSIG) 303 break; 304 child->ptrace &= ~PT_TRACESYS; 305 set_single_step(child); 306 child->exit_code = data; 307 /* give it a chance to run. */ 308 wake_up_process(child); 309 ret = 0; 310 break; 311 } 312 313 case PTRACE_DETACH: 314 ret = ptrace_detach(child, data); 315 break; 316 317#ifdef CONFIG_ALTIVEC 318 case PTRACE_GETVRREGS: 319 /* Get the child altivec register state. */ 320 if (child->thread.regs->msr & MSR_VEC) 321 giveup_altivec(child); 322 ret = get_vrregs((unsigned long *)data, child); 323 break; 324 325 case PTRACE_SETVRREGS: 326 /* Set the child altivec register state. */ 327 /* this is to clear the MSR_VEC bit to force a reload 328 * of register state from memory */ 329 if (child->thread.regs->msr & MSR_VEC) 330 giveup_altivec(child); 331 ret = set_vrregs(child, (unsigned long *)data); 332 break; 333#endif 334 335 default: 336 ret = -EIO; 337 break; 338 } 339out_tsk: 340 free_task_struct(child); 341out: 342 unlock_kernel(); 343 return ret; 344} 345 346void syscall_trace(void) 347{ 348 if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) 349 != (PT_PTRACED|PT_TRACESYS)) 350 return; 351 current->exit_code = SIGTRAP; 352 current->state = TASK_STOPPED; 353 notify_parent(current, SIGCHLD); 354 schedule(); 355 /* 356 * this isn't the same as continuing with a signal, but it will do 357 * for normal use. strace only continues with a signal if the 358 * stopping signal is not SIGTRAP. -brl 359 */ 360 if (current->exit_code) { 361 send_sig(current->exit_code, current, 1); 362 current->exit_code = 0; 363 } 364} 365