import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / 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 #ifdef CONFIG_S390_SUPPORT
42 #include "linux32.h"
43 #else
44 #define parent_31bit 0
45 #endif
46
47
48 void FixPerRegisters(struct task_struct *task)
49 {
50         struct pt_regs *regs = __KSTK_PTREGS(task);
51         per_struct *per_info=
52                         (per_struct *)&task->thread.per_info;
53
54         per_info->control_regs.bits.em_instruction_fetch =
55                 per_info->single_step | per_info->instruction_fetch;
56         
57         if (per_info->single_step) {
58                 per_info->control_regs.bits.starting_addr=0;
59 #ifdef CONFIG_S390_SUPPORT
60                 if (current->thread.flags & S390_FLAG_31BIT) {
61                         per_info->control_regs.bits.ending_addr=0x7fffffffUL;
62                 }
63                 else 
64 #endif      
65                 {
66                 per_info->control_regs.bits.ending_addr=-1L;
67                 }
68         } else {
69                 per_info->control_regs.bits.starting_addr=
70                         per_info->starting_addr;
71                 per_info->control_regs.bits.ending_addr=
72                         per_info->ending_addr;
73         }
74         /* if any of the control reg tracing bits are on 
75            we switch on per in the psw */
76         if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
77                 regs->psw.mask |= PSW_PER_MASK;
78         else
79                 regs->psw.mask &= ~PSW_PER_MASK;
80         if (per_info->control_regs.bits.storage_alt_space_ctl)
81                 task->thread.user_seg |= USER_STD_MASK;
82         else
83                 task->thread.user_seg &= ~USER_STD_MASK;
84 }
85
86 void set_single_step(struct task_struct *task)
87 {
88         per_struct *per_info= (per_struct *) &task->thread.per_info;    
89         
90         per_info->single_step = 1;  /* Single step */
91         FixPerRegisters (task);
92 }
93
94 void clear_single_step(struct task_struct *task)
95 {
96         per_struct *per_info= (per_struct *) &task->thread.per_info;
97
98         per_info->single_step = 0;
99         FixPerRegisters (task);
100 }
101
102 int ptrace_usercopy(addr_t realuseraddr, addr_t copyaddr, int len,
103                     int tofromuser, int writeuser, unsigned long mask)
104 {
105         unsigned long *realuserptr, *copyptr;
106         unsigned long tempuser;
107         int retval;
108
109         retval = 0;
110         realuserptr = (unsigned long *) realuseraddr;
111         copyptr = (unsigned long *) copyaddr;
112
113         if (writeuser && realuserptr == NULL)
114                 return 0;
115
116         if (mask != -1L) {
117                 tempuser = *realuserptr;
118                 if (!writeuser) {
119                         tempuser &= mask;
120                         realuserptr = &tempuser;
121                 }
122         }
123         if (tofromuser) {
124                 if (writeuser) {
125                         retval = copy_from_user(realuserptr, copyptr, len);
126                 } else {
127                         if (realuserptr == NULL)
128                                 retval = clear_user(copyptr, len);
129                         else
130                                 retval = copy_to_user(copyptr,realuserptr,len);
131                 }      
132                 retval = retval ? -EFAULT : 0;
133         } else {
134                 if (writeuser)
135                         memcpy(realuserptr, copyptr, len);
136                 else
137                         memcpy(copyptr, realuserptr, len);
138         }
139         if (mask != -1L && writeuser)
140                 *realuserptr = (*realuserptr & mask) | (tempuser & ~mask);
141         return retval;
142 }
143
144 #ifdef CONFIG_S390_SUPPORT
145
146 typedef struct
147 {
148         __u32 cr[3];
149 } per_cr_words32  __attribute__((packed));
150
151 typedef struct
152 {
153         __u16          perc_atmid;          /* 0x096 */
154         __u32          address;             /* 0x098 */
155         __u8           access_id;           /* 0x0a1 */
156 } per_lowcore_words32  __attribute__((packed));
157
158 typedef struct
159 {
160         union {
161                 per_cr_words32   words;
162         } control_regs  __attribute__((packed));
163         /*
164          * Use these flags instead of setting em_instruction_fetch
165          * directly they are used so that single stepping can be
166          * switched on & off while not affecting other tracing
167          */
168         unsigned  single_step       : 1;
169         unsigned  instruction_fetch : 1;
170         unsigned                    : 30;
171         /*
172          * These addresses are copied into cr10 & cr11 if single
173          * stepping is switched off
174          */
175         __u32     starting_addr;
176         __u32     ending_addr;
177         union {
178                 per_lowcore_words32 words;
179         } lowcore; 
180 } per_struct32 __attribute__((packed));
181
182 struct user_regs_struct32
183 {
184         _psw_t32 psw;
185         u32 gprs[NUM_GPRS];
186         u32 acrs[NUM_ACRS];
187         u32 orig_gpr2;
188         s390_fp_regs fp_regs;
189         /*
190          * These per registers are in here so that gdb can modify them
191          * itself as there is no "official" ptrace interface for hardware
192          * watchpoints. This is the way intel does it.
193          */
194         per_struct32 per_info;
195         u32  ieee_instruction_pointer; 
196         /* Used to give failing instruction back to user for ieee exceptions */
197 };
198
199 struct user32 {
200                                   /* We start with the registers, to mimic the way that "memory" is returned
201                                    from the ptrace(3,...) function.  */
202   struct user_regs_struct32 regs; /* Where the registers are actually stored */
203                                   /* The rest of this junk is to help gdb figure out what goes where */
204   u32 u_tsize;                    /* Text segment size (pages). */
205   u32 u_dsize;                    /* Data segment size (pages). */
206   u32 u_ssize;                    /* Stack segment size (pages). */
207   u32 start_code;                 /* Starting virtual address of text. */
208   u32 start_stack;                /* Starting virtual address of stack area.
209                                    This is actually the bottom of the stack,
210                                    the top of the stack is always found in the
211                                    esp register.  */
212   s32 signal;                     /* Signal that caused the core dump. */
213   u32 u_ar0;                      /* Used by gdb to help find the values for */
214                                   /* the registers. */
215   u32 magic;                      /* To uniquely identify a core file */
216   char u_comm[32];                /* User command that was responsible */
217 };
218
219
220 #define PT32_PSWMASK  0x0
221 #define PT32_PSWADDR  0x04
222 #define PT32_GPR0     0x08
223 #define PT32_GPR15    0x44
224 #define PT32_ACR0     0x48
225 #define PT32_ACR15    0x84
226 #define PT32_ORIGGPR2 0x88
227 #define PT32_FPC      0x90
228 #define PT32_FPR0_HI  0x98
229 #define PT32_FPR15_LO 0x114
230 #define PT32_CR_9     0x118
231 #define PT32_CR_11    0x120
232 #define PT32_IEEE_IP  0x13C
233 #define PT32_LASTOFF  PT32_IEEE_IP
234 #define PT32_ENDREGS  0x140-1
235 #define U32OFFSETOF(member) offsetof(struct user32,regs.member)
236 #define U64OFFSETOF(member) offsetof(struct user,regs.member)
237 #define U6432DIFF(member) (U64OFFSETOF(member) - U32OFFSETOF(member))
238 #define PT_SINGLE_STEP   (PT_CR_11+8)
239 #define PT32_SINGLE_STEP (PT32_CR_11+4)
240
241 #endif /* CONFIG_S390_SUPPORT */
242
243 int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
244               int len, int tofromuser, int writingtouser)
245 {
246         int copylen=0,copymax;
247         addr_t  realuseraddr;
248         saddr_t enduseraddr;
249         unsigned long mask;
250 #ifdef CONFIG_S390_SUPPORT
251         int     parent_31bit=current->thread.flags & S390_FLAG_31BIT;
252         int     skip;
253 #endif
254         enduseraddr=useraddr+len;
255         if ((useraddr<0||useraddr&3||enduseraddr&3)||
256 #ifdef CONFIG_S390_SUPPORT
257             (parent_31bit && enduseraddr > sizeof(struct user32)) ||
258 #endif
259             enduseraddr > sizeof(struct user))
260                 return (-EIO);
261
262 #ifdef CONFIG_S390_SUPPORT
263         if(parent_31bit)
264         {
265                 if(useraddr != PT32_PSWMASK)
266                 {
267                         if (useraddr == PT32_PSWADDR)
268                                 useraddr = PT_PSWADDR+4;
269                         else if(useraddr <= PT32_GPR15)
270                                 useraddr = ((useraddr-PT32_GPR0)*2) + PT_GPR0+4;
271                         else if(useraddr <= PT32_ACR15)
272                                 useraddr += PT_ACR0-PT32_ACR0;
273                         else if(useraddr == PT32_ORIGGPR2)
274                                 useraddr = PT_ORIGGPR2+4;
275                         else if(useraddr <= PT32_FPR15_LO)
276                                 useraddr += PT_FPR0-PT32_FPR0_HI;
277                         else if(useraddr <= PT32_CR_11)
278                                 useraddr = ((useraddr-PT32_CR_9)*2) + PT_CR_9+4;
279                         else if(useraddr ==  PT32_SINGLE_STEP)
280                                 useraddr = PT_SINGLE_STEP; 
281                         else if(useraddr <= U32OFFSETOF(per_info.ending_addr))  
282                                 useraddr = (((useraddr-U32OFFSETOF(per_info.starting_addr)))*2) + 
283                                         U64OFFSETOF(per_info.starting_addr)+4;
284                         else if( useraddr == U32OFFSETOF(per_info.lowcore.words.perc_atmid))
285                                 useraddr = U64OFFSETOF(per_info.lowcore.words.perc_atmid);
286                         else if( useraddr == U32OFFSETOF(per_info.lowcore.words.address))
287                                 useraddr = U64OFFSETOF(per_info.lowcore.words.address)+4;
288                         else if(useraddr == U32OFFSETOF(per_info.lowcore.words.access_id))
289                                 useraddr = U64OFFSETOF(per_info.lowcore.words.access_id);
290                         else if(useraddr == PT32_IEEE_IP)
291                                 useraddr = PT_IEEE_IP+4;
292                 }
293         }
294 #endif /* CONFIG_S390_SUPPORT */
295
296         while(len>0)
297         {
298 #ifdef CONFIG_S390_SUPPORT
299                 skip=0;
300 #endif
301                 mask=PSW_ADDR_MASK;
302                 if(useraddr<PT_FPC)
303                 {
304                         realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
305                         if(useraddr<(PT_PSWMASK+8))
306                         {
307                                 if(parent_31bit)
308                                 {
309                                         copymax=PT_PSWMASK+4;
310 #ifdef CONFIG_S390_SUPPORT
311                                         skip=8;
312 #endif
313                                 }
314                                 else
315                                 {
316                                         copymax=PT_PSWMASK+8;
317                                 }
318                                 if(writingtouser)
319                                         mask=PSW_MASK_DEBUGCHANGE;
320                         }
321                         else if(useraddr<(PT_PSWADDR+8))
322                         {
323                                 copymax=PT_PSWADDR+8;
324                                 mask=PSW_ADDR_DEBUGCHANGE;
325 #ifdef CONFIG_S390_SUPPORT
326                                 if(parent_31bit)
327                                         skip=4;
328 #endif
329
330                         }
331                         else
332                         {
333 #ifdef CONFIG_S390_SUPPORT
334                                 if(parent_31bit && useraddr <= PT_GPR15+4)
335                                 {
336                                         copymax=useraddr+4;
337                                         if(useraddr<PT_GPR15+4)
338                                                 skip=4;
339                                 }
340                                 else
341 #endif
342                                         copymax=PT_FPC;
343                         }
344                 }
345                 else if(useraddr<(PT_FPR15+sizeof(freg_t)))
346                 {
347                         copymax=(PT_FPR15+sizeof(freg_t));
348                         realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
349                 }
350                 else if(useraddr<sizeof(struct user_regs_struct))
351                 {
352 #ifdef CONFIG_S390_SUPPORT
353                         if( parent_31bit && useraddr <= PT_IEEE_IP+4)
354                         {
355                                 switch(useraddr)
356                                 {
357                                 case PT_CR_11+4:
358                                 case U64OFFSETOF(per_info.ending_addr)+4:
359                                 case U64OFFSETOF(per_info.lowcore.words.address)+4:
360                                         copymax=useraddr+4;
361                                         break;
362                                 case  PT_SINGLE_STEP:
363                                 case  U64OFFSETOF(per_info.lowcore.words.perc_atmid):
364                                         /* We copy 2 bytes in excess for the atmid member this also gets around */
365                                         /* alignment for this member in 32 bit */
366                                         skip=8;
367                                         copymax=useraddr+4;
368                                         break;
369                                 default: 
370                                         copymax=useraddr+4;
371                                         skip=4;
372                                 }
373                         }
374                         else
375 #endif
376                         {
377                                 copymax=sizeof(struct user_regs_struct);
378                         }
379                         realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
380                 }
381                 else 
382                 {
383                         copymax=sizeof(struct user);
384                         realuseraddr=(addr_t)NULL;
385                 }
386                 copylen=copymax-useraddr;
387                 copylen=(copylen>len ? len:copylen);
388                 if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
389                         return (-EIO);
390                 copyaddr+=copylen;
391                 len-=copylen;
392                 useraddr+=copylen
393 #if CONFIG_S390_SUPPORT
394                         +skip
395 #endif
396                         ;
397         }
398         FixPerRegisters(task);
399         return(0);
400 }
401
402 /*
403  * Called by kernel/ptrace.c when detaching..
404  *
405  * Make sure single step bits etc are not set.
406  */
407 void ptrace_disable(struct task_struct *child)
408 {
409         /* make sure the single step bit is not set. */
410         clear_single_step(child);
411 }
412
413 typedef struct
414 {
415 __u32   len;
416 __u32   kernel_addr;
417 __u32   process_addr;
418 } ptrace_area_emu31;
419
420
421 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
422 {
423         struct task_struct *child;
424         int ret = -EPERM;
425         int copied;
426 #ifdef CONFIG_S390_SUPPORT
427         int           parent_31bit;
428         int           sizeof_parent_long;
429         u8            *dataptr;
430 #else
431 #define sizeof_parent_long 8
432 #define dataptr (u8 *)&data
433 #endif
434         lock_kernel();
435         if (request == PTRACE_TRACEME) 
436         {
437                 /* are we already being traced? */
438                 if (current->ptrace & PT_PTRACED)
439                         goto out;
440                 /* set the ptrace bit in the process flags. */
441                 current->ptrace |= PT_PTRACED;
442                 ret = 0;
443                 goto out;
444         }
445         ret = -ESRCH;
446         read_lock(&tasklist_lock);
447         child = find_task_by_pid(pid);
448         if (child)
449                 get_task_struct(child);
450         read_unlock(&tasklist_lock);
451         if (!child)
452                 goto out;
453         ret = -EPERM;
454         if (pid == 1)           /* you may not mess with init */
455                 goto out_tsk;
456         if (request == PTRACE_ATTACH) 
457         {
458                 ret = ptrace_attach(child);
459                 goto out_tsk;
460         }
461         ret = -ESRCH;
462         // printk("child=%lX child->flags=%lX",child,child->flags);
463         /* I added child!=current line so we can get the */
464         /* ieee_instruction_pointer from the user structure DJB */
465         if(child!=current)
466         {
467                 if (!(child->ptrace & PT_PTRACED))
468                         goto out_tsk;
469                 if (child->state != TASK_STOPPED) 
470                 {
471                         if (request != PTRACE_KILL)
472                                 goto out_tsk;
473                 }
474                 if (child->p_pptr != current)
475                         goto out_tsk;
476         }
477 #ifdef CONFIG_S390_SUPPORT
478         parent_31bit=(current->thread.flags & S390_FLAG_31BIT);
479         sizeof_parent_long=(parent_31bit ? 4:8);
480         dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);
481 #endif
482         switch (request) 
483         {
484                 /* If I and D space are separate, these will need to be fixed. */
485         case PTRACE_PEEKTEXT: /* read word at location addr. */ 
486         case PTRACE_PEEKDATA: 
487         {
488                 u8 tmp[8];
489                 copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0);
490                 ret = -EIO;
491                 if (copied != sizeof_parent_long)
492                         break;
493                 ret = copy_to_user((void *)data,tmp,sizeof_parent_long);
494                 ret = ret ? -EFAULT : 0;
495                 break;
496         
497         }
498                 /* read the word at location addr in the USER area. */
499         case PTRACE_PEEKUSR:
500                 ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
501                 break;
502
503                 /* If I and D space are separate, this will have to be fixed. */
504         case PTRACE_POKETEXT: /* write the word at location addr. */
505         case PTRACE_POKEDATA:
506                 ret = 0;
507                 if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long)
508                         break;
509                 ret = -EIO;
510                 break;
511
512         case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
513                 ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
514                 break;
515
516         case PTRACE_SYSCALL:    /* continue and stop at next (return from) syscall */
517         case PTRACE_CONT:        /* restart after signal. */
518                 ret = -EIO;
519                 if ((unsigned long) data >= _NSIG)
520                         break;
521                 if (request == PTRACE_SYSCALL)
522                         child->ptrace |= PT_TRACESYS;
523                 else
524                         child->ptrace &= ~PT_TRACESYS;
525                 child->exit_code = data;
526                 /* make sure the single step bit is not set. */
527                 clear_single_step(child);
528                 wake_up_process(child);
529                 ret = 0;
530                 break;
531
532 /*
533  * make the child exit.  Best I can do is send it a sigkill. 
534  * perhaps it should be put in the status that it wants to 
535  * exit.
536  */
537         case PTRACE_KILL:
538                 ret = 0;
539                 if (child->state == TASK_ZOMBIE) /* already dead */
540                         break;
541                 child->exit_code = SIGKILL;
542                 clear_single_step(child);
543                 wake_up_process(child);
544                 /* make sure the single step bit is not set. */
545                 break;
546
547         case PTRACE_SINGLESTEP:  /* set the trap flag. */
548                 ret = -EIO;
549                 if ((unsigned long) data >= _NSIG)
550                         break;
551                 child->ptrace &= ~PT_TRACESYS;
552                 child->exit_code = data;
553                 set_single_step(child);
554                 /* give it a chance to run. */
555                 wake_up_process(child);
556                 ret = 0;
557                 break;
558
559         case PTRACE_DETACH:  /* detach a process that was attached. */
560                 ret = ptrace_detach(child, data);
561                 break;
562
563         case PTRACE_PEEKUSR_AREA:
564         case PTRACE_POKEUSR_AREA:
565                 if(parent_31bit)
566                 {
567                         ptrace_area_emu31   parea; 
568                         if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
569                                 ret=copy_user(child,parea.kernel_addr,parea.process_addr,
570                                               parea.len,1,(request==PTRACE_POKEUSR_AREA));
571                         else ret = -EFAULT;
572                 }
573                 else
574                 {
575                         ptrace_area   parea; 
576                         if(copy_from_user(&parea,(void *)addr,sizeof(parea))==0)
577                                 ret=copy_user(child,parea.kernel_addr,parea.process_addr,
578                                               parea.len,1,(request==PTRACE_POKEUSR_AREA));
579                         else ret = -EFAULT;
580                 }
581                 break;
582         default:
583                 ret = -EIO;
584                 break;
585         }
586  out_tsk:
587         free_task_struct(child);
588  out:
589         unlock_kernel();
590         return ret;
591 }
592
593
594
595 asmlinkage void syscall_trace(void)
596 {
597         lock_kernel();
598         if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
599             != (PT_PTRACED|PT_TRACESYS))
600                 goto out;
601         current->exit_code = SIGTRAP;
602         set_current_state(TASK_STOPPED);
603         notify_parent(current, SIGCHLD);
604         schedule();
605         /*
606          * this isn't the same as continuing with a signal, but it will do
607          * for normal use.  strace only continues with a signal if the
608          * stopping signal is not SIGTRAP.  -brl
609          */
610         if (current->exit_code) {
611                 send_sig(current->exit_code, current, 1);
612                 current->exit_code = 0;
613         }
614  out:
615         unlock_kernel();
616 }