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  */
get_stack_long(struct task_struct * task,int offset)47 static 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  */
put_stack_long(struct task_struct * task,int offset,unsigned long data)62 static 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 
putreg(struct task_struct * child,unsigned long regno,unsigned long value)73 static 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 
getreg(struct task_struct * child,unsigned long regno)110 static 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  */
ptrace_disable(struct task_struct * child)142 void 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 
sys_ptrace(long request,long pid,long addr,long data)150 asmlinkage 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 	}
426 out_tsk:
427 	free_task_struct(child);
428 out:
429 	unlock_kernel();
430 	return ret;
431 }
432 
syscall_trace(void)433 asmlinkage 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