File: /usr/src/linux/arch/s390x/kernel/ptrace.c

1     /*
2      *  arch/s390/kernel/ptrace.c
3      *
4      *  S390 version
5      *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6      *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
7      *
8      *  Based on PowerPC version 
9      *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
10      *
11      *  Derived from "arch/m68k/kernel/ptrace.c"
12      *  Copyright (C) 1994 by Hamish Macdonald
13      *  Taken from linux/kernel/ptrace.c and modified for M680x0.
14      *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
15      *
16      * Modified by Cort Dougan (cort@cs.nmt.edu) 
17      *
18      *
19      * This file is subject to the terms and conditions of the GNU General
20      * Public License.  See the file README.legal in the main directory of
21      * this archive for more details.
22      */
23     
24     #include <stddef.h>
25     #include <linux/config.h>
26     #include <linux/kernel.h>
27     #include <linux/sched.h>
28     #include <linux/mm.h>
29     #include <linux/smp.h>
30     #include <linux/smp_lock.h>
31     #include <linux/errno.h>
32     #include <linux/ptrace.h>
33     #include <linux/user.h>
34     
35     #include <asm/segment.h>
36     #include <asm/page.h>
37     #include <asm/pgtable.h>
38     #include <asm/pgalloc.h>
39     #include <asm/system.h>
40     #include <asm/uaccess.h>
41     
42     void FixPerRegisters(struct task_struct *task)
43     {
44     	struct pt_regs *regs = task->thread.regs;
45     	per_struct *per_info=
46     			(per_struct *)&task->thread.per_info;
47     
48     	per_info->control_regs.bits.em_instruction_fetch =
49     	        per_info->single_step | per_info->instruction_fetch;
50     	
51     	if (per_info->single_step) {
52     		per_info->control_regs.bits.starting_addr=0;
53     #ifdef CONFIG_S390_SUPPORT
54     		if (current->thread.flags & S390_FLAG_31BIT) {
55     			per_info->control_regs.bits.ending_addr=0x7fffffffUL;
56     	        }
57     		else 
58     #endif      
59     		{
60     		per_info->control_regs.bits.ending_addr=-1L;
61     		}
62     	} else {
63     		per_info->control_regs.bits.starting_addr=
64     		        per_info->starting_addr;
65     		per_info->control_regs.bits.ending_addr=
66     		        per_info->ending_addr;
67     	}
68     	/* if any of the control reg tracing bits are on 
69     	   we switch on per in the psw */
70     	if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
71     		regs->psw.mask |= PSW_PER_MASK;
72     	else
73     		regs->psw.mask &= ~PSW_PER_MASK;
74     	if (per_info->control_regs.bits.storage_alt_space_ctl)
75     		task->thread.user_seg |= USER_STD_MASK;
76     	else
77     		task->thread.user_seg &= ~USER_STD_MASK;
78     }
79     
80     void set_single_step(struct task_struct *task)
81     {
82     	per_struct *per_info= (per_struct *) &task->thread.per_info;	
83     	
84     	per_info->single_step = 1;  /* Single step */
85     	FixPerRegisters (task);
86     }
87     
88     void clear_single_step(struct task_struct *task)
89     {
90     	per_struct *per_info= (per_struct *) &task->thread.per_info;
91     
92     	per_info->single_step = 0;
93     	FixPerRegisters (task);
94     }
95     
96     int ptrace_usercopy(addr_t realuseraddr, addr_t copyaddr, int len,
97                         int tofromuser, int writeuser, unsigned long mask)
98     {
99             unsigned long *realuserptr, *copyptr;
100     	unsigned long tempuser;
101     	int retval;
102     
103             retval = 0;
104             realuserptr = (unsigned long *) realuseraddr;
105             copyptr = (unsigned long *) copyaddr;
106     
107     	if (writeuser && realuserptr == NULL)
108     		return 0;
109     
110     	if (mask != -1L) {
111     		tempuser = *realuserptr;
112     		if (!writeuser) {
113     			tempuser &= mask;
114     			realuserptr = &tempuser;
115     		}
116     	}
117     	if (tofromuser) {
118     		if (writeuser) {
119     			retval = copy_from_user(realuserptr, copyptr, len);
120     		} else {
121     			if (realuserptr == NULL)
122     				retval = clear_user(copyptr, len);
123     			else
124     				retval = copy_to_user(copyptr,realuserptr,len);
125                             retval = (retval == -EFAULT) ? -EIO : 0;
126     		}      
127     	} else {
128     		if (writeuser)
129     			memcpy(realuserptr, copyptr, len);
130     		else
131     			memcpy(copyptr, realuserptr, len);
132     	}
133     	if (mask != -1L && writeuser)
134                     *realuserptr = (*realuserptr & mask) | (tempuser & ~mask);
135     	return retval;
136     }
137     
138     int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
139                   int len, int tofromuser, int writingtouser)
140     {
141     	int copylen=0,copymax;
142     	addr_t  realuseraddr;
143     	saddr_t enduseraddr;
144     	
145     	unsigned long mask;
146     
147     #ifdef CONFIG_S390_SUPPORT
148     	if (current->thread.flags & S390_FLAG_31BIT) {
149     	/* adjust user offsets to 64 bit structure */
150     		if (useraddr < PT_PSWADDR / 2)
151     			useraddr = 2 * useraddr;
152     		else if(useraddr < PT_ACR0 / 2)
153     			useraddr = 2 * useraddr + sizeof(addr_t) / 2;
154     		else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0))
155     			useraddr = useraddr + PT_ACR0 / 2;
156     		else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0))
157     			useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; 
158             }
159     #endif  
160         
161     	enduseraddr=useraddr+len;
162     
163     	if (useraddr < 0 || enduseraddr > sizeof(struct user)||
164     	   (useraddr < PT_ENDREGS && (useraddr&3))||
165     	   (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
166     		return (-EIO);
167     	while(len>0)
168     	{
169     		mask=PSW_ADDR_MASK;
170     		if(useraddr<PT_FPC)
171     		{
172     			realuseraddr=(addr_t)&(((u8 *)task->thread.regs)[useraddr]);
173     			if(useraddr<PT_PSWMASK)
174     			{
175     				copymax=PT_PSWMASK;
176     			}
177     			else if(useraddr<(PT_PSWMASK+8))
178     			{
179     				copymax=(PT_PSWMASK+8);
180     				if(writingtouser)
181     					mask=PSW_MASK_DEBUGCHANGE;
182     			}
183     			else if(useraddr<(PT_PSWADDR+8))
184     			{
185     				copymax=PT_PSWADDR+8;
186     				mask=PSW_ADDR_DEBUGCHANGE;
187     			}
188     			else
189     				copymax=PT_FPC;
190     			
191     		}
192     		else if(useraddr<(PT_FPR15+sizeof(freg_t)))
193     		{
194     			copymax=(PT_FPR15+sizeof(freg_t));
195     			realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
196     		}
197     		else if(useraddr<sizeof(struct user_regs_struct))
198     		{
199     			copymax=sizeof(struct user_regs_struct);
200     			realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
201     		}
202     		else 
203     		{
204     			copymax=sizeof(struct user);
205     			realuseraddr=(addr_t)NULL;
206     		}
207     		copylen=copymax-useraddr;
208     		copylen=(copylen>len ? len:copylen);
209     		if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
210     			return (-EIO);
211     		copyaddr+=copylen;
212     		len-=copylen;
213     		useraddr+=copylen;
214     	}
215     	FixPerRegisters(task);
216     	return(0);
217     }
218     
219     /*
220      * Called by kernel/ptrace.c when detaching..
221      *
222      * Make sure single step bits etc are not set.
223      */
224     void ptrace_disable(struct task_struct *child)
225     {
226     	/* make sure the single step bit is not set. */
227     	clear_single_step(child);
228     }
229     
230     asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
231     {
232     	struct task_struct *child;
233     	int ret = -EPERM;
234     	unsigned long flags;
235     	unsigned long tmp;
236     	int copied;
237     	ptrace_area   parea; 
238     
239     	lock_kernel();
240     	if (request == PTRACE_TRACEME) 
241     	{
242     		/* are we already being traced? */
243     		if (current->ptrace & PT_PTRACED)
244     			goto out;
245     		/* set the ptrace bit in the process flags. */
246     		current->ptrace |= PT_PTRACED;
247     		ret = 0;
248     		goto out;
249     	}
250     	ret = -ESRCH;
251     	read_lock(&tasklist_lock);
252     	child = find_task_by_pid(pid);
253     	read_unlock(&tasklist_lock);
254     	if (!child)
255     		goto out;
256     	ret = -EPERM;
257     	if (pid == 1)		/* you may not mess with init */
258     		goto out;
259     	if (request == PTRACE_ATTACH) 
260     	{
261     		ret = ptrace_attach(child);
262     		goto out;
263     	}
264     	ret = -ESRCH;
265     	// printk("child=%lX child->flags=%lX",child,child->flags);
266     	/* I added child!=current line so we can get the */
267     	/* ieee_instruction_pointer from the user structure DJB */
268     	if(child!=current)
269     	{
270     		if (!(child->ptrace & PT_PTRACED))
271     			goto out;
272     		if (child->state != TASK_STOPPED) 
273     		{
274     			if (request != PTRACE_KILL)
275     				goto out;
276     		}
277     		if (child->p_pptr != current)
278     			goto out;
279     	}
280     	switch (request) 
281     	{
282     		/* If I and D space are separate, these will need to be fixed. */
283     	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
284     	case PTRACE_PEEKDATA: 
285     		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
286     		ret = -EIO;
287     		if (copied != sizeof(tmp))
288     			goto out;
289     		ret = put_user(tmp,(unsigned long *) data);
290     		goto out;
291     
292     		/* read the word at location addr in the USER area. */
293     	case PTRACE_PEEKUSR:
294     		ret=copy_user(child,addr,data,sizeof(unsigned long),1,0);
295     		break;
296     
297     		/* If I and D space are separate, this will have to be fixed. */
298     	case PTRACE_POKETEXT: /* write the word at location addr. */
299     	case PTRACE_POKEDATA:
300     		ret = 0;
301     		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
302     			goto out;
303     		ret = -EIO;
304     		goto out;
305     		break;
306     
307     	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
308     		ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1);
309     		break;
310     
311     	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
312     	case PTRACE_CONT: 	 /* restart after signal. */
313     		ret = -EIO;
314     		if ((unsigned long) data >= _NSIG)
315     			break;
316     		if (request == PTRACE_SYSCALL)
317     			child->ptrace |= PT_TRACESYS;
318     		else
319     			child->ptrace &= ~PT_TRACESYS;
320     		child->exit_code = data;
321     		/* make sure the single step bit is not set. */
322     		clear_single_step(child);
323     		wake_up_process(child);
324     		ret = 0;
325     		break;
326     
327     /*
328      * make the child exit.  Best I can do is send it a sigkill. 
329      * perhaps it should be put in the status that it wants to 
330      * exit.
331      */
332     	case PTRACE_KILL:
333     		ret = 0;
334     		if (child->state == TASK_ZOMBIE) /* already dead */
335     			break;
336     		child->exit_code = SIGKILL;
337     		clear_single_step(child);
338     		wake_up_process(child);
339     		/* make sure the single step bit is not set. */
340     		break;
341     
342     	case PTRACE_SINGLESTEP:  /* set the trap flag. */
343     		ret = -EIO;
344     		if ((unsigned long) data >= _NSIG)
345     			break;
346     		child->ptrace &= ~PT_TRACESYS;
347     		child->exit_code = data;
348     		set_single_step(child);
349     		/* give it a chance to run. */
350     		wake_up_process(child);
351     		ret = 0;
352     		break;
353     
354     	case PTRACE_DETACH:  /* detach a process that was attached. */
355     		ret = ptrace_detach(child, data);
356     		break;
357     
358     	case PTRACE_PEEKUSR_AREA:
359     	case PTRACE_POKEUSR_AREA:
360     		if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
361     		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
362     				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
363     		break;
364     	default:
365     		ret = -EIO;
366     		break;
367     	}
368      out:
369     	unlock_kernel();
370     	return ret;
371     }
372     
373     typedef struct
374     {
375     __u32	len;
376     __u32	kernel_addr;
377     __u32	process_addr;
378     } ptrace_area_emu31;
379     
380     asmlinkage int sys32_ptrace(long request, long pid, long addr, s32 data)
381     {
382     	struct task_struct *child;
383     	int ret = -EPERM;
384     	unsigned long flags;
385     	u32 tmp;
386     	int copied;
387     	ptrace_area   parea; 
388     
389     	lock_kernel();
390     	if (request == PTRACE_TRACEME) 
391     	{
392     		/* are we already being traced? */
393     		if (current->ptrace & PT_PTRACED)
394     			goto out;
395     		/* set the ptrace bit in the process flags. */
396     		current->ptrace |= PT_PTRACED;
397     		ret = 0;
398     		goto out;
399     	}
400     	ret = -ESRCH;
401     	read_lock(&tasklist_lock);
402     	child = find_task_by_pid(pid);
403     	read_unlock(&tasklist_lock);
404     	if (!child)
405     		goto out;
406     	ret = -EPERM;
407     	if (pid == 1)		/* you may not mess with init */
408     		goto out;
409     	if (request == PTRACE_ATTACH) 
410     	{
411     		ret = ptrace_attach(child);
412     		goto out;
413     	}
414     	ret = -ESRCH;
415     	// printk("child=%lX child->flags=%lX",child,child->flags);
416     	/* I added child!=current line so we can get the */
417     	/* ieee_instruction_pointer from the user structure DJB */
418     	if(child!=current)
419     	{
420     		if (!(child->ptrace & PT_PTRACED))
421     			goto out;
422     		if (child->state != TASK_STOPPED) 
423     		{
424     			if (request != PTRACE_KILL)
425     				goto out;
426     		}
427     		if (child->p_pptr != current)
428     			goto out;
429     	}
430     	switch (request) 
431     	{
432     		/* If I and D space are separate, these will need to be fixed. */
433     	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
434     	case PTRACE_PEEKDATA: 
435     		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
436     		ret = -EIO;
437     		if (copied != sizeof(tmp))
438     			goto out;
439     		ret = put_user(tmp,(u32 *)(unsigned long)data);
440     		goto out;
441     
442     		/* read the word at location addr in the USER area. */
443     	case PTRACE_PEEKUSR:
444     		ret=copy_user(child,addr,data,sizeof(u32),1,0);
445     		break;
446     
447     		/* If I and D space are separate, this will have to be fixed. */
448     	case PTRACE_POKETEXT: /* write the word at location addr. */
449     	case PTRACE_POKEDATA:
450     		ret = 0;
451     		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
452     			goto out;
453     		ret = -EIO;
454     		goto out;
455     		break;
456     
457     	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
458     		ret=copy_user(child,addr,(addr_t)&data,sizeof(u32),0,1);
459     		break;
460     
461     	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
462     	case PTRACE_CONT: 	 /* restart after signal. */
463     		ret = -EIO;
464     		if ((unsigned long) data >= _NSIG)
465     			break;
466     		if (request == PTRACE_SYSCALL)
467     			child->ptrace |= PT_TRACESYS;
468     		else
469     			child->ptrace &= ~PT_TRACESYS;
470     		child->exit_code = data;
471     		/* make sure the single step bit is not set. */
472     		clear_single_step(child);
473     		wake_up_process(child);
474     		ret = 0;
475     		break;
476     
477     /*
478      * make the child exit.  Best I can do is send it a sigkill. 
479      * perhaps it should be put in the status that it wants to 
480      * exit.
481      */
482     	case PTRACE_KILL:
483     		ret = 0;
484     		if (child->state == TASK_ZOMBIE) /* already dead */
485     			break;
486     		child->exit_code = SIGKILL;
487     		clear_single_step(child);
488     		wake_up_process(child);
489     		/* make sure the single step bit is not set. */
490     		break;
491     
492     	case PTRACE_SINGLESTEP:  /* set the trap flag. */
493     		ret = -EIO;
494     		if ((unsigned long) data >= _NSIG)
495     			break;
496     		child->ptrace &= ~PT_TRACESYS;
497     		child->exit_code = data;
498     		set_single_step(child);
499     		/* give it a chance to run. */
500     		wake_up_process(child);
501     		ret = 0;
502     		break;
503     
504     	case PTRACE_DETACH:  /* detach a process that was attached. */
505     		ret = -EIO;
506     		if ((unsigned long) data >= _NSIG)
507     			break;
508     		child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
509     		child->exit_code = data;
510     		write_lock_irqsave(&tasklist_lock, flags);
511     		REMOVE_LINKS(child);
512     		child->p_pptr = child->p_opptr;
513     		SET_LINKS(child);
514     		write_unlock_irqrestore(&tasklist_lock, flags);
515     		/* make sure the single step bit is not set. */
516     		clear_single_step(child);
517     		wake_up_process(child);
518     		ret = 0;
519     		break;
520     	case PTRACE_PEEKUSR_AREA:
521     	case PTRACE_POKEUSR_AREA:
522     		{
523     		ptrace_area_emu31 * parea31 = (void *)addr;
524     		if (!access_ok(VERIFY_READ, parea31, sizeof(*parea31)))
525     			return(-EFAULT);
526     		ret = __get_user(parea.len, &parea31->len);
527     		ret |= __get_user(parea.kernel_addr, &parea31->kernel_addr);
528     		ret |= __get_user(parea.process_addr, &parea31->process_addr);
529     		if(ret==0)  
530     		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
531     				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
532     		break;
533     		}
534     	default:
535     		ret = -EIO;
536     		break;
537     	}
538      out:
539     	unlock_kernel();
540     	return ret;
541     }
542     
543     asmlinkage void syscall_trace(void)
544     {
545     	lock_kernel();
546     	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
547     	    != (PT_PTRACED|PT_TRACESYS))
548     		goto out;
549     	current->exit_code = SIGTRAP;
550     	set_current_state(TASK_STOPPED);
551     	notify_parent(current, SIGCHLD);
552     	schedule();
553     	/*
554     	 * this isn't the same as continuing with a signal, but it will do
555     	 * for normal use.  strace only continues with a signal if the
556     	 * stopping signal is not SIGTRAP.  -brl
557     	 */
558     	if (current->exit_code) {
559     		send_sig(current->exit_code, current, 1);
560     		current->exit_code = 0;
561     	}
562      out:
563     	unlock_kernel();
564     }
565