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 * Audit support: Yuichi Nakamura <ynakam@hitachisoft.jp> 10 */ 11 #include <linux/kernel.h> 12 #include <linux/sched.h> 13 #include <linux/mm.h> 14 #include <linux/smp.h> 15 #include <linux/errno.h> 16 #include <linux/ptrace.h> 17 #include <linux/user.h> 18 #include <linux/slab.h> 19 #include <linux/security.h> 20 #include <linux/signal.h> 21 #include <linux/io.h> 22 #include <linux/audit.h> 23 #include <linux/seccomp.h> 24 #include <linux/tracehook.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 void user_enable_single_step(struct task_struct *child) 63 { 64 struct pt_regs *regs = task_pt_regs(child); 65 long pc; 66 67 pc = get_stack_long(child, (long)®s->pc); 68 69 /* Next scheduling will set up UBC */ 70 if (child->thread.ubc_pc == 0) 71 ubc_usercnt += 1; 72 73 child->thread.ubc_pc = pc; 74 75 set_tsk_thread_flag(child, TIF_SINGLESTEP); 76 } 77 78 void user_disable_single_step(struct task_struct *child) 79 { 80 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 81 82 /* 83 * Ensure the UBC is not programmed at the next context switch. 84 * 85 * Normally this is not needed but there are sequences such as 86 * singlestep, signal delivery, and continue that leave the 87 * ubc_pc non-zero leading to spurious SIGTRAPs. 88 */ 89 if (child->thread.ubc_pc != 0) { 90 ubc_usercnt -= 1; 91 child->thread.ubc_pc = 0; 92 } 93 } 94 95 /* 96 * Called by kernel/ptrace.c when detaching.. 97 * 98 * Make sure single step bits etc are not set. 99 */ 100 void ptrace_disable(struct task_struct *child) 101 { 102 user_disable_single_step(child); 103 } 104 105 long arch_ptrace(struct task_struct *child, long request, long addr, long data) 106 { 107 struct user * dummy = NULL; 108 int ret; 109 110 switch (request) { 111 /* read the word at location addr in the USER area. */ 112 case PTRACE_PEEKUSR: { 113 unsigned long tmp; 114 115 ret = -EIO; 116 if ((addr & 3) || addr < 0 || 117 addr > sizeof(struct user) - 3) 118 break; 119 120 if (addr < sizeof(struct pt_regs)) 121 tmp = get_stack_long(child, addr); 122 else if (addr >= (long) &dummy->fpu && 123 addr < (long) &dummy->u_fpvalid) { 124 if (!tsk_used_math(child)) { 125 if (addr == (long)&dummy->fpu.fpscr) 126 tmp = FPSCR_INIT; 127 else 128 tmp = 0; 129 } else 130 tmp = ((long *)&child->thread.fpu) 131 [(addr - (long)&dummy->fpu) >> 2]; 132 } else if (addr == (long) &dummy->u_fpvalid) 133 tmp = !!tsk_used_math(child); 134 else 135 tmp = 0; 136 ret = put_user(tmp, (unsigned long __user *)data); 137 break; 138 } 139 140 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 141 ret = -EIO; 142 if ((addr & 3) || addr < 0 || 143 addr > sizeof(struct user) - 3) 144 break; 145 146 if (addr < sizeof(struct pt_regs)) 147 ret = put_stack_long(child, addr, data); 148 else if (addr >= (long) &dummy->fpu && 149 addr < (long) &dummy->u_fpvalid) { 150 set_stopped_child_used_math(child); 151 ((long *)&child->thread.fpu) 152 [(addr - (long)&dummy->fpu) >> 2] = data; 153 ret = 0; 154 } else if (addr == (long) &dummy->u_fpvalid) { 155 conditional_stopped_child_used_math(data, child); 156 ret = 0; 157 } 158 break; 159 160 #ifdef CONFIG_SH_DSP 161 case PTRACE_GETDSPREGS: { 162 unsigned long dp; 163 164 ret = -EIO; 165 dp = ((unsigned long) child) + THREAD_SIZE - 166 sizeof(struct pt_dspregs); 167 if (*((int *) (dp - 4)) == SR_FD) { 168 copy_to_user((void *)addr, (void *) dp, 169 sizeof(struct pt_dspregs)); 170 ret = 0; 171 } 172 break; 173 } 174 175 case PTRACE_SETDSPREGS: { 176 unsigned long dp; 177 178 ret = -EIO; 179 dp = ((unsigned long) child) + THREAD_SIZE - 180 sizeof(struct pt_dspregs); 181 if (*((int *) (dp - 4)) == SR_FD) { 182 copy_from_user((void *) dp, (void *)addr, 183 sizeof(struct pt_dspregs)); 184 ret = 0; 185 } 186 break; 187 } 188 #endif 189 #ifdef CONFIG_BINFMT_ELF_FDPIC 190 case PTRACE_GETFDPIC: { 191 unsigned long tmp = 0; 192 193 switch (addr) { 194 case PTRACE_GETFDPIC_EXEC: 195 tmp = child->mm->context.exec_fdpic_loadmap; 196 break; 197 case PTRACE_GETFDPIC_INTERP: 198 tmp = child->mm->context.interp_fdpic_loadmap; 199 break; 200 default: 201 break; 202 } 203 204 ret = 0; 205 if (put_user(tmp, (unsigned long *) data)) { 206 ret = -EFAULT; 207 break; 208 } 209 break; 210 } 211 #endif 212 default: 213 ret = ptrace_request(child, request, addr, data); 214 break; 215 } 216 217 return ret; 218 } 219 220 static inline int audit_arch(void) 221 { 222 int arch = EM_SH; 223 224 #ifdef CONFIG_CPU_LITTLE_ENDIAN 225 arch |= __AUDIT_ARCH_LE; 226 #endif 227 228 return arch; 229 } 230 231 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) 232 { 233 long ret = 0; 234 235 secure_computing(regs->regs[0]); 236 237 if (test_thread_flag(TIF_SYSCALL_TRACE) && 238 tracehook_report_syscall_entry(regs)) 239 /* 240 * Tracing decided this syscall should not happen. 241 * We'll return a bogus call number to get an ENOSYS 242 * error, but leave the original number in regs->regs[0]. 243 */ 244 ret = -1L; 245 246 if (unlikely(current->audit_context)) 247 audit_syscall_entry(audit_arch(), regs->regs[3], 248 regs->regs[4], regs->regs[5], 249 regs->regs[6], regs->regs[7]); 250 251 return ret ?: regs->regs[0]; 252 } 253 254 asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) 255 { 256 int step; 257 258 if (unlikely(current->audit_context)) 259 audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), 260 regs->regs[0]); 261 262 step = test_thread_flag(TIF_SINGLESTEP); 263 if (step || test_thread_flag(TIF_SYSCALL_TRACE)) 264 tracehook_report_syscall_exit(regs, step); 265 } 266