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