brcmfmac: don't include linux/unaligned/access_ok.h
[cascardo/linux.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 <linux/tracehook.h>
10 #include <asm/uaccess.h>
11 #include <skas_ptrace.h>
12
13
14
15 void user_enable_single_step(struct task_struct *child)
16 {
17         child->ptrace |= PT_DTRACE;
18         child->thread.singlestep_syscall = 0;
19
20 #ifdef SUBARCH_SET_SINGLESTEPPING
21         SUBARCH_SET_SINGLESTEPPING(child, 1);
22 #endif
23 }
24
25 void user_disable_single_step(struct task_struct *child)
26 {
27         child->ptrace &= ~PT_DTRACE;
28         child->thread.singlestep_syscall = 0;
29
30 #ifdef SUBARCH_SET_SINGLESTEPPING
31         SUBARCH_SET_SINGLESTEPPING(child, 0);
32 #endif
33 }
34
35 /*
36  * Called by kernel/ptrace.c when detaching..
37  */
38 void ptrace_disable(struct task_struct *child)
39 {
40         user_disable_single_step(child);
41 }
42
43 extern int peek_user(struct task_struct * child, long addr, long data);
44 extern int poke_user(struct task_struct * child, long addr, long data);
45
46 long arch_ptrace(struct task_struct *child, long request,
47                  unsigned long addr, unsigned long data)
48 {
49         int i, ret;
50         unsigned long __user *p = (void __user *)data;
51         void __user *vp = p;
52
53         switch (request) {
54         /* read the word at location addr in the USER area. */
55         case PTRACE_PEEKUSR:
56                 ret = peek_user(child, addr, data);
57                 break;
58
59         /* write the word at location addr in the USER area */
60         case PTRACE_POKEUSR:
61                 ret = poke_user(child, addr, data);
62                 break;
63
64         case PTRACE_SYSEMU:
65         case PTRACE_SYSEMU_SINGLESTEP:
66                 ret = -EIO;
67                 break;
68
69 #ifdef PTRACE_GETREGS
70         case PTRACE_GETREGS: { /* Get all gp regs from the child. */
71                 if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
72                         ret = -EIO;
73                         break;
74                 }
75                 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
76                         __put_user(getreg(child, i), p);
77                         p++;
78                 }
79                 ret = 0;
80                 break;
81         }
82 #endif
83 #ifdef PTRACE_SETREGS
84         case PTRACE_SETREGS: { /* Set all gp regs in the child. */
85                 unsigned long tmp = 0;
86                 if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
87                         ret = -EIO;
88                         break;
89                 }
90                 for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
91                         __get_user(tmp, p);
92                         putreg(child, i, tmp);
93                         p++;
94                 }
95                 ret = 0;
96                 break;
97         }
98 #endif
99         case PTRACE_GET_THREAD_AREA:
100                 ret = ptrace_get_thread_area(child, addr, vp);
101                 break;
102
103         case PTRACE_SET_THREAD_AREA:
104                 ret = ptrace_set_thread_area(child, addr, vp);
105                 break;
106
107         case PTRACE_FAULTINFO: {
108                 /*
109                  * Take the info from thread->arch->faultinfo,
110                  * but transfer max. sizeof(struct ptrace_faultinfo).
111                  * On i386, ptrace_faultinfo is smaller!
112                  */
113                 ret = copy_to_user(p, &child->thread.arch.faultinfo,
114                                    sizeof(struct ptrace_faultinfo)) ?
115                         -EIO : 0;
116                 break;
117         }
118
119 #ifdef PTRACE_LDT
120         case PTRACE_LDT: {
121                 struct ptrace_ldt ldt;
122
123                 if (copy_from_user(&ldt, p, sizeof(ldt))) {
124                         ret = -EIO;
125                         break;
126                 }
127
128                 /*
129                  * This one is confusing, so just punt and return -EIO for
130                  * now
131                  */
132                 ret = -EIO;
133                 break;
134         }
135 #endif
136         default:
137                 ret = ptrace_request(child, request, addr, data);
138                 if (ret == -EIO)
139                         ret = subarch_ptrace(child, request, addr, data);
140                 break;
141         }
142
143         return ret;
144 }
145
146 static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,
147                   int error_code)
148 {
149         struct siginfo info;
150
151         memset(&info, 0, sizeof(info));
152         info.si_signo = SIGTRAP;
153         info.si_code = TRAP_BRKPT;
154
155         /* User-mode eip? */
156         info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
157
158         /* Send us the fake SIGTRAP */
159         force_sig_info(SIGTRAP, &info, tsk);
160 }
161
162 /*
163  * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
164  * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
165  */
166 void syscall_trace_enter(struct pt_regs *regs)
167 {
168         audit_syscall_entry(HOST_AUDIT_ARCH,
169                             UPT_SYSCALL_NR(&regs->regs),
170                             UPT_SYSCALL_ARG1(&regs->regs),
171                             UPT_SYSCALL_ARG2(&regs->regs),
172                             UPT_SYSCALL_ARG3(&regs->regs),
173                             UPT_SYSCALL_ARG4(&regs->regs));
174
175         if (!test_thread_flag(TIF_SYSCALL_TRACE))
176                 return;
177
178         tracehook_report_syscall_entry(regs);
179 }
180
181 void syscall_trace_leave(struct pt_regs *regs)
182 {
183         int ptraced = current->ptrace;
184
185         audit_syscall_exit(regs);
186
187         /* Fake a debug trap */
188         if (ptraced & PT_DTRACE)
189                 send_sigtrap(current, &regs->regs, 0);
190
191         if (!test_thread_flag(TIF_SYSCALL_TRACE))
192                 return;
193
194         tracehook_report_syscall_exit(regs, 0);
195         /* force do_signal() --> is_syscall() */
196         if (ptraced & PT_PTRACED)
197                 set_thread_flag(TIF_SIGPENDING);
198 }