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), 0);
161 return (copied == sizeof(int)) ? 0 : -EIO;
162}
163
164static inline int
165write_int(struct task_struct *task, unsigned long addr, int data)
166{
167 int copied = access_process_vm(task, addr, &data, sizeof(int), 1);
168 return (copied == sizeof(int)) ? 0 : -EIO;
169}
170
171
172
173
174int
175ptrace_set_bpt(struct task_struct * child)
176{
177 int displ, i, res, reg_b, nsaved = 0;
178 unsigned int insn, op_code;
179 unsigned long pc;
180
181 pc = get_reg(child, REG_PC);
182 res = read_int(child, pc, (int *) &insn);
183 if (res < 0)
184 return res;
185
186 op_code = insn >> 26;
187 if (op_code >= 0x30) {
188
189
190
191
192
193
194
195
196 displ = ((s32)(insn << 11)) >> 9;
197 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
198 if (displ)
199 task_thread_info(child)->bpt_addr[nsaved++]
200 = pc + 4 + displ;
201 DBG(DBG_BPT, ("execing branch\n"));
202 } else if (op_code == 0x1a) {
203 reg_b = (insn >> 16) & 0x1f;
204 task_thread_info(child)->bpt_addr[nsaved++] = get_reg(child, reg_b);
205 DBG(DBG_BPT, ("execing jump\n"));
206 } else {
207 task_thread_info(child)->bpt_addr[nsaved++] = pc + 4;
208 DBG(DBG_BPT, ("execing normal insn\n"));
209 }
210
211
212 for (i = 0; i < nsaved; ++i) {
213 res = read_int(child, task_thread_info(child)->bpt_addr[i],
214 (int *) &insn);
215 if (res < 0)
216 return res;
217 task_thread_info(child)->bpt_insn[i] = insn;
218 DBG(DBG_BPT, (" -> next_pc=%lx\n",
219 task_thread_info(child)->bpt_addr[i]));
220 res = write_int(child, task_thread_info(child)->bpt_addr[i],
221 BREAKINST);
222 if (res < 0)
223 return res;
224 }
225 task_thread_info(child)->bpt_nsaved = nsaved;
226 return 0;
227}
228
229
230
231
232
233int
234ptrace_cancel_bpt(struct task_struct * child)
235{
236 int i, nsaved = task_thread_info(child)->bpt_nsaved;
237
238 task_thread_info(child)->bpt_nsaved = 0;
239
240 if (nsaved > 2) {
241 printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
242 nsaved = 2;
243 }
244
245 for (i = 0; i < nsaved; ++i) {
246 write_int(child, task_thread_info(child)->bpt_addr[i],
247 task_thread_info(child)->bpt_insn[i]);
248 }
249 return (nsaved != 0);
250}
251
252void user_enable_single_step(struct task_struct *child)
253{
254
255 task_thread_info(child)->bpt_nsaved = -1;
256}
257
258void user_disable_single_step(struct task_struct *child)
259{
260 ptrace_cancel_bpt(child);
261}
262
263
264
265
266
267
268void ptrace_disable(struct task_struct *child)
269{
270 user_disable_single_step(child);
271}
272
273long arch_ptrace(struct task_struct *child, long request,
274 unsigned long addr, unsigned long data)
275{
276 unsigned long tmp;
277 size_t copied;
278 long ret;
279
280 switch (request) {
281
282 case PTRACE_PEEKTEXT:
283 case PTRACE_PEEKDATA:
284 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
285 ret = -EIO;
286 if (copied != sizeof(tmp))
287 break;
288
289 force_successful_syscall_return();
290 ret = tmp;
291 break;
292
293
294 case PTRACE_PEEKUSR:
295 force_successful_syscall_return();
296 ret = get_reg(child, addr);
297 DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret));
298 break;
299
300
301 case PTRACE_POKETEXT:
302 case PTRACE_POKEDATA:
303 ret = generic_ptrace_pokedata(child, addr, data);
304 break;
305
306 case PTRACE_POKEUSR:
307 DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));
308 ret = put_reg(child, addr, data);
309 break;
310 default:
311 ret = ptrace_request(child, request, addr, data);
312 break;
313 }
314 return ret;
315}
316
317asmlinkage unsigned long syscall_trace_enter(void)
318{
319 unsigned long ret = 0;
320 struct pt_regs *regs = current_pt_regs();
321 if (test_thread_flag(TIF_SYSCALL_TRACE) &&
322 tracehook_report_syscall_entry(current_pt_regs()))
323 ret = -1UL;
324 audit_syscall_entry(AUDIT_ARCH_ALPHA, regs->r0, regs->r16, regs->r17, regs->r18, regs->r19);
325 return ret ?: current_pt_regs()->r0;
326}
327
328asmlinkage void
329syscall_trace_leave(void)
330{
331 audit_syscall_exit(current_pt_regs());
332 if (test_thread_flag(TIF_SYSCALL_TRACE))
333 tracehook_report_syscall_exit(current_pt_regs(), 0);
334}
335