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