arch/tile: provide PT_FLAGS_COMPAT value in pt_regs
[profile/ivi/kernel-adaptation-intel-automotive.git] / arch / tile / kernel / ptrace.c
1 /*
2  * Copyright 2010 Tilera Corporation. All Rights Reserved.
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful, but
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  *   NON INFRINGEMENT.  See the GNU General Public License for
12  *   more details.
13  *
14  * Copied from i386: Ross Biro 1/23/92
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/ptrace.h>
19 #include <linux/kprobes.h>
20 #include <linux/compat.h>
21 #include <linux/uaccess.h>
22 #include <asm/traps.h>
23
24 void user_enable_single_step(struct task_struct *child)
25 {
26         set_tsk_thread_flag(child, TIF_SINGLESTEP);
27 }
28
29 void user_disable_single_step(struct task_struct *child)
30 {
31         clear_tsk_thread_flag(child, TIF_SINGLESTEP);
32 }
33
34 /*
35  * Called by kernel/ptrace.c when detaching..
36  */
37 void ptrace_disable(struct task_struct *child)
38 {
39         clear_tsk_thread_flag(child, TIF_SINGLESTEP);
40
41         /*
42          * These two are currently unused, but will be set by arch_ptrace()
43          * and used in the syscall assembly when we do support them.
44          */
45         clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
46 }
47
48 /*
49  * Get registers from task and ready the result for userspace.
50  * Note that we localize the API issues to getregs() and putregs() at
51  * some cost in performance, e.g. we need a full pt_regs copy for
52  * PEEKUSR, and two copies for POKEUSR.  But in general we expect
53  * GETREGS/PUTREGS to be the API of choice anyway.
54  */
55 static char *getregs(struct task_struct *child, struct pt_regs *uregs)
56 {
57         *uregs = *task_pt_regs(child);
58
59         /* Set up flags ABI bits. */
60         uregs->flags = 0;
61 #ifdef CONFIG_COMPAT
62         if (task_thread_info(child)->status & TS_COMPAT)
63                 uregs->flags |= PT_FLAGS_COMPAT;
64 #endif
65
66         return (char *)uregs;
67 }
68
69 /* Put registers back to task. */
70 static void putregs(struct task_struct *child, struct pt_regs *uregs)
71 {
72         struct pt_regs *regs = task_pt_regs(child);
73
74         /* Don't allow overwriting the kernel-internal flags word. */
75         uregs->flags = regs->flags;
76
77         /* Only allow setting the ICS bit in the ex1 word. */
78         uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1));
79
80         *regs = *uregs;
81 }
82
83 long arch_ptrace(struct task_struct *child, long request,
84                  unsigned long addr, unsigned long data)
85 {
86         unsigned long __user *datap = (long __user __force *)data;
87         unsigned long tmp;
88         long ret = -EIO;
89         char *childreg;
90         struct pt_regs copyregs;
91
92         switch (request) {
93
94         case PTRACE_PEEKUSR:  /* Read register from pt_regs. */
95                 if (addr >= PTREGS_SIZE)
96                         break;
97                 childreg = getregs(child, &copyregs) + addr;
98 #ifdef CONFIG_COMPAT
99                 if (is_compat_task()) {
100                         if (addr & (sizeof(compat_long_t)-1))
101                                 break;
102                         ret = put_user(*(compat_long_t *)childreg,
103                                        (compat_long_t __user *)datap);
104                 } else
105 #endif
106                 {
107                         if (addr & (sizeof(long)-1))
108                                 break;
109                         ret = put_user(*(long *)childreg, datap);
110                 }
111                 break;
112
113         case PTRACE_POKEUSR:  /* Write register in pt_regs. */
114                 if (addr >= PTREGS_SIZE)
115                         break;
116                 childreg = getregs(child, &copyregs) + addr;
117 #ifdef CONFIG_COMPAT
118                 if (is_compat_task()) {
119                         if (addr & (sizeof(compat_long_t)-1))
120                                 break;
121                         *(compat_long_t *)childreg = data;
122                 } else
123 #endif
124                 {
125                         if (addr & (sizeof(long)-1))
126                                 break;
127                         *(long *)childreg = data;
128                 }
129                 putregs(child, &copyregs);
130                 ret = 0;
131                 break;
132
133         case PTRACE_GETREGS:  /* Get all registers from the child. */
134                 if (copy_to_user(datap, getregs(child, &copyregs),
135                                  sizeof(struct pt_regs)) == 0) {
136                         ret = 0;
137                 }
138                 break;
139
140         case PTRACE_SETREGS:  /* Set all registers in the child. */
141                 if (copy_from_user(&copyregs, datap,
142                                    sizeof(struct pt_regs)) == 0) {
143                         putregs(child, &copyregs);
144                         ret = 0;
145                 }
146                 break;
147
148         case PTRACE_GETFPREGS:  /* Get the child FPU state. */
149         case PTRACE_SETFPREGS:  /* Set the child FPU state. */
150                 break;
151
152         case PTRACE_SETOPTIONS:
153                 /* Support TILE-specific ptrace options. */
154                 child->ptrace &= ~PT_TRACE_MASK_TILE;
155                 tmp = data & PTRACE_O_MASK_TILE;
156                 data &= ~PTRACE_O_MASK_TILE;
157                 ret = ptrace_request(child, request, addr, data);
158                 if (tmp & PTRACE_O_TRACEMIGRATE)
159                         child->ptrace |= PT_TRACE_MIGRATE;
160                 break;
161
162         default:
163 #ifdef CONFIG_COMPAT
164                 if (task_thread_info(current)->status & TS_COMPAT) {
165                         ret = compat_ptrace_request(child, request,
166                                                     addr, data);
167                         break;
168                 }
169 #endif
170                 ret = ptrace_request(child, request, addr, data);
171                 break;
172         }
173
174         return ret;
175 }
176
177 #ifdef CONFIG_COMPAT
178 /* Not used; we handle compat issues in arch_ptrace() directly. */
179 long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
180                                compat_ulong_t addr, compat_ulong_t data)
181 {
182         BUG();
183 }
184 #endif
185
186 void do_syscall_trace(void)
187 {
188         if (!test_thread_flag(TIF_SYSCALL_TRACE))
189                 return;
190
191         if (!(current->ptrace & PT_PTRACED))
192                 return;
193
194         /*
195          * The 0x80 provides a way for the tracing parent to distinguish
196          * between a syscall stop and SIGTRAP delivery
197          */
198         ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
199
200         /*
201          * this isn't the same as continuing with a signal, but it will do
202          * for normal use.  strace only continues with a signal if the
203          * stopping signal is not SIGTRAP.  -brl
204          */
205         if (current->exit_code) {
206                 send_sig(current->exit_code, current, 1);
207                 current->exit_code = 0;
208         }
209 }
210
211 void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
212 {
213         struct siginfo info;
214
215         memset(&info, 0, sizeof(info));
216         info.si_signo = SIGTRAP;
217         info.si_code  = TRAP_BRKPT;
218         info.si_addr  = (void __user *) regs->pc;
219
220         /* Send us the fakey SIGTRAP */
221         force_sig_info(SIGTRAP, &info, tsk);
222 }
223
224 /* Handle synthetic interrupt delivered only by the simulator. */
225 void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
226 {
227         send_sigtrap(current, regs, fault_num);
228 }