1 /* 2 * linux/arch/sh/kernel/ptrace.c 3 * 4 * Original x86 implementation: 5 * By Ross Biro 1/23/92 6 * edited by Linus Torvalds 7 * 8 * SuperH version: Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka 9 * 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/sched.h> 14 #include <linux/mm.h> 15 #include <linux/smp.h> 16 #include <linux/smp_lock.h> 17 #include <linux/errno.h> 18 #include <linux/ptrace.h> 19 #include <linux/user.h> 20 #include <linux/slab.h> 21 #include <linux/security.h> 22 #include <linux/signal.h> 23 24 #include <asm/io.h> 25 #include <asm/uaccess.h> 26 #include <asm/pgtable.h> 27 #include <asm/system.h> 28 #include <asm/processor.h> 29 #include <asm/mmu_context.h> 30 31 /* 32 * does not yet catch signals sent when the child dies. 33 * in exit.c or in signal.c. 34 */ 35 36 /* 37 * This routine will get a word off of the process kernel stack. 38 */ 39 static inline int get_stack_long(struct task_struct *task, int offset) 40 { 41 unsigned char *stack; 42 43 stack = (unsigned char *)task_pt_regs(task); 44 stack += offset; 45 return (*((int *)stack)); 46 } 47 48 /* 49 * This routine will put a word on the process kernel stack. 50 */ 51 static inline int put_stack_long(struct task_struct *task, int offset, 52 unsigned long data) 53 { 54 unsigned char *stack; 55 56 stack = (unsigned char *)task_pt_regs(task); 57 stack += offset; 58 *(unsigned long *) stack = data; 59 return 0; 60 } 61 62 /* 63 * Called by kernel/ptrace.c when detaching.. 64 * 65 * Make sure single step bits etc are not set. 66 */ 67 void ptrace_disable(struct task_struct *child) 68 { 69 /* nothing to do.. */ 70 } 71 72 long arch_ptrace(struct task_struct *child, long request, long addr, long data) 73 { 74 struct user * dummy = NULL; 75 int ret; 76 77 switch (request) { 78 /* when I and D space are separate, these will need to be fixed. */ 79 case PTRACE_PEEKTEXT: /* read word at location addr. */ 80 case PTRACE_PEEKDATA: { 81 unsigned long tmp; 82 int copied; 83 84 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); 85 ret = -EIO; 86 if (copied != sizeof(tmp)) 87 break; 88 ret = put_user(tmp,(unsigned long *) data); 89 break; 90 } 91 92 /* read the word at location addr in the USER area. */ 93 case PTRACE_PEEKUSR: { 94 unsigned long tmp; 95 96 ret = -EIO; 97 if ((addr & 3) || addr < 0 || 98 addr > sizeof(struct user) - 3) 99 break; 100 101 if (addr < sizeof(struct pt_regs)) 102 tmp = get_stack_long(child, addr); 103 else if (addr >= (long) &dummy->fpu && 104 addr < (long) &dummy->u_fpvalid) { 105 if (!tsk_used_math(child)) { 106 if (addr == (long)&dummy->fpu.fpscr) 107 tmp = FPSCR_INIT; 108 else 109 tmp = 0; 110 } else 111 tmp = ((long *)&child->thread.fpu) 112 [(addr - (long)&dummy->fpu) >> 2]; 113 } else if (addr == (long) &dummy->u_fpvalid) 114 tmp = !!tsk_used_math(child); 115 else 116 tmp = 0; 117 ret = put_user(tmp, (unsigned long *)data); 118 break; 119 } 120 121 /* when I and D space are separate, this will have to be fixed. */ 122 case PTRACE_POKETEXT: /* write the word at location addr. */ 123 case PTRACE_POKEDATA: 124 ret = 0; 125 if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) 126 break; 127 ret = -EIO; 128 break; 129 130 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 131 ret = -EIO; 132 if ((addr & 3) || addr < 0 || 133 addr > sizeof(struct user) - 3) 134 break; 135 136 if (addr < sizeof(struct pt_regs)) 137 ret = put_stack_long(child, addr, data); 138 else if (addr >= (long) &dummy->fpu && 139 addr < (long) &dummy->u_fpvalid) { 140 set_stopped_child_used_math(child); 141 ((long *)&child->thread.fpu) 142 [(addr - (long)&dummy->fpu) >> 2] = data; 143 ret = 0; 144 } else if (addr == (long) &dummy->u_fpvalid) { 145 conditional_stopped_child_used_math(data, child); 146 ret = 0; 147 } 148 break; 149 150 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 151 case PTRACE_CONT: { /* restart after signal. */ 152 ret = -EIO; 153 if (!valid_signal(data)) 154 break; 155 if (request == PTRACE_SYSCALL) 156 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 157 else 158 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 159 child->exit_code = data; 160 wake_up_process(child); 161 ret = 0; 162 break; 163 } 164 165 /* 166 * make the child exit. Best I can do is send it a sigkill. 167 * perhaps it should be put in the status that it wants to 168 * exit. 169 */ 170 case PTRACE_KILL: { 171 ret = 0; 172 if (child->exit_state == EXIT_ZOMBIE) /* already dead */ 173 break; 174 child->exit_code = SIGKILL; 175 wake_up_process(child); 176 break; 177 } 178 179 case PTRACE_SINGLESTEP: { /* set the trap flag. */ 180 long pc; 181 struct pt_regs *dummy = NULL; 182 183 ret = -EIO; 184 if (!valid_signal(data)) 185 break; 186 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); 187 if ((child->ptrace & PT_DTRACE) == 0) { 188 /* Spurious delayed TF traps may occur */ 189 child->ptrace |= PT_DTRACE; 190 } 191 192 pc = get_stack_long(child, (long)&dummy->pc); 193 194 /* Next scheduling will set up UBC */ 195 if (child->thread.ubc_pc == 0) 196 ubc_usercnt += 1; 197 child->thread.ubc_pc = pc; 198 199 child->exit_code = data; 200 /* give it a chance to run. */ 201 wake_up_process(child); 202 ret = 0; 203 break; 204 } 205 206 case PTRACE_DETACH: /* detach a process that was attached. */ 207 ret = ptrace_detach(child, data); 208 break; 209 210 #ifdef CONFIG_SH_DSP 211 case PTRACE_GETDSPREGS: { 212 unsigned long dp; 213 214 ret = -EIO; 215 dp = ((unsigned long) child) + THREAD_SIZE - 216 sizeof(struct pt_dspregs); 217 if (*((int *) (dp - 4)) == SR_FD) { 218 copy_to_user(addr, (void *) dp, 219 sizeof(struct pt_dspregs)); 220 ret = 0; 221 } 222 break; 223 } 224 225 case PTRACE_SETDSPREGS: { 226 unsigned long dp; 227 int i; 228 229 ret = -EIO; 230 dp = ((unsigned long) child) + THREAD_SIZE - 231 sizeof(struct pt_dspregs); 232 if (*((int *) (dp - 4)) == SR_FD) { 233 copy_from_user((void *) dp, addr, 234 sizeof(struct pt_dspregs)); 235 ret = 0; 236 } 237 break; 238 } 239 #endif 240 default: 241 ret = ptrace_request(child, request, addr, data); 242 break; 243 } 244 245 return ret; 246 } 247 248 asmlinkage void do_syscall_trace(void) 249 { 250 struct task_struct *tsk = current; 251 252 if (!test_thread_flag(TIF_SYSCALL_TRACE)) 253 return; 254 if (!(tsk->ptrace & PT_PTRACED)) 255 return; 256 /* the 0x80 provides a way for the tracing parent to distinguish 257 between a syscall stop and SIGTRAP delivery */ 258 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) 259 ? 0x80 : 0)); 260 261 /* 262 * this isn't the same as continuing with a signal, but it will do 263 * for normal use. strace only continues with a signal if the 264 * stopping signal is not SIGTRAP. -brl 265 */ 266 if (tsk->exit_code) { 267 send_sig(tsk->exit_code, tsk, 1); 268 tsk->exit_code = 0; 269 } 270 } 271