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