blob: e9bd4b2aa9c2659ba219457e66a2a407877e6d6f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Yuichi Nakamura1322b9d2007-11-10 19:21:34 +09009 * Audit support: Yuichi Nakamura <ynakam@hitachisoft.jp>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <linux/mm.h>
14#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
16#include <linux/ptrace.h>
17#include <linux/user.h>
18#include <linux/slab.h>
19#include <linux/security.h>
Jesper Juhl7ed20e12005-05-01 08:59:14 -070020#include <linux/signal.h>
Stuart Menefy9432f962007-02-23 13:22:17 +090021#include <linux/io.h>
Yuichi Nakamura1322b9d2007-11-10 19:21:34 +090022#include <linux/audit.h>
Paul Mundtc4637d42008-07-30 15:30:52 +090023#include <linux/seccomp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/uaccess.h>
25#include <asm/pgtable.h>
26#include <asm/system.h>
27#include <asm/processor.h>
28#include <asm/mmu_context.h>
29
30/*
31 * does not yet catch signals sent when the child dies.
32 * in exit.c or in signal.c.
33 */
34
35/*
36 * This routine will get a word off of the process kernel stack.
37 */
38static inline int get_stack_long(struct task_struct *task, int offset)
39{
40 unsigned char *stack;
41
Al Viro3cf0f4e2006-01-12 01:05:44 -080042 stack = (unsigned char *)task_pt_regs(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 stack += offset;
44 return (*((int *)stack));
45}
46
47/*
48 * This routine will put a word on the process kernel stack.
49 */
50static inline int put_stack_long(struct task_struct *task, int offset,
51 unsigned long data)
52{
53 unsigned char *stack;
54
Al Viro3cf0f4e2006-01-12 01:05:44 -080055 stack = (unsigned char *)task_pt_regs(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 stack += offset;
57 *(unsigned long *) stack = data;
58 return 0;
59}
60
Stuart Menefy9432f962007-02-23 13:22:17 +090061static void ptrace_disable_singlestep(struct task_struct *child)
62{
63 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
64
65 /*
66 * Ensure the UBC is not programmed at the next context switch.
67 *
68 * Normally this is not needed but there are sequences such as
69 * singlestep, signal delivery, and continue that leave the
70 * ubc_pc non-zero leading to spurious SIGTRAPs.
71 */
72 if (child->thread.ubc_pc != 0) {
73 ubc_usercnt -= 1;
74 child->thread.ubc_pc = 0;
75 }
76}
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078/*
79 * Called by kernel/ptrace.c when detaching..
80 *
81 * Make sure single step bits etc are not set.
82 */
83void ptrace_disable(struct task_struct *child)
84{
Stuart Menefy9432f962007-02-23 13:22:17 +090085 ptrace_disable_singlestep(child);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
Christoph Hellwig481bed42005-11-07 00:59:47 -080088long arch_ptrace(struct task_struct *child, long request, long addr, long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 struct user * dummy = NULL;
91 int ret;
92
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 switch (request) {
94 /* when I and D space are separate, these will need to be fixed. */
Stuart Menefy9432f962007-02-23 13:22:17 +090095 case PTRACE_PEEKTEXT: /* read word at location addr. */
Alexey Dobriyan76647322007-07-17 04:03:43 -070096 case PTRACE_PEEKDATA:
97 ret = generic_ptrace_peekdata(child, addr, data);
Paul Mundt662ae212007-08-04 13:39:21 +090098 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100 /* read the word at location addr in the USER area. */
101 case PTRACE_PEEKUSR: {
102 unsigned long tmp;
103
104 ret = -EIO;
Stuart Menefy9432f962007-02-23 13:22:17 +0900105 if ((addr & 3) || addr < 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 addr > sizeof(struct user) - 3)
107 break;
108
109 if (addr < sizeof(struct pt_regs))
110 tmp = get_stack_long(child, addr);
111 else if (addr >= (long) &dummy->fpu &&
112 addr < (long) &dummy->u_fpvalid) {
113 if (!tsk_used_math(child)) {
114 if (addr == (long)&dummy->fpu.fpscr)
115 tmp = FPSCR_INIT;
116 else
117 tmp = 0;
118 } else
119 tmp = ((long *)&child->thread.fpu)
120 [(addr - (long)&dummy->fpu) >> 2];
121 } else if (addr == (long) &dummy->u_fpvalid)
122 tmp = !!tsk_used_math(child);
123 else
124 tmp = 0;
Paul Mundte08f4572007-05-14 12:52:56 +0900125 ret = put_user(tmp, (unsigned long __user *)data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 break;
127 }
128
129 /* when I and D space are separate, this will have to be fixed. */
130 case PTRACE_POKETEXT: /* write the word at location addr. */
131 case PTRACE_POKEDATA:
Alexey Dobriyanf284ce72007-07-17 04:03:44 -0700132 ret = generic_ptrace_pokedata(child, addr, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 break;
134
135 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
136 ret = -EIO;
Stuart Menefy9432f962007-02-23 13:22:17 +0900137 if ((addr & 3) || addr < 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 addr > sizeof(struct user) - 3)
139 break;
140
141 if (addr < sizeof(struct pt_regs))
142 ret = put_stack_long(child, addr, data);
143 else if (addr >= (long) &dummy->fpu &&
144 addr < (long) &dummy->u_fpvalid) {
145 set_stopped_child_used_math(child);
146 ((long *)&child->thread.fpu)
147 [(addr - (long)&dummy->fpu) >> 2] = data;
148 ret = 0;
149 } else if (addr == (long) &dummy->u_fpvalid) {
150 conditional_stopped_child_used_math(data, child);
151 ret = 0;
152 }
153 break;
154
155 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
156 case PTRACE_CONT: { /* restart after signal. */
157 ret = -EIO;
Jesper Juhl7ed20e12005-05-01 08:59:14 -0700158 if (!valid_signal(data))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 break;
160 if (request == PTRACE_SYSCALL)
161 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
162 else
163 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
Stuart Menefy9432f962007-02-23 13:22:17 +0900164
165 ptrace_disable_singlestep(child);
166
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 child->exit_code = data;
168 wake_up_process(child);
169 ret = 0;
170 break;
171 }
172
173/*
Stuart Menefy9432f962007-02-23 13:22:17 +0900174 * make the child exit. Best I can do is send it a sigkill.
175 * perhaps it should be put in the status that it wants to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 * exit.
177 */
178 case PTRACE_KILL: {
179 ret = 0;
180 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
181 break;
Stuart Menefy9432f962007-02-23 13:22:17 +0900182 ptrace_disable_singlestep(child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 child->exit_code = SIGKILL;
184 wake_up_process(child);
185 break;
186 }
187
188 case PTRACE_SINGLESTEP: { /* set the trap flag. */
189 long pc;
Paul Mundte08f4572007-05-14 12:52:56 +0900190 struct pt_regs *regs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
192 ret = -EIO;
Jesper Juhl7ed20e12005-05-01 08:59:14 -0700193 if (!valid_signal(data))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 break;
195 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
196 if ((child->ptrace & PT_DTRACE) == 0) {
197 /* Spurious delayed TF traps may occur */
198 child->ptrace |= PT_DTRACE;
199 }
200
Paul Mundte08f4572007-05-14 12:52:56 +0900201 pc = get_stack_long(child, (long)&regs->pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
203 /* Next scheduling will set up UBC */
204 if (child->thread.ubc_pc == 0)
205 ubc_usercnt += 1;
206 child->thread.ubc_pc = pc;
207
Stuart Menefy9432f962007-02-23 13:22:17 +0900208 set_tsk_thread_flag(child, TIF_SINGLESTEP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 child->exit_code = data;
210 /* give it a chance to run. */
211 wake_up_process(child);
212 ret = 0;
213 break;
214 }
215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216#ifdef CONFIG_SH_DSP
217 case PTRACE_GETDSPREGS: {
218 unsigned long dp;
219
220 ret = -EIO;
221 dp = ((unsigned long) child) + THREAD_SIZE -
222 sizeof(struct pt_dspregs);
223 if (*((int *) (dp - 4)) == SR_FD) {
Magnus Damm09061852008-02-08 17:26:54 +0900224 copy_to_user((void *)addr, (void *) dp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 sizeof(struct pt_dspregs));
226 ret = 0;
227 }
228 break;
229 }
230
231 case PTRACE_SETDSPREGS: {
232 unsigned long dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 ret = -EIO;
235 dp = ((unsigned long) child) + THREAD_SIZE -
236 sizeof(struct pt_dspregs);
237 if (*((int *) (dp - 4)) == SR_FD) {
Magnus Damm09061852008-02-08 17:26:54 +0900238 copy_from_user((void *) dp, (void *)addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 sizeof(struct pt_dspregs));
240 ret = 0;
241 }
242 break;
243 }
244#endif
Paul Mundt3bc24a12008-05-19 13:40:12 +0900245#ifdef CONFIG_BINFMT_ELF_FDPIC
246 case PTRACE_GETFDPIC: {
247 unsigned long tmp = 0;
248
249 switch (addr) {
250 case PTRACE_GETFDPIC_EXEC:
251 tmp = child->mm->context.exec_fdpic_loadmap;
252 break;
253 case PTRACE_GETFDPIC_INTERP:
254 tmp = child->mm->context.interp_fdpic_loadmap;
255 break;
256 default:
257 break;
258 }
259
260 ret = 0;
261 if (put_user(tmp, (unsigned long *) data)) {
262 ret = -EFAULT;
263 break;
264 }
265 break;
266 }
267#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 default:
269 ret = ptrace_request(child, request, addr, data);
270 break;
271 }
Christoph Hellwig481bed42005-11-07 00:59:47 -0800272
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return ret;
274}
275
Yuichi Nakamura1322b9d2007-11-10 19:21:34 +0900276asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 struct task_struct *tsk = current;
279
Paul Mundtc4637d42008-07-30 15:30:52 +0900280 secure_computing(regs->regs[0]);
281
Yuichi Nakamura1322b9d2007-11-10 19:21:34 +0900282 if (unlikely(current->audit_context) && entryexit)
283 audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
284 regs->regs[0]);
285
Stuart Menefy9432f962007-02-23 13:22:17 +0900286 if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
287 !test_thread_flag(TIF_SINGLESTEP))
Yuichi Nakamura1322b9d2007-11-10 19:21:34 +0900288 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 if (!(tsk->ptrace & PT_PTRACED))
Yuichi Nakamura1322b9d2007-11-10 19:21:34 +0900290 goto out;
291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 /* the 0x80 provides a way for the tracing parent to distinguish
293 between a syscall stop and SIGTRAP delivery */
Stuart Menefy9432f962007-02-23 13:22:17 +0900294 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
295 !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 /*
298 * this isn't the same as continuing with a signal, but it will do
299 * for normal use. strace only continues with a signal if the
300 * stopping signal is not SIGTRAP. -brl
301 */
302 if (tsk->exit_code) {
303 send_sig(tsk->exit_code, tsk, 1);
304 tsk->exit_code = 0;
305 }
Yuichi Nakamura1322b9d2007-11-10 19:21:34 +0900306
307out:
308 if (unlikely(current->audit_context) && !entryexit)
309 audit_syscall_entry(AUDIT_ARCH_SH, regs->regs[3],
310 regs->regs[4], regs->regs[5],
311 regs->regs[6], regs->regs[7]);
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313}