1/*
2 * arch/ubicom32/kernel/ptrace.c
3 *   Ubicom32 architecture ptrace implementation.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 * (C) 1994 by Hamish Macdonald
7 * Taken from linux/kernel/ptrace.c and modified for M680x0.
8 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
9 *
10 * This file is part of the Ubicom32 Linux Kernel Port.
11 *
12 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
13 * it and/or modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
18 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
20 * the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with the Ubicom32 Linux Kernel Port.  If not,
24 * see <http://www.gnu.org/licenses/>.
25 *
26 * Ubicom32 implementation derived from (with many thanks):
27 *   arch/m68knommu
28 *   arch/blackfin
29 *   arch/parisc
30 */
31
32#include <linux/module.h>
33#include <linux/kernel.h>
34#include <linux/sched.h>
35#include <linux/mm.h>
36#include <linux/smp.h>
37#include <linux/errno.h>
38#include <linux/ptrace.h>
39#include <linux/user.h>
40#include <linux/signal.h>
41#include <linux/uaccess.h>
42
43#include <asm/page.h>
44#include <asm/pgtable.h>
45#include <asm/system.h>
46#include <asm/cacheflush.h>
47#include <asm/processor.h>
48
49/*
50 * ptrace_getregs()
51 *
52 *	Get all user integer registers.
53 */
54static inline int ptrace_getregs(struct task_struct *task, void __user *uregs)
55{
56	struct pt_regs *regs = task_pt_regs(task);
57	return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
58}
59
60/*
61 * ptrace_get_reg()
62 *
63 *	Get contents of register REGNO in task TASK.
64 */
65static unsigned long ptrace_get_reg(struct task_struct *task, int regno)
66{
67	if (regno < sizeof(struct pt_regs)) {
68		struct pt_regs *pt_regs = task_pt_regs(task);
69		return *(unsigned long *)((long) pt_regs + regno);
70	}
71
72	return -EIO;
73}
74
75/*
76 * ptrace_put_reg()
77 *	Write contents of register REGNO in task TASK.
78 */
79static int ptrace_put_reg(struct task_struct *task, int regno,
80			  unsigned long data)
81{
82	if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) {
83		struct pt_regs *pt_regs = task_pt_regs(task);
84		*(unsigned long *)((long) pt_regs + regno) = data;
85		return 0;
86	}
87	return -EIO;
88}
89
90/*
91 * ptrace_disable_single_step()
92 *	Disable Single Step
93 */
94static int ptrace_disable_single_step(struct task_struct *task)
95{
96	/*
97	 * Single Step not yet implemented, so must always be disabled
98	 */
99	return 0;
100}
101
102/*
103 * ptrace_disable()
104 *	Make sure the single step bit is not set.
105 * Called by kernel/ptrace.c when detaching..
106 */
107void ptrace_disable(struct task_struct *child)
108{
109	ptrace_disable_single_step(child);
110}
111
112/*
113 * arch_ptrace()
114 *	architecture specific ptrace routine.
115 */
116long arch_ptrace(struct task_struct *child, long request, long addr, long data)
117{
118	int ret;
119	switch (request) {
120	/* when I and D space are separate, these will need to be fixed. */
121	case PTRACE_PEEKTEXT: /* read word at location addr. */
122	case PTRACE_PEEKDATA:
123		ret = generic_ptrace_peekdata(child, addr, data);
124		break;
125
126	/* read the word at location addr in the USER area. */
127	case PTRACE_PEEKUSR: {
128		unsigned long tmp;
129
130		ret = -EIO;
131		if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP)
132		    || (addr & 3))
133			break;
134
135		tmp = 0;  /* Default return condition */
136
137		ret = -EIO;
138		if (addr < sizeof(struct pt_regs)) {
139			tmp = ptrace_get_reg(child, addr);
140		} else if (addr == PT_TEXT_ADDR) {
141			tmp = child->mm->start_code;
142		} else if (addr == PT_TEXT_END_ADDR) {
143			tmp = child->mm->end_code;
144		} else if (addr == PT_DATA_ADDR) {
145			tmp = child->mm->start_data;
146		} else if (addr == PT_EXEC_FDPIC_LOADMAP) {
147#ifdef CONFIG_BINFMT_ELF_FDPIC
148			tmp = child->mm->context.exec_fdpic_loadmap;
149#endif
150		} else if (addr == PT_INTERP_FDPIC_LOADMAP) {
151#ifdef CONFIG_BINFMT_ELF_FDPIC
152			tmp = child->mm->context.interp_fdpic_loadmap;
153#endif
154		} else {
155			break;
156		}
157
158		ret = put_user(tmp, (unsigned long *)data);
159		break;
160	}
161
162	case PTRACE_POKETEXT: /* write the word at location addr. */
163	case PTRACE_POKEDATA:
164		ret = generic_ptrace_pokedata(child, addr, data);
165
166		/*
167		 * If we just changed some code so we need to
168		 * correct the caches
169		 */
170		if (request == PTRACE_POKETEXT && ret == 0) {
171			flush_icache_range(addr, addr + 4);
172		}
173		break;
174
175	case PTRACE_POKEUSR: /* write the word at location addr
176			      * in the USER area */
177		ret = -EIO;
178
179		if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3))
180			break;
181
182		if (addr < sizeof(struct pt_regs)) {
183			ret = ptrace_put_reg(child, addr, data);
184		}
185		break;
186
187	case PTRACE_SYSCALL: /* continue and stop at next (return from)
188			      * syscall */
189	case PTRACE_CONT: { /* restart after signal. */
190
191		ret = -EIO;
192		if (!valid_signal(data))
193			break;
194		if (request == PTRACE_SYSCALL)
195			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
196		else
197			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
198		child->exit_code = data;
199		/* make sure the single step bit is not set. */
200		ptrace_disable_single_step(child);
201		wake_up_process(child);
202		ret = 0;
203		break;
204	}
205
206	/*
207	 * make the child exit.  Best I can do is send it a sigkill.
208	 * perhaps it should be put in the status that it wants to exit.
209	 */
210	case PTRACE_KILL: {
211		ret = 0;
212		if (child->exit_state == EXIT_ZOMBIE) /* already dead */
213			break;
214		child->exit_code = SIGKILL;
215		/* make sure the single step bit is not set. */
216		ptrace_disable_single_step(child);
217		wake_up_process(child);
218		break;
219	}
220
221	case PTRACE_DETACH:	/* detach a process that was attached. */
222		ret = ptrace_detach(child, data);
223		break;
224
225	case PTRACE_GETREGS:    /* Get all gp regs from the child. */
226		ptrace_getregs(child, (unsigned long *)data);
227		ret = 0;
228		break;
229
230	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
231		int i;
232		unsigned long tmp;
233		int count = sizeof(struct pt_regs) / sizeof(unsigned long);
234		for (i = 0; i < count; i++) {
235			if (get_user(tmp, (unsigned long *) data)) {
236				ret = -EFAULT;
237				break;
238			}
239			ptrace_put_reg(child, sizeof(unsigned long) * i, tmp);
240			data += sizeof(long);
241		}
242		ret = 0;
243		break;
244	}
245
246	default:
247		return ptrace_request(child, request, addr, data);
248		break;
249	}
250	return ret;
251}
252/*
253 * syscall_trace
254 *
255 * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set.
256 */
257asmlinkage void syscall_trace(void)
258{
259	struct task_struct *cur = current;
260	if (!test_thread_flag(TIF_SYSCALL_TRACE))
261		return;
262	if (!(cur->ptrace & PT_PTRACED))
263		return;
264	ptrace_notify(SIGTRAP | ((cur->ptrace & PT_TRACESYSGOOD)
265				 ? 0x80 : 0));
266	/*
267	 * this isn't the same as continuing with a signal, but it will do
268	 * for normal use.  strace only continues with a signal if the
269	 * stopping signal is not SIGTRAP.  -brl
270	 */
271	if (cur->exit_code) {
272		send_sig(cur->exit_code, current, 1);
273		current->exit_code = 0;
274	}
275}
276