xref: /openbmc/linux/arch/xtensa/kernel/ptrace.c (revision 22246614)
1 // TODO some minor issues
2 /*
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.  See the file "COPYING" in the main directory of this archive
5  * for more details.
6  *
7  * Copyright (C) 2001 - 2007  Tensilica Inc.
8  *
9  * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
10  * Chris Zankel <chris@zankel.net>
11  * Scott Foehner<sfoehner@yahoo.com>,
12  * Kevin Chea
13  * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
14  */
15 
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/mm.h>
19 #include <linux/errno.h>
20 #include <linux/ptrace.h>
21 #include <linux/smp.h>
22 #include <linux/security.h>
23 #include <linux/signal.h>
24 
25 #include <asm/pgtable.h>
26 #include <asm/page.h>
27 #include <asm/system.h>
28 #include <asm/uaccess.h>
29 #include <asm/ptrace.h>
30 #include <asm/elf.h>
31 #include <asm/coprocessor.h>
32 
33 /*
34  * Called by kernel/ptrace.c when detaching to disable single stepping.
35  */
36 
37 void ptrace_disable(struct task_struct *child)
38 {
39 	/* Nothing to do.. */
40 }
41 
42 int ptrace_getregs(struct task_struct *child, void __user *uregs)
43 {
44 	struct pt_regs *regs = task_pt_regs(child);
45 	xtensa_gregset_t __user *gregset = uregs;
46 	unsigned long wm = regs->wmask;
47 	unsigned long wb = regs->windowbase;
48 	int live, i;
49 
50 	if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
51 		return -EIO;
52 
53 	__put_user(regs->pc, &gregset->pc);
54 	__put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
55 	__put_user(regs->lbeg, &gregset->lbeg);
56 	__put_user(regs->lend, &gregset->lend);
57 	__put_user(regs->lcount, &gregset->lcount);
58 	__put_user(regs->windowstart, &gregset->windowstart);
59 	__put_user(regs->windowbase, &gregset->windowbase);
60 
61 	live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
62 
63 	for (i = 0; i < live; i++)
64 		__put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
65 	for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++)
66 		__put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
67 
68 	return 0;
69 }
70 
71 int ptrace_setregs(struct task_struct *child, void __user *uregs)
72 {
73 	struct pt_regs *regs = task_pt_regs(child);
74 	xtensa_gregset_t *gregset = uregs;
75 	const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
76 	unsigned long ps;
77 	unsigned long wb;
78 
79 	if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
80 		return -EIO;
81 
82 	__get_user(regs->pc, &gregset->pc);
83 	__get_user(ps, &gregset->ps);
84 	__get_user(regs->lbeg, &gregset->lbeg);
85 	__get_user(regs->lend, &gregset->lend);
86 	__get_user(regs->lcount, &gregset->lcount);
87 	__get_user(regs->windowstart, &gregset->windowstart);
88 	__get_user(wb, &gregset->windowbase);
89 
90 	regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT);
91 
92 	if (wb >= XCHAL_NUM_AREGS / 4)
93 		return -EFAULT;
94 
95 	regs->windowbase = wb;
96 
97 	if (wb != 0 &&  __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
98 					 gregset->a, wb * 16))
99 		return -EFAULT;
100 
101 	if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16))
102 		return -EFAULT;
103 
104 	return 0;
105 }
106 
107 
108 int ptrace_getxregs(struct task_struct *child, void __user *uregs)
109 {
110 	struct pt_regs *regs = task_pt_regs(child);
111 	struct thread_info *ti = task_thread_info(child);
112 	elf_xtregs_t __user *xtregs = uregs;
113 	int ret = 0;
114 
115 	if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t)))
116 		return -EIO;
117 
118 #if XTENSA_HAVE_COPROCESSORS
119 	/* Flush all coprocessor registers to memory. */
120 	coprocessor_flush_all(ti);
121 	ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp,
122 			      sizeof(xtregs_coprocessor_t));
123 #endif
124 	ret |= __copy_to_user(&xtregs->opt, &regs->xtregs_opt,
125 			      sizeof(xtregs->opt));
126 	ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user,
127 			      sizeof(xtregs->user));
128 
129 	return ret ? -EFAULT : 0;
130 }
131 
132 int ptrace_setxregs(struct task_struct *child, void __user *uregs)
133 {
134 	struct thread_info *ti = task_thread_info(child);
135 	struct pt_regs *regs = task_pt_regs(child);
136 	elf_xtregs_t *xtregs = uregs;
137 	int ret = 0;
138 
139 #if XTENSA_HAVE_COPROCESSORS
140 	/* Flush all coprocessors before we overwrite them. */
141 	coprocessor_flush_all(ti);
142 	coprocessor_release_all(ti);
143 
144 	ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0,
145 				sizeof(xtregs_coprocessor_t));
146 #endif
147 	ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt,
148 				sizeof(xtregs->opt));
149 	ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user,
150 				sizeof(xtregs->user));
151 
152 	return ret ? -EFAULT : 0;
153 }
154 
155 int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret)
156 {
157 	struct pt_regs *regs;
158 	unsigned long tmp;
159 
160 	regs = task_pt_regs(child);
161 	tmp = 0;  /* Default return value. */
162 
163 	switch(regno) {
164 
165 		case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
166 			tmp = regs->areg[regno - REG_AR_BASE];
167 			break;
168 
169 		case REG_A_BASE ... REG_A_BASE + 15:
170 			tmp = regs->areg[regno - REG_A_BASE];
171 			break;
172 
173 		case REG_PC:
174 			tmp = regs->pc;
175 			break;
176 
177 		case REG_PS:
178 			/* Note:  PS.EXCM is not set while user task is running;
179 			 * its being set in regs is for exception handling
180 			 * convenience.  */
181 			tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
182 			break;
183 
184 		case REG_WB:
185 			break;		/* tmp = 0 */
186 
187 		case REG_WS:
188 		{
189 			unsigned long wb = regs->windowbase;
190 			unsigned long ws = regs->windowstart;
191 			tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1);
192 			break;
193 		}
194 		case REG_LBEG:
195 			tmp = regs->lbeg;
196 			break;
197 
198 		case REG_LEND:
199 			tmp = regs->lend;
200 			break;
201 
202 		case REG_LCOUNT:
203 			tmp = regs->lcount;
204 			break;
205 
206 		case REG_SAR:
207 			tmp = regs->sar;
208 			break;
209 
210 		case SYSCALL_NR:
211 			tmp = regs->syscall;
212 			break;
213 
214 		default:
215 			return -EIO;
216 	}
217 	return put_user(tmp, ret);
218 }
219 
220 int ptrace_pokeusr(struct task_struct *child, long regno, long val)
221 {
222 	struct pt_regs *regs;
223 	regs = task_pt_regs(child);
224 
225 	switch (regno) {
226 		case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
227 			regs->areg[regno - REG_AR_BASE] = val;
228 			break;
229 
230 		case REG_A_BASE ... REG_A_BASE + 15:
231 			regs->areg[regno - REG_A_BASE] = val;
232 			break;
233 
234 		case REG_PC:
235 			regs->pc = val;
236 			break;
237 
238 		case SYSCALL_NR:
239 			regs->syscall = val;
240 			break;
241 
242 		default:
243 			return -EIO;
244 	}
245 	return 0;
246 }
247 
248 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
249 {
250 	int ret = -EPERM;
251 
252 	switch (request) {
253 	case PTRACE_PEEKTEXT:	/* read word at location addr. */
254 	case PTRACE_PEEKDATA:
255 		ret = generic_ptrace_peekdata(child, addr, data);
256 		break;
257 
258 	case PTRACE_PEEKUSR:	/* read register specified by addr. */
259 		ret = ptrace_peekusr(child, addr, (void __user *) data);
260 		break;
261 
262 	case PTRACE_POKETEXT:	/* write the word at location addr. */
263 	case PTRACE_POKEDATA:
264 		ret = generic_ptrace_pokedata(child, addr, data);
265 		break;
266 
267 	case PTRACE_POKEUSR:	/* write register specified by addr. */
268 		ret = ptrace_pokeusr(child, addr, data);
269 		break;
270 
271 	/* continue and stop at next (return from) syscall */
272 
273 	case PTRACE_SYSCALL:
274 	case PTRACE_CONT: /* restart after signal. */
275 	{
276 		ret = -EIO;
277 		if (!valid_signal(data))
278 			break;
279 		if (request == PTRACE_SYSCALL)
280 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
281 		else
282 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
283 		child->exit_code = data;
284 		/* Make sure the single step bit is not set. */
285 		child->ptrace &= ~PT_SINGLESTEP;
286 		wake_up_process(child);
287 		ret = 0;
288 		break;
289 	}
290 
291 	/*
292 	 * make the child exit.  Best I can do is send it a sigkill.
293 	 * perhaps it should be put in the status that it wants to
294 	 * exit.
295 	 */
296 	case PTRACE_KILL:
297 		ret = 0;
298 		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
299 			break;
300 		child->exit_code = SIGKILL;
301 		child->ptrace &= ~PT_SINGLESTEP;
302 		wake_up_process(child);
303 		break;
304 
305 	case PTRACE_SINGLESTEP:
306 		ret = -EIO;
307 		if (!valid_signal(data))
308 			break;
309 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
310 		child->ptrace |= PT_SINGLESTEP;
311 		child->exit_code = data;
312 		wake_up_process(child);
313 		ret = 0;
314 		break;
315 
316 	case PTRACE_GETREGS:
317 		ret = ptrace_getregs(child, (void __user *) data);
318 		break;
319 
320 	case PTRACE_SETREGS:
321 		ret = ptrace_setregs(child, (void __user *) data);
322 		break;
323 
324 	case PTRACE_GETXTREGS:
325 		ret = ptrace_getxregs(child, (void __user *) data);
326 		break;
327 
328 	case PTRACE_SETXTREGS:
329 		ret = ptrace_setxregs(child, (void __user *) data);
330 		break;
331 
332 	default:
333 		ret = ptrace_request(child, request, addr, data);
334 		break;
335 	}
336 
337 	return ret;
338 }
339 
340 void do_syscall_trace(void)
341 {
342 	/*
343 	 * The 0x80 provides a way for the tracing parent to distinguish
344 	 * between a syscall stop and SIGTRAP delivery
345 	 */
346 	ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
347 
348 	/*
349 	 * this isn't the same as continuing with a signal, but it will do
350 	 * for normal use.  strace only continues with a signal if the
351 	 * stopping signal is not SIGTRAP.  -brl
352 	 */
353 	if (current->exit_code) {
354 		send_sig(current->exit_code, current, 1);
355 		current->exit_code = 0;
356 	}
357 }
358 
359 void do_syscall_trace_enter(struct pt_regs *regs)
360 {
361 	if (test_thread_flag(TIF_SYSCALL_TRACE)
362 			&& (current->ptrace & PT_PTRACED))
363 		do_syscall_trace();
364 
365 #if 0
366 	if (unlikely(current->audit_context))
367 		audit_syscall_entry(current, AUDIT_ARCH_XTENSA..);
368 #endif
369 }
370 
371 void do_syscall_trace_leave(struct pt_regs *regs)
372 {
373 	if ((test_thread_flag(TIF_SYSCALL_TRACE))
374 			&& (current->ptrace & PT_PTRACED))
375 		do_syscall_trace();
376 }
377 
378