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