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