1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1992 Ross Biro
7  * Copyright (C) Linus Torvalds
8  * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
9  * Copyright (C) 1996 David S. Miller
10  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
11  * Copyright (C) 1999 MIPS Technologies, Inc.
12  */
13 #include <linux/config.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/mm.h>
17 #include <linux/errno.h>
18 #include <linux/ptrace.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21 #include <linux/user.h>
22 
23 #include <asm/mipsregs.h>
24 #include <asm/pgtable.h>
25 #include <asm/page.h>
26 #include <asm/system.h>
27 #include <asm/uaccess.h>
28 #include <asm/bootinfo.h>
29 #include <asm/cpu.h>
30 #include <asm/fpu.h>
31 
32 /*
33  * Called by kernel/ptrace.c when detaching..
34  *
35  * Make sure single step bits etc are not set.
36  */
ptrace_disable(struct task_struct * child)37 void ptrace_disable(struct task_struct *child)
38 {
39 	/* Nothing to do.. */
40 }
41 
sys_ptrace(long request,long pid,long addr,long data)42 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
43 {
44 	struct task_struct *child;
45 	int ret;
46 
47 	lock_kernel();
48 #if 0
49 	printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
50 	       (int) request, (int) pid, (unsigned long) addr,
51 	       (unsigned long) data);
52 #endif
53 	if (request == PTRACE_TRACEME) {
54 		/* are we already being traced? */
55 		if (current->ptrace & PT_PTRACED) {
56 			ret = -EPERM;
57 			goto out;
58 		}
59 		/* set the ptrace bit in the process flags. */
60 		current->ptrace |= PT_PTRACED;
61 		ret = 0;
62 		goto out;
63 	}
64 	ret = -ESRCH;
65 	read_lock(&tasklist_lock);
66 	child = find_task_by_pid(pid);
67 	if (child)
68 		get_task_struct(child);
69 	read_unlock(&tasklist_lock);
70 	if (!child)
71 		goto out;
72 
73 	ret = -EPERM;
74 	if (pid == 1)		/* you may not mess with init */
75 		goto out_tsk;
76 
77 	if (request == PTRACE_ATTACH) {
78 		ret = ptrace_attach(child);
79 		goto out_tsk;
80 	}
81 
82 	ret = ptrace_check_attach(child, request == PTRACE_KILL);
83 	if (ret < 0)
84 		goto out_tsk;
85 
86 	switch (request) {
87 	case PTRACE_PEEKTEXT: /* read word at location addr. */
88 	case PTRACE_PEEKDATA: {
89 		unsigned long tmp;
90 		int copied;
91 
92 		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
93 		ret = -EIO;
94 		if (copied != sizeof(tmp))
95 			break;
96 		ret = put_user(tmp,(unsigned long *) data);
97 		break;
98 		}
99 
100 	/* Read the word at location addr in the USER area.  */
101 	case PTRACE_PEEKUSR: {
102 		struct pt_regs *regs;
103 		unsigned long tmp;
104 
105 		regs = (struct pt_regs *) ((unsigned long) child +
106 		       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
107 		tmp = 0;  /* Default return value. */
108 
109 		switch(addr) {
110 		case 0 ... 31:
111 			tmp = regs->regs[addr];
112 			break;
113 		case FPR_BASE ... FPR_BASE + 31:
114 			if (child->used_math) {
115 			        unsigned long long *fregs = get_fpu_regs(child);
116 				/*
117 				 * The odd registers are actually the high
118 				 * order bits of the values stored in the even
119 				 * registers - unless we're using r2k_switch.S.
120 				 */
121 				if (addr & 1)
122 					tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
123 				else
124 					tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
125 			} else {
126 				tmp = -1;	/* FP not yet used  */
127 			}
128 			break;
129 		case PC:
130 			tmp = regs->cp0_epc;
131 			break;
132 		case CAUSE:
133 			tmp = regs->cp0_cause;
134 			break;
135 		case BADVADDR:
136 			tmp = regs->cp0_badvaddr;
137 			break;
138 		case MMHI:
139 			tmp = regs->hi;
140 			break;
141 		case MMLO:
142 			tmp = regs->lo;
143 			break;
144 		case FPC_CSR:
145 			if (!cpu_has_fpu)
146 				tmp = child->thread.fpu.soft.sr;
147 			else
148 				tmp = child->thread.fpu.hard.control;
149 			break;
150 		case FPC_EIR: {	/* implementation / version register */
151 			unsigned long flags;
152 
153 			if (!cpu_has_fpu)
154 				break;
155 
156 			__save_flags(flags);
157 			__enable_fpu();
158 			__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
159 			__restore_flags(flags);
160 			break;
161 		}
162 		default:
163 			tmp = 0;
164 			ret = -EIO;
165 			goto out_tsk;
166 		}
167 		ret = put_user(tmp, (unsigned long *) data);
168 		break;
169 		}
170 
171 	case PTRACE_POKETEXT: /* write the word at location addr. */
172 	case PTRACE_POKEDATA:
173 		ret = 0;
174 		if (access_process_vm(child, addr, &data, sizeof(data), 1)
175 		    == sizeof(data))
176 			break;
177 		ret = -EIO;
178 		break;
179 
180 	case PTRACE_POKEUSR: {
181 		struct pt_regs *regs;
182 		ret = 0;
183 		regs = (struct pt_regs *) ((unsigned long) child +
184 		       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
185 
186 		switch (addr) {
187 		case 0 ... 31:
188 			regs->regs[addr] = data;
189 			break;
190 		case FPR_BASE ... FPR_BASE + 31: {
191 			unsigned long long *fregs;
192 			fregs = (unsigned long long *)get_fpu_regs(child);
193 			if (!child->used_math) {
194 				/* FP not yet used  */
195 				memset(&child->thread.fpu.hard, ~0,
196 				       sizeof(child->thread.fpu.hard));
197 				child->thread.fpu.hard.control = 0;
198 			}
199 			/*
200 			 * The odd registers are actually the high order bits
201 			 * of the values stored in the even registers - unless
202 			 * we're using r2k_switch.S.
203 			 */
204 			if (addr & 1) {
205 				fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
206 				fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
207 			} else {
208 				fregs[addr - FPR_BASE] &= ~0xffffffffLL;
209 				fregs[addr - FPR_BASE] |= data;
210 			}
211 			break;
212 		}
213 		case PC:
214 			regs->cp0_epc = data;
215 			break;
216 		case MMHI:
217 			regs->hi = data;
218 			break;
219 		case MMLO:
220 			regs->lo = data;
221 			break;
222 		case FPC_CSR:
223 			if (!cpu_has_fpu)
224 				child->thread.fpu.soft.sr = data;
225 			else
226 				child->thread.fpu.hard.control = data;
227 			break;
228 		default:
229 			/* The rest are not allowed. */
230 			ret = -EIO;
231 			break;
232 		}
233 		break;
234 		}
235 
236 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
237 	case PTRACE_CONT: { /* restart after signal. */
238 		ret = -EIO;
239 		if ((unsigned long) data > _NSIG)
240 			break;
241 		if (request == PTRACE_SYSCALL)
242 			child->ptrace |= PT_TRACESYS;
243 		else
244 			child->ptrace &= ~PT_TRACESYS;
245 		child->exit_code = data;
246 		wake_up_process(child);
247 		ret = 0;
248 		break;
249 		}
250 
251 	/*
252 	 * make the child exit.  Best I can do is send it a sigkill.
253 	 * perhaps it should be put in the status that it wants to
254 	 * exit.
255 	 */
256 	case PTRACE_KILL:
257 		ret = 0;
258 		if (child->state == TASK_ZOMBIE)	/* already dead */
259 			break;
260 		child->exit_code = SIGKILL;
261 		wake_up_process(child);
262 		break;
263 
264 	case PTRACE_DETACH: /* detach a process that was attached. */
265 		ret = ptrace_detach(child, data);
266 		break;
267 
268 	case PTRACE_SETOPTIONS:
269 		if (data & PTRACE_O_TRACESYSGOOD)
270 			child->ptrace |= PT_TRACESYSGOOD;
271 		else
272 			child->ptrace &= ~PT_TRACESYSGOOD;
273 		ret = 0;
274 		break;
275 
276 	default:
277 		ret = -EIO;
278 		break;
279 	}
280 out_tsk:
281 	free_task_struct(child);
282 out:
283 	unlock_kernel();
284 	return ret;
285 }
286 
syscall_trace(void)287 asmlinkage void syscall_trace(void)
288 {
289 	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
290 			!= (PT_PTRACED|PT_TRACESYS))
291 		return;
292 	/* The 0x80 provides a way for the tracing parent to distinguish
293 	   between a syscall stop and SIGTRAP delivery */
294 	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
295 	                                ? 0x80 : 0);
296 	current->state = TASK_STOPPED;
297 	notify_parent(current, SIGCHLD);
298 	schedule();
299 	/*
300 	 * this isn't the same as continuing with a signal, but it will do
301 	 * for normal use.  strace only continues with a signal if the
302 	 * stopping signal is not SIGTRAP.  -brl
303 	 */
304 	if (current->exit_code) {
305 		send_sig(current->exit_code, current, 1);
306 		current->exit_code = 0;
307 	}
308 }
309