OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [s390x/] [kernel/] [ptrace.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.