1/* ptrace.c */
2/* By Ross Biro 1/23/92 */
3/*
4 * Pentium III FXSR, SSE support
5 *	Gareth Hughes <gareth@valinux.com>, May 2000
6 */
7
8#include <linux/kernel.h>
9#include <linux/sched.h>
10#include <linux/mm.h>
11#include <linux/smp.h>
12#include <linux/smp_lock.h>
13#include <linux/errno.h>
14#include <linux/ptrace.h>
15#include <linux/user.h>
16
17#include <asm/uaccess.h>
18#include <asm/pgtable.h>
19#include <asm/system.h>
20#include <asm/processor.h>
21#include <asm/i387.h>
22#include <asm/debugreg.h>
23
24/*
25 * does not yet catch signals sent when the child dies.
26 * in exit.c or in signal.c.
27 */
28
29/* determines which flags the user has access to. */
30/* 1 = access 0 = no access */
31#define FLAG_MASK 0x00044dd5
32
33/* set's the trap flag. */
34#define TRAP_FLAG 0x100
35
36/*
37 * Offset of eflags on child stack..
38 */
39#define EFL_OFFSET ((EFL-2)*4-sizeof(struct pt_regs))
40
41/*
42 * this routine will get a word off of the processes privileged stack.
43 * the offset is how far from the base addr as stored in the TSS.
44 * this routine assumes that all the privileged stacks are in our
45 * data space.
46 */
47static inline int get_stack_long(struct task_struct *task, int offset)
48{
49	unsigned char *stack;
50
51	stack = (unsigned char *)task->thread.esp0;
52	stack += offset;
53	return (*((int *)stack));
54}
55
56/*
57 * this routine will put a word on the processes privileged stack.
58 * the offset is how far from the base addr as stored in the TSS.
59 * this routine assumes that all the privileged stacks are in our
60 * data space.
61 */
62static inline int put_stack_long(struct task_struct *task, int offset,
63	unsigned long data)
64{
65	unsigned char * stack;
66
67	stack = (unsigned char *) task->thread.esp0;
68	stack += offset;
69	*(unsigned long *) stack = data;
70	return 0;
71}
72
73static int putreg(struct task_struct *child,
74	unsigned long regno, unsigned long value)
75{
76	switch (regno >> 2) {
77		case FS:
78			if (value && (value & 3) != 3)
79				return -EIO;
80			child->thread.fs = value;
81			return 0;
82		case GS:
83			if (value && (value & 3) != 3)
84				return -EIO;
85			child->thread.gs = value;
86			return 0;
87		case DS:
88		case ES:
89			if (value && (value & 3) != 3)
90				return -EIO;
91			value &= 0xffff;
92			break;
93		case SS:
94		case CS:
95			if ((value & 3) != 3)
96				return -EIO;
97			value &= 0xffff;
98			break;
99		case EFL:
100			value &= FLAG_MASK;
101			value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK;
102			break;
103	}
104	if (regno > GS*4)
105		regno -= 2*4;
106	put_stack_long(child, regno - sizeof(struct pt_regs), value);
107	return 0;
108}
109
110static unsigned long getreg(struct task_struct *child,
111	unsigned long regno)
112{
113	unsigned long retval = ~0UL;
114
115	switch (regno >> 2) {
116		case FS:
117			retval = child->thread.fs;
118			break;
119		case GS:
120			retval = child->thread.gs;
121			break;
122		case DS:
123		case ES:
124		case SS:
125		case CS:
126			retval = 0xffff;
127			/* fall through */
128		default:
129			if (regno > GS*4)
130				regno -= 2*4;
131			regno = regno - sizeof(struct pt_regs);
132			retval &= get_stack_long(child, regno);
133	}
134	return retval;
135}
136
137/*
138 * Called by kernel/ptrace.c when detaching..
139 *
140 * Make sure the single step bit is not set.
141 */
142void ptrace_disable(struct task_struct *child)
143{
144	long tmp;
145
146	tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
147	put_stack_long(child, EFL_OFFSET, tmp);
148}
149
150asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
151{
152	struct task_struct *child;
153	struct user * dummy = NULL;
154	int i, ret;
155
156	lock_kernel();
157	ret = -EPERM;
158	if (request == PTRACE_TRACEME) {
159		/* are we already being traced? */
160		if (current->ptrace & PT_PTRACED)
161			goto out;
162		/* set the ptrace bit in the process flags. */
163		current->ptrace |= PT_PTRACED;
164		ret = 0;
165		goto out;
166	}
167	ret = -ESRCH;
168	read_lock(&tasklist_lock);
169	child = find_task_by_pid(pid);
170	if (child)
171		get_task_struct(child);
172	read_unlock(&tasklist_lock);
173	if (!child)
174		goto out;
175
176	ret = -EPERM;
177	if (pid == 1)		/* you may not mess with init */
178		goto out_tsk;
179
180	if (request == PTRACE_ATTACH) {
181		ret = ptrace_attach(child);
182		goto out_tsk;
183	}
184
185	ret = ptrace_check_attach(child, request == PTRACE_KILL);
186	if (ret < 0)
187		goto out_tsk;
188
189	switch (request) {
190	/* when I and D space are separate, these will need to be fixed. */
191	case PTRACE_PEEKTEXT: /* read word at location addr. */
192	case PTRACE_PEEKDATA: {
193		unsigned long tmp;
194		int copied;
195
196		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
197		ret = -EIO;
198		if (copied != sizeof(tmp))
199			break;
200		ret = put_user(tmp,(unsigned long *) data);
201		break;
202	}
203
204	/* read the word at location addr in the USER area. */
205	case PTRACE_PEEKUSR: {
206		unsigned long tmp;
207
208		ret = -EIO;
209		if ((addr & 3) || addr < 0 ||
210		    addr > sizeof(struct user) - 3)
211			break;
212
213		tmp = 0;  /* Default return condition */
214		if(addr < FRAME_SIZE*sizeof(long))
215			tmp = getreg(child, addr);
216		if(addr >= (long) &dummy->u_debugreg[0] &&
217		   addr <= (long) &dummy->u_debugreg[7]){
218			addr -= (long) &dummy->u_debugreg[0];
219			addr = addr >> 2;
220			tmp = child->thread.debugreg[addr];
221		}
222		ret = put_user(tmp,(unsigned long *) data);
223		break;
224	}
225
226	/* when I and D space are separate, this will have to be fixed. */
227	case PTRACE_POKETEXT: /* write the word at location addr. */
228	case PTRACE_POKEDATA:
229		ret = 0;
230		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
231			break;
232		ret = -EIO;
233		break;
234
235	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
236		ret = -EIO;
237		if ((addr & 3) || addr < 0 ||
238		    addr > sizeof(struct user) - 3)
239			break;
240
241		if (addr < FRAME_SIZE*sizeof(long)) {
242			ret = putreg(child, addr, data);
243			break;
244		}
245		/* We need to be very careful here.  We implicitly
246		   want to modify a portion of the task_struct, and we
247		   have to be selective about what portions we allow someone
248		   to modify. */
249
250		  ret = -EIO;
251		  if(addr >= (long) &dummy->u_debugreg[0] &&
252		     addr <= (long) &dummy->u_debugreg[7]){
253
254			  if(addr == (long) &dummy->u_debugreg[4]) break;
255			  if(addr == (long) &dummy->u_debugreg[5]) break;
256			  if(addr < (long) &dummy->u_debugreg[4] &&
257			     ((unsigned long) data) >= TASK_SIZE-3) break;
258
259			  if(addr == (long) &dummy->u_debugreg[7]) {
260				  data &= ~DR_CONTROL_RESERVED;
261				  for(i=0; i<4; i++)
262					  if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
263						  goto out_tsk;
264			  }
265
266			  addr -= (long) &dummy->u_debugreg;
267			  addr = addr >> 2;
268			  child->thread.debugreg[addr] = data;
269			  ret = 0;
270		  }
271		  break;
272
273	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
274	case PTRACE_CONT: { /* restart after signal. */
275		long tmp;
276
277		ret = -EIO;
278		if ((unsigned long) data > _NSIG)
279			break;
280		if (request == PTRACE_SYSCALL)
281			child->ptrace |= PT_TRACESYS;
282		else
283			child->ptrace &= ~PT_TRACESYS;
284		child->exit_code = data;
285	/* make sure the single step bit is not set. */
286		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
287		put_stack_long(child, EFL_OFFSET,tmp);
288		wake_up_process(child);
289		ret = 0;
290		break;
291	}
292
293/*
294 * make the child exit.  Best I can do is send it a sigkill.
295 * perhaps it should be put in the status that it wants to
296 * exit.
297 */
298	case PTRACE_KILL: {
299		long tmp;
300
301		ret = 0;
302		if (child->state == TASK_ZOMBIE)	/* already dead */
303			break;
304		child->exit_code = SIGKILL;
305		/* make sure the single step bit is not set. */
306		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
307		put_stack_long(child, EFL_OFFSET, tmp);
308		wake_up_process(child);
309		break;
310	}
311
312	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
313		long tmp;
314
315		ret = -EIO;
316		if ((unsigned long) data > _NSIG)
317			break;
318		child->ptrace &= ~PT_TRACESYS;
319		if ((child->ptrace & PT_DTRACE) == 0) {
320			/* Spurious delayed TF traps may occur */
321			child->ptrace |= PT_DTRACE;
322		}
323		tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
324		put_stack_long(child, EFL_OFFSET, tmp);
325		child->exit_code = data;
326		/* give it a chance to run. */
327		wake_up_process(child);
328		ret = 0;
329		break;
330	}
331
332	case PTRACE_DETACH:
333		/* detach a process that was attached. */
334		ret = ptrace_detach(child, data);
335		break;
336
337	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
338	  	if (!access_ok(VERIFY_WRITE, (unsigned *)data, FRAME_SIZE*sizeof(long))) {
339			ret = -EIO;
340			break;
341		}
342		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
343			__put_user(getreg(child, i),(unsigned long *) data);
344			data += sizeof(long);
345		}
346		ret = 0;
347		break;
348	}
349
350	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
351		unsigned long tmp;
352	  	if (!access_ok(VERIFY_READ, (unsigned *)data, FRAME_SIZE*sizeof(long))) {
353			ret = -EIO;
354			break;
355		}
356		for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long) ) {
357			__get_user(tmp, (unsigned long *) data);
358			putreg(child, i, tmp);
359			data += sizeof(long);
360		}
361		ret = 0;
362		break;
363	}
364
365	case PTRACE_GETFPREGS: { /* Get the child FPU state. */
366		if (!access_ok(VERIFY_WRITE, (unsigned *)data,
367			       sizeof(struct user_i387_struct))) {
368			ret = -EIO;
369			break;
370		}
371		ret = 0;
372		if ( !child->used_math )
373			load_empty_fpu(child);
374		get_fpregs((struct user_i387_struct *)data, child);
375		break;
376	}
377
378	case PTRACE_SETFPREGS: { /* Set the child FPU state. */
379		if (!access_ok(VERIFY_READ, (unsigned *)data,
380			       sizeof(struct user_i387_struct))) {
381			ret = -EIO;
382			break;
383		}
384		child->used_math = 1;
385		set_fpregs(child, (struct user_i387_struct *)data);
386		ret = 0;
387		break;
388	}
389
390	case PTRACE_GETFPXREGS: { /* Get the child extended FPU state. */
391		if (!access_ok(VERIFY_WRITE, (unsigned *)data,
392			       sizeof(struct user_fxsr_struct))) {
393			ret = -EIO;
394			break;
395		}
396		if ( !child->used_math )
397			load_empty_fpu(child);
398		ret = get_fpxregs((struct user_fxsr_struct *)data, child);
399		break;
400	}
401
402	case PTRACE_SETFPXREGS: { /* Set the child extended FPU state. */
403		if (!access_ok(VERIFY_READ, (unsigned *)data,
404			       sizeof(struct user_fxsr_struct))) {
405			ret = -EIO;
406			break;
407		}
408		child->used_math = 1;
409		ret = set_fpxregs(child, (struct user_fxsr_struct *)data);
410		break;
411	}
412
413	case PTRACE_SETOPTIONS: {
414		if (data & PTRACE_O_TRACESYSGOOD)
415			child->ptrace |= PT_TRACESYSGOOD;
416		else
417			child->ptrace &= ~PT_TRACESYSGOOD;
418		ret = 0;
419		break;
420	}
421
422	default:
423		ret = -EIO;
424		break;
425	}
426out_tsk:
427	free_task_struct(child);
428out:
429	unlock_kernel();
430	return ret;
431}
432
433asmlinkage void syscall_trace(void)
434{
435	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
436			(PT_PTRACED|PT_TRACESYS))
437		return;
438	/* the 0x80 provides a way for the tracing parent to distinguish
439	   between a syscall stop and SIGTRAP delivery */
440	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
441					? 0x80 : 0);
442	current->state = TASK_STOPPED;
443	notify_parent(current, SIGCHLD);
444	schedule();
445	/*
446	 * this isn't the same as continuing with a signal, but it will do
447	 * for normal use.  strace only continues with a signal if the
448	 * stopping signal is not SIGTRAP.  -brl
449	 */
450	if (current->exit_code) {
451		send_sig(current->exit_code, current, 1);
452		current->exit_code = 0;
453	}
454}
455