Merge branch 'setlocalversion-speedup' into kbuild/rc-fixes
[sfrench/cifs-2.6.git] / arch / um / kernel / ptrace.c
1 /*
2  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/audit.h"
7 #include "linux/ptrace.h"
8 #include "linux/sched.h"
9 #include "asm/uaccess.h"
10 #ifdef CONFIG_PROC_MM
11 #include "proc_mm.h"
12 #endif
13 #include "skas_ptrace.h"
14
15
16
17 void user_enable_single_step(struct task_struct *child)
18 {
19         child->ptrace |= PT_DTRACE;
20         child->thread.singlestep_syscall = 0;
21
22 #ifdef SUBARCH_SET_SINGLESTEPPING
23         SUBARCH_SET_SINGLESTEPPING(child, 1);
24 #endif
25 }
26
27 void user_disable_single_step(struct task_struct *child)
28 {
29         child->ptrace &= ~PT_DTRACE;
30         child->thread.singlestep_syscall = 0;
31
32 #ifdef SUBARCH_SET_SINGLESTEPPING
33         SUBARCH_SET_SINGLESTEPPING(child, 0);
34 #endif
35 }
36
37 /*
38  * Called by kernel/ptrace.c when detaching..
39  */
40 void ptrace_disable(struct task_struct *child)
41 {
42         user_disable_single_step(child);
43 }
44
45 extern int peek_user(struct task_struct * child, long addr, long data);
46 extern int poke_user(struct task_struct * child, long addr, long data);
47
48 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
49 {
50         int i, ret;
51         unsigned long __user *p = (void __user *)(unsigned long)data;
52
53         switch (request) {
54         /* read word at location addr. */
55         case PTRACE_PEEKTEXT:
56         case PTRACE_PEEKDATA:
57                 ret = generic_ptrace_peekdata(child, addr, data);
58                 break;
59
60         /* read the word at location addr in the USER area. */
61         case PTRACE_PEEKUSR:
62                 ret = peek_user(child, addr, data);
63                 break;
64
65         /* write the word at location addr. */
66         case PTRACE_POKETEXT:
67         case PTRACE_POKEDATA:
68                 ret = generic_ptrace_pokedata(child, addr, data);
69                 break;
70
71         /* write the word at location addr in the USER area */
72         case PTRACE_POKEUSR:
73                 ret = poke_user(child, addr, data);
74                 break;
75
76         case PTRACE_SYSEMU:
77         case PTRACE_SYSEMU_SINGLESTEP:
78                 ret = -EIO;
79                 break;
80
81 #ifdef PTRACE_GETREGS
82         case PTRACE_GETREGS: { /* Get all gp regs from the child. */
83                 if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
84                         ret = -EIO;
85                         break;
86                 }
87                 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
88                         __put_user(getreg(child, i), p);
89                         p++;
90                 }
91                 ret = 0;
92                 break;
93         }
94 #endif
95 #ifdef PTRACE_SETREGS
96         case PTRACE_SETREGS: { /* Set all gp regs in the child. */
97                 unsigned long tmp = 0;
98                 if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
99                         ret = -EIO;
100                         break;
101                 }
102                 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
103                         __get_user(tmp, p);
104                         putreg(child, i, tmp);
105                         p++;
106                 }
107                 ret = 0;
108                 break;
109         }
110 #endif
111 #ifdef PTRACE_GETFPREGS
112         case PTRACE_GETFPREGS: /* Get the child FPU state. */
113                 ret = get_fpregs((struct user_i387_struct __user *) data,
114                                  child);
115                 break;
116 #endif
117 #ifdef PTRACE_SETFPREGS
118         case PTRACE_SETFPREGS: /* Set the child FPU state. */
119                 ret = set_fpregs((struct user_i387_struct __user *) data,
120                                  child);
121                 break;
122 #endif
123         case PTRACE_GET_THREAD_AREA:
124                 ret = ptrace_get_thread_area(child, addr,
125                                              (struct user_desc __user *) data);
126                 break;
127
128         case PTRACE_SET_THREAD_AREA:
129                 ret = ptrace_set_thread_area(child, addr,
130                                              (struct user_desc __user *) data);
131                 break;
132
133         case PTRACE_FAULTINFO: {
134                 /*
135                  * Take the info from thread->arch->faultinfo,
136                  * but transfer max. sizeof(struct ptrace_faultinfo).
137                  * On i386, ptrace_faultinfo is smaller!
138                  */
139                 ret = copy_to_user(p, &child->thread.arch.faultinfo,
140                                    sizeof(struct ptrace_faultinfo));
141                 break;
142         }
143
144 #ifdef PTRACE_LDT
145         case PTRACE_LDT: {
146                 struct ptrace_ldt ldt;
147
148                 if (copy_from_user(&ldt, p, sizeof(ldt))) {
149                         ret = -EIO;
150                         break;
151                 }
152
153                 /*
154                  * This one is confusing, so just punt and return -EIO for
155                  * now
156                  */
157                 ret = -EIO;
158                 break;
159         }
160 #endif
161 #ifdef CONFIG_PROC_MM
162         case PTRACE_SWITCH_MM: {
163                 struct mm_struct *old = child->mm;
164                 struct mm_struct *new = proc_mm_get_mm(data);
165
166                 if (IS_ERR(new)) {
167                         ret = PTR_ERR(new);
168                         break;
169                 }
170
171                 atomic_inc(&new->mm_users);
172                 child->mm = new;
173                 child->active_mm = new;
174                 mmput(old);
175                 ret = 0;
176                 break;
177         }
178 #endif
179 #ifdef PTRACE_ARCH_PRCTL
180         case PTRACE_ARCH_PRCTL:
181                 /* XXX Calls ptrace on the host - needs some SMP thinking */
182                 ret = arch_prctl(child, data, (void *) addr);
183                 break;
184 #endif
185         default:
186                 ret = ptrace_request(child, request, addr, data);
187                 if (ret == -EIO)
188                         ret = subarch_ptrace(child, request, addr, data);
189                 break;
190         }
191
192         return ret;
193 }
194
195 static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,
196                   int error_code)
197 {
198         struct siginfo info;
199
200         memset(&info, 0, sizeof(info));
201         info.si_signo = SIGTRAP;
202         info.si_code = TRAP_BRKPT;
203
204         /* User-mode eip? */
205         info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
206
207         /* Send us the fake SIGTRAP */
208         force_sig_info(SIGTRAP, &info, tsk);
209 }
210
211 /*
212  * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
213  * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
214  */
215 void syscall_trace(struct uml_pt_regs *regs, int entryexit)
216 {
217         int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
218         int tracesysgood;
219
220         if (unlikely(current->audit_context)) {
221                 if (!entryexit)
222                         audit_syscall_entry(HOST_AUDIT_ARCH,
223                                             UPT_SYSCALL_NR(regs),
224                                             UPT_SYSCALL_ARG1(regs),
225                                             UPT_SYSCALL_ARG2(regs),
226                                             UPT_SYSCALL_ARG3(regs),
227                                             UPT_SYSCALL_ARG4(regs));
228                 else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
229                                         UPT_SYSCALL_RET(regs));
230         }
231
232         /* Fake a debug trap */
233         if (is_singlestep)
234                 send_sigtrap(current, regs, 0);
235
236         if (!test_thread_flag(TIF_SYSCALL_TRACE))
237                 return;
238
239         if (!(current->ptrace & PT_PTRACED))
240                 return;
241
242         /*
243          * the 0x80 provides a way for the tracing parent to distinguish
244          * between a syscall stop and SIGTRAP delivery
245          */
246         tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
247         ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
248
249         if (entryexit) /* force do_signal() --> is_syscall() */
250                 set_thread_flag(TIF_SIGPENDING);
251
252         /*
253          * this isn't the same as continuing with a signal, but it will do
254          * for normal use.  strace only continues with a signal if the
255          * stopping signal is not SIGTRAP.  -brl
256          */
257         if (current->exit_code) {
258                 send_sig(current->exit_code, current, 1);
259                 current->exit_code = 0;
260         }
261 }