1
2
3
4
5
6
7#include <linux/kernel.h>
8#include <linux/sched.h>
9#include <linux/mm.h>
10#include <linux/smp.h>
11#include <linux/errno.h>
12#include <linux/ptrace.h>
13#include <linux/user.h>
14#include <linux/security.h>
15#include <linux/signal.h>
16
17#include <asm/uaccess.h>
18#include <asm/pgtable.h>
19#include <asm/fpu.h>
20
21#include "proto.h"
22
23#define DEBUG DBG_MEM
24#undef DEBUG
25
26#ifdef DEBUG
27enum {
28 DBG_MEM = (1<<0),
29 DBG_BPT = (1<<1),
30 DBG_MEM_ALL = (1<<2)
31};
32#define DBG(fac,args) {if ((fac) & DEBUG) printk args;}
33#else
34#define DBG(fac,args)
35#endif
36
37#define BREAKINST 0x00000080
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68enum {
69 REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64
70};
71
72#define PT_REG(reg) \
73 (PAGE_SIZE*2 - sizeof(struct pt_regs) + offsetof(struct pt_regs, reg))
74
75#define SW_REG(reg) \
76 (PAGE_SIZE*2 - sizeof(struct pt_regs) - sizeof(struct switch_stack) \
77 + offsetof(struct switch_stack, reg))
78
79static int regoff[] = {
80 PT_REG( r0), PT_REG( r1), PT_REG( r2), PT_REG( r3),
81 PT_REG( r4), PT_REG( r5), PT_REG( r6), PT_REG( r7),
82 PT_REG( r8), SW_REG( r9), SW_REG( r10), SW_REG( r11),
83 SW_REG( r12), SW_REG( r13), SW_REG( r14), SW_REG( r15),
84 PT_REG( r16), PT_REG( r17), PT_REG( r18), PT_REG( r19),
85 PT_REG( r20), PT_REG( r21), PT_REG( r22), PT_REG( r23),
86 PT_REG( r24), PT_REG( r25), PT_REG( r26), PT_REG( r27),
87 PT_REG( r28), PT_REG( gp), -1, -1,
88 SW_REG(fp[ 0]), SW_REG(fp[ 1]), SW_REG(fp[ 2]), SW_REG(fp[ 3]),
89 SW_REG(fp[ 4]), SW_REG(fp[ 5]), SW_REG(fp[ 6]), SW_REG(fp[ 7]),
90 SW_REG(fp[ 8]), SW_REG(fp[ 9]), SW_REG(fp[10]), SW_REG(fp[11]),
91 SW_REG(fp[12]), SW_REG(fp[13]), SW_REG(fp[14]), SW_REG(fp[15]),
92 SW_REG(fp[16]), SW_REG(fp[17]), SW_REG(fp[18]), SW_REG(fp[19]),
93 SW_REG(fp[20]), SW_REG(fp[21]), SW_REG(fp[22]), SW_REG(fp[23]),
94 SW_REG(fp[24]), SW_REG(fp[25]), SW_REG(fp[26]), SW_REG(fp[27]),
95 SW_REG(fp[28]), SW_REG(fp[29]), SW_REG(fp[30]), SW_REG(fp[31]),
96 PT_REG( pc)
97};
98
99static unsigned long zero;
100
101
102
103
104static unsigned long *
105get_reg_addr(struct task_struct * task, unsigned long regno)
106{
107 unsigned long *addr;
108
109 if (regno == 30) {
110 addr = &task_thread_info(task)->pcb.usp;
111 } else if (regno == 65) {
112 addr = &task_thread_info(task)->pcb.unique;
113 } else if (regno == 31 || regno > 65) {
114 zero = 0;
115 addr = &zero;
116 } else {
117 addr = task_stack_page(task) + regoff[regno];
118 }
119 return addr;
120}
121
122
123
124
125static unsigned long
126get_reg(struct task_struct * task, unsigned long regno)
127{
128
129 if (regno == 63) {
130 unsigned long fpcr = *get_reg_addr(task, regno);
131 unsigned long swcr
132 = task_thread_info(task)->ieee_state & IEEE_SW_MASK;
133 swcr = swcr_update_status(swcr, fpcr);
134 return fpcr | swcr;
135 }
136 return *get_reg_addr(task, regno);
137}
138
139
140
141
142static int
143put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
144{
145 if (regno == 63) {
146 task_thread_info(task)->ieee_state
147 = ((task_thread_info(task)->ieee_state & ~IEEE_SW_MASK)
148 | (data & IEEE_SW_MASK));
149 data = (data & FPCR_DYN_MASK) | ieee_swcr_to_fpcr(data);
150 }
151 *get_reg_addr(task, regno) = data;
152 return 0;
153}
154
155static inline int
156read_int(struct task_struct *task, unsigned long addr, int * data)
157{
158 int copied = access_process_vm(task, addr, data, sizeof(int), 0);
159 return (copied == sizeof(int)) ? 0 : -EIO;
160}
161
162static inline int
163write_int(struct task_struct *task, unsigned long addr, int data)
164{
165 int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
166 return (copied == sizeof(int)) ? 0 : -EIO;
167}
168
169
170
171
172int
173ptrace_set_bpt(struct task_struct * child)
174{
175 int displ, i, res, reg_b, nsaved = 0;
176 unsigned int insn, op_code;
177 unsigned long pc;
178
179 pc = get_reg(child, REG_PC);
180 res = read_int(child, pc, (int *) &insn);
181 if (res < 0)
182 return res;
183
184 op_code = insn >> 26;
185 if (op_code >= 0x30) {
186
187
188
189
190
191
192
193
194 displ = ((s32)(insn << 11)) >> 9;
195 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
196 if (displ)
197 task_thread_info(child)->bpt_addr[nsaved++]
198 = pc + 4 + displ;
199 DBG(DBG_BPT, ("execing branch\n"));
200 } else if (op_code == 0x1a) {
201 reg_b = (insn >> 16) & 0x1f;
202 task_thread_info(child)->bpt_addr[nsaved++] = get_reg(child, reg_b);
203 DBG(DBG_BPT, ("execing jump\n"));
204 } else {
205 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
206 DBG(DBG_BPT, ("execing normal insn\n"));
207 }
208
209
210 for (i = 0; i < nsaved; ++i) {
211 res = read_int(child, task_thread_info(child)->bpt_addr[i],
212 (int *) &insn);
213 if (res < 0)
214 return res;
215 task_thread_info(child)->bpt_insn[i] = insn;
216 DBG(DBG_BPT, (" -> next_pc=%lx\n",
217 task_thread_info(child)->bpt_addr[i]));
218 res = write_int(child, task_thread_info(child)->bpt_addr[i],
219 BREAKINST);
220 if (res < 0)
221 return res;
222 }
223 task_thread_info(child)->bpt_nsaved = nsaved;
224 return 0;
225}
226
227
228
229
230
231int
232ptrace_cancel_bpt(struct task_struct * child)
233{
234 int i, nsaved = task_thread_info(child)->bpt_nsaved;
235
236 task_thread_info(child)->bpt_nsaved = 0;
237
238 if (nsaved > 2) {
239 printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
240 nsaved = 2;
241 }
242
243 for (i = 0; i < nsaved; ++i) {
244 write_int(child, task_thread_info(child)->bpt_addr[i],
245 task_thread_info(child)->bpt_insn[i]);
246 }
247 return (nsaved != 0);
248}
249
250void user_enable_single_step(struct task_struct *child)
251{
252
253 task_thread_info(child)->bpt_nsaved = -1;
254}
255
256void user_disable_single_step(struct task_struct *child)
257{
258 ptrace_cancel_bpt(child);
259}
260
261
262
263
264
265
266void ptrace_disable(struct task_struct *child)
267{
268 user_disable_single_step(child);
269}
270
271long arch_ptrace(struct task_struct *child, long request,
272 unsigned long addr, unsigned long data)
273{
274 unsigned long tmp;
275 size_t copied;
276 long ret;
277
278 switch (request) {
279
280 case PTRACE_PEEKTEXT:
281 case PTRACE_PEEKDATA:
282 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
283 ret = -EIO;
284 if (copied != sizeof(tmp))
285 break;
286
287 force_successful_syscall_return();
288 ret = tmp;
289 break;
290
291
292 case PTRACE_PEEKUSR:
293 force_successful_syscall_return();
294 ret = get_reg(child, addr);
295 DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret));
296 break;
297
298
299 case PTRACE_POKETEXT:
300 case PTRACE_POKEDATA:
301 ret = generic_ptrace_pokedata(child, addr, data);
302 break;
303
304 case PTRACE_POKEUSR:
305 DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));
306 ret = put_reg(child, addr, data);
307 break;
308 default:
309 ret = ptrace_request(child, request, addr, data);
310 break;
311 }
312 return ret;
313}
314
315asmlinkage void
316syscall_trace(void)
317{
318 if (!test_thread_flag(TIF_SYSCALL_TRACE))
319 return;
320 if (!(current->ptrace & PT_PTRACED))
321 return;
322
323
324 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
325 ? 0x80 : 0));
326
327
328
329
330
331
332 if (current->exit_code) {
333 send_sig(current->exit_code, current, 1);
334 current->exit_code = 0;
335 }
336}
337