1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
48void 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
75
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
86void 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;
91 FixPerRegisters (task);
92}
93
94void 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
102int 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
146typedef struct
147{
148 __u32 cr[3];
149} per_cr_words32 __attribute__((packed));
150
151typedef struct
152{
153 __u16 perc_atmid;
154 __u32 address;
155 __u8 access_id;
156} per_lowcore_words32 __attribute__((packed));
157
158typedef struct
159{
160 union {
161 per_cr_words32 words;
162 } control_regs __attribute__((packed));
163
164
165
166
167
168 unsigned single_step : 1;
169 unsigned instruction_fetch : 1;
170 unsigned : 30;
171
172
173
174
175 __u32 starting_addr;
176 __u32 ending_addr;
177 union {
178 per_lowcore_words32 words;
179 } lowcore;
180} per_struct32 __attribute__((packed));
181
182struct 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
191
192
193
194 per_struct32 per_info;
195 u32 ieee_instruction_pointer;
196
197};
198
199struct user32 {
200
201
202 struct user_regs_struct32 regs;
203
204 u32 u_tsize;
205 u32 u_dsize;
206 u32 u_ssize;
207 u32 start_code;
208 u32 start_stack;
209
210
211
212 s32 signal;
213 u32 u_ar0;
214
215 u32 magic;
216 char u_comm[32];
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
242
243int 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
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
365
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
404
405
406
407void ptrace_disable(struct task_struct *child)
408{
409
410 clear_single_step(child);
411}
412
413typedef struct
414{
415__u32 len;
416__u32 kernel_addr;
417__u32 process_addr;
418} ptrace_area_emu31;
419
420
421asmlinkage 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
438 if (current->ptrace & PT_PTRACED)
439 goto out;
440
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)
455 goto out_tsk;
456 if (request == PTRACE_ATTACH)
457 {
458 ret = ptrace_attach(child);
459 goto out_tsk;
460 }
461 ret = -ESRCH;
462
463
464
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
485 case PTRACE_PEEKTEXT:
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
499 case PTRACE_PEEKUSR:
500 ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
501 break;
502
503
504 case PTRACE_POKETEXT:
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:
513 ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
514 break;
515
516 case PTRACE_SYSCALL:
517 case PTRACE_CONT:
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
527 clear_single_step(child);
528 wake_up_process(child);
529 ret = 0;
530 break;
531
532
533
534
535
536
537 case PTRACE_KILL:
538 ret = 0;
539 if (child->state == TASK_ZOMBIE)
540 break;
541 child->exit_code = SIGKILL;
542 clear_single_step(child);
543 wake_up_process(child);
544
545 break;
546
547 case PTRACE_SINGLESTEP:
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
555 wake_up_process(child);
556 ret = 0;
557 break;
558
559 case PTRACE_DETACH:
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
595asmlinkage 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
607
608
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}
617