File: /usr/src/linux/arch/s390/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/kernel.h>
26     #include <linux/sched.h>
27     #include <linux/mm.h>
28     #include <linux/smp.h>
29     #include <linux/smp_lock.h>
30     #include <linux/errno.h>
31     #include <linux/ptrace.h>
32     #include <linux/user.h>
33     
34     #include <asm/segment.h>
35     #include <asm/page.h>
36     #include <asm/pgtable.h>
37     #include <asm/pgalloc.h>
38     #include <asm/system.h>
39     #include <asm/uaccess.h>
40     
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     	{
53     		per_info->control_regs.bits.starting_addr=0;
54     		per_info->control_regs.bits.ending_addr=0x7fffffffUL;
55     	}
56     	else
57     	{
58     		per_info->control_regs.bits.starting_addr=
59     		per_info->starting_addr;
60     		per_info->control_regs.bits.ending_addr=
61     		per_info->ending_addr;
62     	}
63     	/* if any of the control reg tracing bits are on 
64     	   we switch on per in the psw */
65     	if(per_info->control_regs.words.cr[0]&PER_EM_MASK)
66     		regs->psw.mask |=PSW_PER_MASK;
67     	else
68     		regs->psw.mask &= ~PSW_PER_MASK;
69     	if (per_info->control_regs.bits.em_storage_alteration)
70     	{
71     		per_info->control_regs.bits.storage_alt_space_ctl=1;
72     		//((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK;
73     	}
74     	else
75     	{
76     		per_info->control_regs.bits.storage_alt_space_ctl=0;
77     		//((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK;
78     	}
79     }
80     
81     void set_single_step(struct task_struct *task)
82     {
83     	per_struct *per_info=
84     			(per_struct *)&task->thread.per_info;	
85     	
86     	per_info->single_step=1;  /* Single step */
87     	FixPerRegisters(task);
88     }
89     
90     void clear_single_step(struct task_struct *task)
91     {
92     	per_struct *per_info=
93     			(per_struct *)&task->thread.per_info;
94     
95     	per_info->single_step=0;
96     	FixPerRegisters(task);
97     }
98     
99     int ptrace_usercopy(addr_t realuseraddr,addr_t copyaddr,int len,int tofromuser,int writeuser,u32 mask)
100     {
101     	u32  tempuser;
102     	int  retval=0;
103     	
104     	if(writeuser&&realuseraddr==(addr_t)NULL)
105     		return(0);
106     	if(mask!=0xffffffff)
107     	{
108     		tempuser=*((u32 *)realuseraddr);
109     		if(!writeuser)
110     		{
111     			tempuser&=mask;
112     			realuseraddr=(addr_t)&tempuser;
113     		}
114     	}
115     	if(tofromuser)
116     	{
117     		if(writeuser)
118     		{
119     			retval=copy_from_user((void *)realuseraddr,(void *)copyaddr,len);
120     		}
121     		else
122     		{
123     			if(realuseraddr==(addr_t)NULL)
124     				retval=(clear_user((void *)copyaddr,len)==-EFAULT ? -EIO:0);
125     			else
126     				retval=(copy_to_user((void *)copyaddr,(void *)realuseraddr,len)==-EFAULT ? -EIO:0);
127     		}      
128     	}
129     	else
130     	{
131     		if(writeuser)
132     			memcpy((void *)realuseraddr,(void *)copyaddr,len);
133     		else
134     			memcpy((void *)copyaddr,(void *)realuseraddr,len);
135     	}
136     	if(mask!=0xffffffff&&writeuser)
137     			(*((u32 *)realuseraddr))=(((*((u32 *)realuseraddr))&mask)|(tempuser&~mask));
138     	return(retval);
139     }
140     
141     int copy_user(struct task_struct *task,saddr_t useraddr,addr_t copyaddr,int len,int tofromuser,int writingtouser)
142     {
143     	int copylen=0,copymax;
144     	addr_t  realuseraddr;
145     	saddr_t enduseraddr=useraddr+len;
146     	
147     	u32 mask;
148     
149     	if (useraddr < 0 || enduseraddr > sizeof(struct user)||
150     	   (useraddr < PT_ENDREGS && (useraddr&3))||
151     	   (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
152     		return (-EIO);
153     	while(len>0)
154     	{
155     		mask=0xffffffff;
156     		if(useraddr<PT_FPC)
157     		{
158     			realuseraddr=(addr_t)&(((u8 *)task->thread.regs)[useraddr]);
159     			if(useraddr<PT_PSWMASK)
160     			{
161     				copymax=PT_PSWMASK;
162     			}
163     			else if(useraddr<(PT_PSWMASK+4))
164     			{
165     				copymax=(PT_PSWMASK+4);
166     				if(writingtouser)
167     					mask=PSW_MASK_DEBUGCHANGE;
168     			}
169     			else if(useraddr<(PT_PSWADDR+4))
170     			{
171     				copymax=PT_PSWADDR+4;
172     				mask=PSW_ADDR_DEBUGCHANGE;
173     			}
174     			else
175     				copymax=PT_FPC;
176     			
177     		}
178     		else if(useraddr<(PT_FPR15_LO+4))
179     		{
180     			copymax=(PT_FPR15_LO+4);
181     			realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
182     		}
183     		else if(useraddr<sizeof(struct user_regs_struct))
184     		{
185     			copymax=sizeof(struct user_regs_struct);
186     			realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
187     		}
188     		else 
189     		{
190     			copymax=sizeof(struct user);
191     			realuseraddr=(addr_t)NULL;
192     		}
193     		copylen=copymax-useraddr;
194     		copylen=(copylen>len ? len:copylen);
195     		if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
196     			return (-EIO);
197     		copyaddr+=copylen;
198     		len-=copylen;
199     		useraddr+=copylen;
200     	}
201     	FixPerRegisters(task);
202     	return(0);
203     }
204     
205     /*
206      * Called by kernel/ptrace.c when detaching..
207      *
208      * Make sure single step bits etc are not set.
209      */
210     void ptrace_disable(struct task_struct *child)
211     {
212     	/* make sure the single step bit is not set. */
213     	clear_single_step(child);
214     }
215     
216     asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
217     {
218     	struct task_struct *child;
219     	int ret = -EPERM;
220     	unsigned long flags;
221     	unsigned long tmp;
222     	int copied;
223     	ptrace_area   parea; 
224     
225     	lock_kernel();
226     	if (request == PTRACE_TRACEME) 
227     	{
228     		/* are we already being traced? */
229     		if (current->ptrace & PT_PTRACED)
230     			goto out;
231     		/* set the ptrace bit in the process flags. */
232     		current->ptrace |= PT_PTRACED;
233     		ret = 0;
234     		goto out;
235     	}
236     	ret = -ESRCH;
237     	read_lock(&tasklist_lock);
238     	child = find_task_by_pid(pid);
239     	read_unlock(&tasklist_lock);
240     	if (!child)
241     		goto out;
242     	ret = -EPERM;
243     	if (pid == 1)		/* you may not mess with init */
244     		goto out;
245     	if (request == PTRACE_ATTACH) 
246     	{
247     		ret = ptrace_attach(child);
248     		goto out;
249     	}
250     	ret = -ESRCH;
251     	// printk("child=%lX child->flags=%lX",child,child->flags);
252     	/* I added child!=current line so we can get the */
253     	/* ieee_instruction_pointer from the user structure DJB */
254     	if(child!=current)
255     	{
256     		if (!(child->ptrace & PT_PTRACED))
257     			goto out;
258     		if (child->state != TASK_STOPPED) 
259     		{
260     			if (request != PTRACE_KILL)
261     				goto out;
262     		}
263     		if (child->p_pptr != current)
264     			goto out;
265     	}
266     	switch (request) 
267     	{
268     		/* If I and D space are separate, these will need to be fixed. */
269     	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
270     	case PTRACE_PEEKDATA: 
271     		copied = access_process_vm(child,ADDR_BITS_REMOVE(addr), &tmp, sizeof(tmp), 0);
272     		ret = -EIO;
273     		if (copied != sizeof(tmp))
274     			goto out;
275     		ret = put_user(tmp,(unsigned long *) data);
276     		goto out;
277     
278     		/* read the word at location addr in the USER area. */
279     	case PTRACE_PEEKUSR:
280     		ret=copy_user(child,addr,data,sizeof(unsigned long),1,0);
281     		break;
282     
283     		/* If I and D space are separate, this will have to be fixed. */
284     	case PTRACE_POKETEXT: /* write the word at location addr. */
285     	case PTRACE_POKEDATA:
286     		ret = 0;
287     		if (access_process_vm(child,ADDR_BITS_REMOVE(addr), &data, sizeof(data), 1) == sizeof(data))
288     			goto out;
289     		ret = -EIO;
290     		goto out;
291     		break;
292     
293     	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
294     		ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1);
295     		break;
296     
297     	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
298     	case PTRACE_CONT: 	 /* restart after signal. */
299     		ret = -EIO;
300     		if ((unsigned long) data >= _NSIG)
301     			break;
302     		if (request == PTRACE_SYSCALL)
303     			child->ptrace |= PT_TRACESYS;
304     		else
305     			child->ptrace &= ~PT_TRACESYS;
306     		child->exit_code = data;
307     		/* make sure the single step bit is not set. */
308     		clear_single_step(child);
309     		wake_up_process(child);
310     		ret = 0;
311     		break;
312     
313     /*
314      * make the child exit.  Best I can do is send it a sigkill. 
315      * perhaps it should be put in the status that it wants to 
316      * exit.
317      */
318     	case PTRACE_KILL:
319     		ret = 0;
320     		if (child->state == TASK_ZOMBIE) /* already dead */
321     			break;
322     		child->exit_code = SIGKILL;
323     		clear_single_step(child);
324     		wake_up_process(child);
325     		/* make sure the single step bit is not set. */
326     		break;
327     
328     	case PTRACE_SINGLESTEP:  /* set the trap flag. */
329     		ret = -EIO;
330     		if ((unsigned long) data >= _NSIG)
331     			break;
332     		child->ptrace &= ~PT_TRACESYS;
333     		child->exit_code = data;
334     		set_single_step(child);
335     		/* give it a chance to run. */
336     		wake_up_process(child);
337     		ret = 0;
338     		break;
339     
340     	case PTRACE_DETACH:  /* detach a process that was attached. */
341     		ret = ptrace_detach(child, data);
342     		break;
343     	case PTRACE_PEEKUSR_AREA:
344     	case PTRACE_POKEUSR_AREA:
345     		if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
346     		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
347     				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
348     		break;
349     	default:
350     		ret = -EIO;
351     		break;
352     	}
353      out:
354     	unlock_kernel();
355     	return ret;
356     }
357     
358     asmlinkage void syscall_trace(void)
359     {
360     	lock_kernel();
361     	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
362     	    != (PT_PTRACED|PT_TRACESYS))
363     		goto out;
364     	current->exit_code = SIGTRAP;
365     	set_current_state(TASK_STOPPED);
366     	notify_parent(current, SIGCHLD);
367     	schedule();
368     	/*
369     	 * this isn't the same as continuing with a signal, but it will do
370     	 * for normal use.  strace only continues with a signal if the
371     	 * stopping signal is not SIGTRAP.  -brl
372     	 */
373     	if (current->exit_code) {
374     		send_sig(current->exit_code, current, 1);
375     		current->exit_code = 0;
376     	}
377      out:
378     	unlock_kernel();
379     }
380