Merge branch 'misc' into release
[linux-2.6] / arch / mn10300 / kernel / ptrace.c
1 /* MN10300 Process tracing
2  *
3  * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5  * Modified by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
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 <asm/uaccess.h>
21 #include <asm/pgtable.h>
22 #include <asm/system.h>
23 #include <asm/processor.h>
24 #include <asm/cacheflush.h>
25 #include <asm/fpu.h>
26 #include <asm/asm-offsets.h>
27
28 /*
29  * translate ptrace register IDs into struct pt_regs offsets
30  */
31 static const u8 ptrace_regid_to_frame[] = {
32         [PT_A3 << 2]            = REG_A3,
33         [PT_A2 << 2]            = REG_A2,
34         [PT_D3 << 2]            = REG_D3,
35         [PT_D2 << 2]            = REG_D2,
36         [PT_MCVF << 2]          = REG_MCVF,
37         [PT_MCRL << 2]          = REG_MCRL,
38         [PT_MCRH << 2]          = REG_MCRH,
39         [PT_MDRQ << 2]          = REG_MDRQ,
40         [PT_E1 << 2]            = REG_E1,
41         [PT_E0 << 2]            = REG_E0,
42         [PT_E7 << 2]            = REG_E7,
43         [PT_E6 << 2]            = REG_E6,
44         [PT_E5 << 2]            = REG_E5,
45         [PT_E4 << 2]            = REG_E4,
46         [PT_E3 << 2]            = REG_E3,
47         [PT_E2 << 2]            = REG_E2,
48         [PT_SP << 2]            = REG_SP,
49         [PT_LAR << 2]           = REG_LAR,
50         [PT_LIR << 2]           = REG_LIR,
51         [PT_MDR << 2]           = REG_MDR,
52         [PT_A1 << 2]            = REG_A1,
53         [PT_A0 << 2]            = REG_A0,
54         [PT_D1 << 2]            = REG_D1,
55         [PT_D0 << 2]            = REG_D0,
56         [PT_ORIG_D0 << 2]       = REG_ORIG_D0,
57         [PT_EPSW << 2]          = REG_EPSW,
58         [PT_PC << 2]            = REG_PC,
59 };
60
61 static inline int get_stack_long(struct task_struct *task, int offset)
62 {
63         return *(unsigned long *)
64                 ((unsigned long) task->thread.uregs + offset);
65 }
66
67 /*
68  * this routine will put a word on the processes privileged stack.
69  * the offset is how far from the base addr as stored in the TSS.
70  * this routine assumes that all the privileged stacks are in our
71  * data space.
72  */
73 static inline
74 int put_stack_long(struct task_struct *task, int offset, unsigned long data)
75 {
76         unsigned long stack;
77
78         stack = (unsigned long) task->thread.uregs + offset;
79         *(unsigned long *) stack = data;
80         return 0;
81 }
82
83 static inline unsigned long get_fpregs(struct fpu_state_struct *buf,
84                                        struct task_struct *tsk)
85 {
86         return __copy_to_user(buf, &tsk->thread.fpu_state,
87                               sizeof(struct fpu_state_struct));
88 }
89
90 static inline unsigned long set_fpregs(struct task_struct *tsk,
91                                        struct fpu_state_struct *buf)
92 {
93         return __copy_from_user(&tsk->thread.fpu_state, buf,
94                                 sizeof(struct fpu_state_struct));
95 }
96
97 static inline void fpsave_init(struct task_struct *task)
98 {
99         memset(&task->thread.fpu_state, 0, sizeof(struct fpu_state_struct));
100 }
101
102 /*
103  * make sure the single step bit is not set
104  */
105 void ptrace_disable(struct task_struct *child)
106 {
107 #ifndef CONFIG_MN10300_USING_JTAG
108         struct user *dummy = NULL;
109         long tmp;
110
111         tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
112         tmp &= ~EPSW_T;
113         put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
114 #endif
115 }
116
117 /*
118  * set the single step bit
119  */
120 void ptrace_enable(struct task_struct *child)
121 {
122 #ifndef CONFIG_MN10300_USING_JTAG
123         struct user *dummy = NULL;
124         long tmp;
125
126         tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
127         tmp |= EPSW_T;
128         put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
129 #endif
130 }
131
132 /*
133  * handle the arch-specific side of process tracing
134  */
135 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
136 {
137         struct fpu_state_struct fpu_state;
138         int i, ret;
139
140         switch (request) {
141         /* read the word at location addr. */
142         case PTRACE_PEEKTEXT: {
143                 unsigned long tmp;
144                 int copied;
145
146                 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
147                 ret = -EIO;
148                 if (copied != sizeof(tmp))
149                         break;
150                 ret = put_user(tmp, (unsigned long *) data);
151                 break;
152         }
153
154         /* read the word at location addr. */
155         case PTRACE_PEEKDATA: {
156                 unsigned long tmp;
157                 int copied;
158
159                 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
160                 ret = -EIO;
161                 if (copied != sizeof(tmp))
162                         break;
163                 ret = put_user(tmp, (unsigned long *) data);
164                 break;
165         }
166
167         /* read the word at location addr in the USER area. */
168         case PTRACE_PEEKUSR: {
169                 unsigned long tmp;
170
171                 ret = -EIO;
172                 if ((addr & 3) || addr < 0 ||
173                     addr > sizeof(struct user) - 3)
174                         break;
175
176                 tmp = 0;  /* Default return condition */
177                 if (addr < NR_PTREGS << 2)
178                         tmp = get_stack_long(child,
179                                              ptrace_regid_to_frame[addr]);
180                 ret = put_user(tmp, (unsigned long *) data);
181                 break;
182         }
183
184         /* write the word at location addr. */
185         case PTRACE_POKETEXT:
186         case PTRACE_POKEDATA:
187                 if (access_process_vm(child, addr, &data, sizeof(data), 1) ==
188                     sizeof(data))
189                         ret = 0;
190                 else
191                         ret = -EIO;
192                 break;
193
194                 /* write the word at location addr in the USER area */
195         case PTRACE_POKEUSR:
196                 ret = -EIO;
197                 if ((addr & 3) || addr < 0 ||
198                     addr > sizeof(struct user) - 3)
199                         break;
200
201                 ret = 0;
202                 if (addr < NR_PTREGS << 2)
203                         ret = put_stack_long(child, ptrace_regid_to_frame[addr],
204                                              data);
205                 break;
206
207                 /* continue and stop at next (return from) syscall */
208         case PTRACE_SYSCALL:
209                 /* restart after signal. */
210         case PTRACE_CONT:
211                 ret = -EIO;
212                 if ((unsigned long) data > _NSIG)
213                         break;
214                 if (request == PTRACE_SYSCALL)
215                         set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
216                 else
217                         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
218                 child->exit_code = data;
219                 ptrace_disable(child);
220                 wake_up_process(child);
221                 ret = 0;
222                 break;
223
224                 /*
225                  * make the child exit
226                  * - the best I can do is send it a sigkill
227                  * - perhaps it should be put in the status that it wants to
228                  *   exit
229                  */
230         case PTRACE_KILL:
231                 ret = 0;
232                 if (child->exit_state == EXIT_ZOMBIE)   /* already dead */
233                         break;
234                 child->exit_code = SIGKILL;
235                 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
236                 ptrace_disable(child);
237                 wake_up_process(child);
238                 break;
239
240         case PTRACE_SINGLESTEP: /* set the trap flag. */
241 #ifndef CONFIG_MN10300_USING_JTAG
242                 ret = -EIO;
243                 if ((unsigned long) data > _NSIG)
244                         break;
245                 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
246                 ptrace_enable(child);
247                 child->exit_code = data;
248                 wake_up_process(child);
249                 ret = 0;
250 #else
251                 ret = -EINVAL;
252 #endif
253                 break;
254
255         case PTRACE_DETACH:     /* detach a process that was attached. */
256                 ret = ptrace_detach(child, data);
257                 break;
258
259                 /* Get all gp regs from the child. */
260         case PTRACE_GETREGS: {
261                 unsigned long tmp;
262
263                 if (!access_ok(VERIFY_WRITE, (unsigned *) data, NR_PTREGS << 2)) {
264                         ret = -EIO;
265                         break;
266                 }
267
268                 for (i = 0; i < NR_PTREGS << 2; i += 4) {
269                         tmp = get_stack_long(child, ptrace_regid_to_frame[i]);
270                         __put_user(tmp, (unsigned long *) data);
271                         data += sizeof(tmp);
272                 }
273                 ret = 0;
274                 break;
275         }
276
277         case PTRACE_SETREGS: { /* Set all gp regs in the child. */
278                 unsigned long tmp;
279
280                 if (!access_ok(VERIFY_READ, (unsigned long *)data,
281                                sizeof(struct pt_regs))) {
282                         ret = -EIO;
283                         break;
284                 }
285
286                 for (i = 0; i < NR_PTREGS << 2; i += 4) {
287                         __get_user(tmp, (unsigned long *) data);
288                         put_stack_long(child, ptrace_regid_to_frame[i], tmp);
289                         data += sizeof(tmp);
290                 }
291                 ret = 0;
292                 break;
293         }
294
295         case PTRACE_GETFPREGS: { /* Get the child FPU state. */
296                 if (is_using_fpu(child)) {
297                         unlazy_fpu(child);
298                         fpu_state = child->thread.fpu_state;
299                 } else {
300                         memset(&fpu_state, 0, sizeof(fpu_state));
301                 }
302
303                 ret = -EIO;
304                 if (copy_to_user((void *) data, &fpu_state,
305                                  sizeof(fpu_state)) == 0)
306                         ret = 0;
307                 break;
308         }
309
310         case PTRACE_SETFPREGS: { /* Set the child FPU state. */
311                 ret = -EFAULT;
312                 if (copy_from_user(&fpu_state, (const void *) data,
313                                    sizeof(fpu_state)) == 0) {
314                         fpu_kill_state(child);
315                         child->thread.fpu_state = fpu_state;
316                         set_using_fpu(child);
317                         ret = 0;
318                 }
319                 break;
320         }
321
322         case PTRACE_SETOPTIONS: {
323                 if (data & PTRACE_O_TRACESYSGOOD)
324                         child->ptrace |= PT_TRACESYSGOOD;
325                 else
326                         child->ptrace &= ~PT_TRACESYSGOOD;
327                 ret = 0;
328                 break;
329         }
330
331         default:
332                 ret = -EIO;
333                 break;
334         }
335
336         return ret;
337 }
338
339 /*
340  * notification of system call entry/exit
341  * - triggered by current->work.syscall_trace
342  */
343 asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
344 {
345 #if 0
346         /* just in case... */
347         printk(KERN_DEBUG "[%d] syscall_%lu(%lx,%lx,%lx,%lx) = %lx\n",
348                current->pid,
349                regs->orig_d0,
350                regs->a0,
351                regs->d1,
352                regs->a3,
353                regs->a2,
354                regs->d0);
355         return;
356 #endif
357
358         if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
359             !test_thread_flag(TIF_SINGLESTEP))
360                 return;
361         if (!(current->ptrace & PT_PTRACED))
362                 return;
363
364         /* the 0x80 provides a way for the tracing parent to distinguish
365            between a syscall stop and SIGTRAP delivery */
366         ptrace_notify(SIGTRAP |
367                       ((current->ptrace & PT_TRACESYSGOOD) &&
368                        !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
369
370         /*
371          * this isn't the same as continuing with a signal, but it will do
372          * for normal use.  strace only continues with a signal if the
373          * stopping signal is not SIGTRAP.  -brl
374          */
375         if (current->exit_code) {
376                 send_sig(current->exit_code, current, 1);
377                 current->exit_code = 0;
378         }
379 }