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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [sparc/] [kernel/] [ptrace.c] - Blame information for rev 1624

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1624 jcastillo
/* ptrace.c: Sparc process tracing support.
2
 *
3
 * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
4
 *
5
 * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
6
 * and David Mosberger.
7
 */
8
 
9
#include <linux/kernel.h>
10
#include <linux/sched.h>
11
#include <linux/mm.h>
12
#include <linux/errno.h>
13
#include <linux/ptrace.h>
14
#include <linux/user.h>
15
 
16
#include <asm/pgtable.h>
17
#include <asm/system.h>
18
 
19
/* change a pid into a task struct. */
20
static inline struct task_struct * get_task(int pid)
21
{
22
        int i;
23
 
24
        for (i = 1; i < NR_TASKS; i++) {
25
                if (task[i] != NULL && (task[i]->pid == pid))
26
                        return task[i];
27
        }
28
        return NULL;
29
}
30
 
31
/*
32
 * This routine gets a long from any process space by following the page
33
 * tables. NOTE! You should check that the long isn't on a page boundary,
34
 * and that it is in the task area before calling this: this routine does
35
 * no checking.
36
 */
37
static unsigned long get_long(struct task_struct * tsk,
38
        struct vm_area_struct * vma, unsigned long addr)
39
{
40
        pgd_t * pgdir;
41
        pmd_t * pgmiddle;
42
        pte_t * pgtable;
43
        unsigned long page, retval;
44
 
45
repeat:
46
        pgdir = pgd_offset(vma->vm_mm, addr);
47
        if (pgd_none(*pgdir)) {
48
                do_no_page(tsk, vma, addr, 0);
49
                goto repeat;
50
        }
51
        if (pgd_bad(*pgdir)) {
52
                printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
53
                pgd_clear(pgdir);
54
                return 0;
55
        }
56
        pgmiddle = pmd_offset(pgdir, addr);
57
        if (pmd_none(*pgmiddle)) {
58
                do_no_page(tsk, vma, addr, 0);
59
                goto repeat;
60
        }
61
        if (pmd_bad(*pgmiddle)) {
62
                printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
63
                pmd_clear(pgmiddle);
64
                return 0;
65
        }
66
        pgtable = pte_offset(pgmiddle, addr);
67
        if (!pte_present(*pgtable)) {
68
                do_no_page(tsk, vma, addr, 0);
69
                goto repeat;
70
        }
71
        page = pte_page(*pgtable);
72
/* this is a hack for non-kernel-mapped video buffers and similar */
73
        if (page >= high_memory)
74
                return 0;
75
        page += addr & ~PAGE_MASK;
76
        retval = *(unsigned long *) page;
77
        flush_page_to_ram(page);
78
        return retval;
79
}
80
 
81
/*
82
 * This routine puts a long into any process space by following the page
83
 * tables. NOTE! You should check that the long isn't on a page boundary,
84
 * and that it is in the task area before calling this: this routine does
85
 * no checking.
86
 *
87
 * Now keeps R/W state of page so that a text page stays readonly
88
 * even if a debugger scribbles breakpoints into it.  -M.U-
89
 */
90
static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
91
        unsigned long addr, unsigned long data)
92
{
93
        pgd_t *pgdir;
94
        pmd_t *pgmiddle;
95
        pte_t *pgtable;
96
        unsigned long page;
97
 
98
repeat:
99
        pgdir = pgd_offset(vma->vm_mm, addr);
100
        if (!pgd_present(*pgdir)) {
101
                do_no_page(tsk, vma, addr, 1);
102
                goto repeat;
103
        }
104
        if (pgd_bad(*pgdir)) {
105
                printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
106
                pgd_clear(pgdir);
107
                return;
108
        }
109
        pgmiddle = pmd_offset(pgdir, addr);
110
        if (pmd_none(*pgmiddle)) {
111
                do_no_page(tsk, vma, addr, 1);
112
                goto repeat;
113
        }
114
        if (pmd_bad(*pgmiddle)) {
115
                printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
116
                pmd_clear(pgmiddle);
117
                return;
118
        }
119
        pgtable = pte_offset(pgmiddle, addr);
120
        if (!pte_present(*pgtable)) {
121
                do_no_page(tsk, vma, addr, 1);
122
                goto repeat;
123
        }
124
        page = pte_page(*pgtable);
125
        if (!pte_write(*pgtable)) {
126
                do_wp_page(tsk, vma, addr, 1);
127
                goto repeat;
128
        }
129
/* this is a hack for non-kernel-mapped video buffers and similar */
130
        flush_cache_page(vma, page);
131
        if (page < high_memory) {
132
                *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
133
                flush_page_to_ram(page);
134
        }
135
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
136
/* this should also re-instate whatever read-only mode there was before */
137
        set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
138
        flush_tlb_page(vma, page);
139
}
140
 
141
static struct vm_area_struct * find_extend_vma(struct task_struct * tsk,
142
                                               unsigned long addr)
143
{
144
        struct vm_area_struct * vma;
145
 
146
        addr &= PAGE_MASK;
147
        vma = find_vma(tsk,addr);
148
        if (!vma)
149
                return NULL;
150
        if (vma->vm_start <= addr)
151
                return vma;
152
        if (!(vma->vm_flags & VM_GROWSDOWN))
153
                return NULL;
154
        if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
155
                return NULL;
156
        vma->vm_offset -= vma->vm_start - addr;
157
        vma->vm_start = addr;
158
        return vma;
159
}
160
 
161
/*
162
 * This routine checks the page boundaries, and that the offset is
163
 * within the task area. It then calls get_long() to read a long.
164
 */
165
static int read_long(struct task_struct * tsk, unsigned long addr,
166
                     unsigned long * result)
167
{
168
        struct vm_area_struct * vma = find_extend_vma(tsk, addr);
169
 
170
        if (!vma)
171
                return -EIO;
172
        *result = get_long(tsk, vma, addr);
173
        return 0;
174
}
175
 
176
static int read_byte(struct task_struct *tsk, unsigned long addr,
177
                     unsigned char *result)
178
{
179
        struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3);
180
        unsigned long tmp;
181
 
182
        if(!vma)
183
                return -EIO;
184
        tmp = get_long(tsk, vma, (addr & ~3));
185
        switch(addr & 3) {
186
        case 0:
187
                *result = (tmp & 0xff000000)>>24;
188
                break;
189
        case 1:
190
                *result = (tmp & 0x00ff0000)>>16;
191
                break;
192
        case 2:
193
                *result = (tmp & 0x0000ff00)>>8;
194
                break;
195
        case 3:
196
                *result = (tmp & 0x000000ff);
197
                break;
198
        }
199
        return 0;
200
}
201
 
202
/*
203
 * This routine checks the page boundaries, and that the offset is
204
 * within the task area. It then calls put_long() to write a long.
205
 */
206
static int write_long(struct task_struct * tsk, unsigned long addr,
207
                      unsigned long data)
208
{
209
        struct vm_area_struct * vma = find_extend_vma(tsk, addr);
210
 
211
        if (!vma)
212
                return -EIO;
213
        put_long(tsk, vma, addr, data);
214
        return 0;
215
}
216
 
217
static int write_byte(struct task_struct * tsk, unsigned long addr,
218
                      unsigned char data)
219
{
220
        struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3));
221
        unsigned long tmp;
222
 
223
        if (!vma)
224
                return -EIO;
225
        tmp = get_long(tsk, vma, (addr & ~3));
226
        switch(addr & 3) {
227
        case 0:
228
                tmp &= 0x00ffffff;
229
                tmp |= (data << 24);
230
                break;
231
        case 1:
232
                tmp &= 0xff00ffff;
233
                tmp |= ((data << 16) & 0x00ff0000);
234
                break;
235
        case 2:
236
                tmp &= 0xffff00ff;
237
                tmp |= ((data << 8) & 0x0000ff00);
238
                break;
239
        case 3:
240
                tmp &= 0xffffff00;
241
                tmp |= (data & 0x000000ff);
242
                break;
243
        }
244
        put_long(tsk, vma, (addr & ~3), tmp);
245
        return 0;
246
}
247
 
248
/* Returning from ptrace is a bit tricky because the syscall return
249
 * low level code assumes any value returned which is negative and
250
 * is a valid errno will mean setting the condition codes to indicate
251
 * an error return.  This doesn't work, so we have this hook.
252
 */
253
static inline void pt_error_return(struct pt_regs *regs, unsigned long error)
254
{
255
        regs->u_regs[UREG_I0] = error;
256
        regs->psr |= PSR_C;
257
        regs->pc = regs->npc;
258
        regs->npc += 4;
259
}
260
 
261
static inline void pt_succ_return(struct pt_regs *regs, unsigned long value)
262
{
263
        regs->u_regs[UREG_I0] = value;
264
        regs->psr &= ~PSR_C;
265
        regs->pc = regs->npc;
266
        regs->npc += 4;
267
}
268
 
269
/* Fuck me gently with a chainsaw... */
270
static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset,
271
                                   struct task_struct *tsk)
272
{
273
        struct pt_regs *cregs = tsk->tss.kregs;
274
        struct thread_struct *t = &tsk->tss;
275
 
276
        if(offset >= 1024)
277
                offset -= 1024; /* whee... */
278
        if(offset & ((sizeof(unsigned long) - 1))) {
279
                pt_error_return(regs, EIO);
280
                return;
281
        }
282
        if(offset >= 16 && offset < 784) {
283
                offset -= 16; offset >>= 2;
284
                pt_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset));
285
                return;
286
        }
287
        if(offset >= 784 && offset < 832) {
288
                offset -= 784; offset >>= 2;
289
                pt_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset));
290
                return;
291
        }
292
        switch(offset) {
293
        case 0:
294
                regs->u_regs[UREG_I0] = t->ksp;
295
                break;
296
        case 4:
297
                regs->u_regs[UREG_I0] = t->kpc;
298
                break;
299
        case 8:
300
                regs->u_regs[UREG_I0] = t->kpsr;
301
                break;
302
        case 12:
303
                regs->u_regs[UREG_I0] = t->uwinmask;
304
                break;
305
        case 832:
306
                regs->u_regs[UREG_I0] = t->w_saved;
307
                break;
308
        case 896:
309
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
310
                break;
311
        case 900:
312
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
313
                break;
314
        case 904:
315
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I2];
316
                break;
317
        case 908:
318
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I3];
319
                break;
320
        case 912:
321
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I4];
322
                break;
323
        case 916:
324
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I5];
325
                break;
326
        case 920:
327
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I6];
328
                break;
329
        case 924:
330
                if(tsk->tss.flags & 0x80000000)
331
                        regs->u_regs[UREG_I0] = cregs->u_regs[UREG_G1];
332
                else
333
                        regs->u_regs[UREG_I0] = 0;
334
                break;
335
        case 940:
336
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0];
337
                break;
338
        case 944:
339
                regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1];
340
                break;
341
 
342
        case 948:
343
                /* Isn't binary compatibility _fun_??? */
344
                if(cregs->psr & PSR_C)
345
                        regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0] << 24;
346
                else
347
                        regs->u_regs[UREG_I0] = 0;
348
                break;
349
 
350
                /* Rest of them are completely unsupported. */
351
        default:
352
                printk("%s [%d]: Wants to read user offset %d\n",
353
                       current->comm, current->pid, offset);
354
                pt_error_return(regs, EIO);
355
                return;
356
        }
357
        regs->psr &= ~PSR_C;
358
        regs->pc = regs->npc;
359
        regs->npc += 4;
360
        return;
361
}
362
 
363
static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset,
364
                                    struct task_struct *tsk)
365
{
366
        struct pt_regs *cregs = tsk->tss.kregs;
367
        struct thread_struct *t = &tsk->tss;
368
        unsigned long value = regs->u_regs[UREG_I3];
369
 
370
        if(offset >= 1024)
371
                offset -= 1024; /* whee... */
372
        if(offset & ((sizeof(unsigned long) - 1)))
373
                goto failure;
374
        if(offset >= 16 && offset < 784) {
375
                offset -= 16; offset >>= 2;
376
                *(((unsigned long *)(&t->reg_window[0]))+offset) = value;
377
                goto success;
378
        }
379
        if(offset >= 784 && offset < 832) {
380
                offset -= 784; offset >>= 2;
381
                *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value;
382
                goto success;
383
        }
384
        switch(offset) {
385
        case 896:
386
                cregs->u_regs[UREG_I0] = value;
387
                break;
388
        case 900:
389
                cregs->u_regs[UREG_I1] = value;
390
                break;
391
        case 904:
392
                cregs->u_regs[UREG_I2] = value;
393
                break;
394
        case 908:
395
                cregs->u_regs[UREG_I3] = value;
396
                break;
397
        case 912:
398
                cregs->u_regs[UREG_I4] = value;
399
                break;
400
        case 916:
401
                cregs->u_regs[UREG_I5] = value;
402
                break;
403
        case 920:
404
                cregs->u_regs[UREG_I6] = value;
405
                break;
406
        case 924:
407
                cregs->u_regs[UREG_I7] = value;
408
                break;
409
        case 940:
410
                cregs->u_regs[UREG_I0] = value;
411
                break;
412
        case 944:
413
                cregs->u_regs[UREG_I1] = value;
414
                break;
415
 
416
                /* Rest of them are completely unsupported or "no-touch". */
417
        default:
418
                printk("%s [%d]: Wants to write user offset %d\n",
419
                       current->comm, current->pid, offset);
420
                goto failure;
421
        }
422
success:
423
        pt_succ_return(regs, 0);
424
        return;
425
failure:
426
        pt_error_return(regs, EIO);
427
        return;
428
}
429
 
430
/* #define ALLOW_INIT_TRACING */
431
/* #define DEBUG_PTRACE */
432
 
433
asmlinkage void do_ptrace(struct pt_regs *regs)
434
{
435
        unsigned long request = regs->u_regs[UREG_I0];
436
        unsigned long pid = regs->u_regs[UREG_I1];
437
        unsigned long addr = regs->u_regs[UREG_I2];
438
        unsigned long data = regs->u_regs[UREG_I3];
439
        unsigned long addr2 = regs->u_regs[UREG_I4];
440
        struct task_struct *child;
441
 
442
#ifdef DEBUG_PTRACE
443
        printk("do_ptrace: rq=%d pid=%d addr=%08lx data=%08lx addr2=%08lx\n",
444
               (int) request, (int) pid, addr, data, addr2);
445
#endif
446
        if(request == PTRACE_TRACEME) {
447
                /* are we already being traced? */
448
                if (current->flags & PF_PTRACED) {
449
                        pt_error_return(regs, EPERM);
450
                        return;
451
                }
452
                /* set the ptrace bit in the process flags. */
453
                current->flags |= PF_PTRACED;
454
                pt_succ_return(regs, 0);
455
                return;
456
        }
457
#ifndef ALLOW_INIT_TRACING
458
        if(pid == 1) {
459
                /* Can't dork with init. */
460
                pt_error_return(regs, EPERM);
461
                return;
462
        }
463
#endif
464
        if(!(child = get_task(pid))) {
465
                pt_error_return(regs, ESRCH);
466
                return;
467
        }
468
 
469
        if(request == PTRACE_SUNATTACH) {
470
                if(child == current) {
471
                        /* Try this under SunOS/Solaris, bwa haha
472
                         * You'll never be able to kill the process. ;-)
473
                         */
474
                        pt_error_return(regs, EPERM);
475
                        return;
476
                }
477
                if((!child->dumpable ||
478
                    (current->uid != child->euid) ||
479
                    (current->uid != child->uid) ||
480
                    (current->gid != child->egid) ||
481
                    (current->gid != child->gid)) && !suser()) {
482
                        pt_error_return(regs, EPERM);
483
                        return;
484
                }
485
                /* the same process cannot be attached many times */
486
                if (child->flags & PF_PTRACED) {
487
                        pt_error_return(regs, EPERM);
488
                        return;
489
                }
490
                child->flags |= PF_PTRACED;
491
                if(child->p_pptr != current) {
492
                        REMOVE_LINKS(child);
493
                        child->p_pptr = current;
494
                        SET_LINKS(child);
495
                }
496
                send_sig(SIGSTOP, child, 1);
497
                pt_succ_return(regs, 0);
498
                return;
499
        }
500
        if(!(child->flags & PF_PTRACED)) {
501
                pt_error_return(regs, ESRCH);
502
                return;
503
        }
504
        if(child->state != TASK_STOPPED) {
505
                if(request != PTRACE_KILL) {
506
                        pt_error_return(regs, ESRCH);
507
                        return;
508
                }
509
        }
510
        if(child->p_pptr != current) {
511
                pt_error_return(regs, ESRCH);
512
                return;
513
        }
514
        switch(request) {
515
        case PTRACE_PEEKTEXT: /* read word at location addr. */
516
        case PTRACE_PEEKDATA: {
517
                unsigned long tmp;
518
                int res;
519
 
520
                /* Non-word alignment _not_ allowed on Sparc. */
521
                if(addr & (sizeof(unsigned long) - 1)) {
522
                        pt_error_return(regs, EINVAL);
523
                        return;
524
                }
525
                res = read_long(child, addr, &tmp);
526
                if (res < 0) {
527
                        pt_error_return(regs, -res);
528
                        return;
529
                }
530
                pt_succ_return(regs, tmp);
531
                return;
532
        }
533
 
534
        case PTRACE_PEEKUSR:
535
                read_sunos_user(regs, addr, child);
536
                return;
537
 
538
        case PTRACE_POKEUSR:
539
                write_sunos_user(regs, addr, child);
540
                return;
541
 
542
        case PTRACE_POKETEXT: /* write the word at location addr. */
543
        case PTRACE_POKEDATA: {
544
                struct vm_area_struct *vma;
545
                int res;
546
 
547
                /* Non-word alignment _not_ allowed on Sparc. */
548
                if(addr & (sizeof(unsigned long) - 1)) {
549
                        pt_error_return(regs, EINVAL);
550
                        return;
551
                }
552
                vma = find_extend_vma(child, addr);
553
                if(vma && request == PTRACE_POKEDATA && (vma->vm_flags & VM_EXEC)) {
554
                        pt_error_return(regs, EIO);
555
                        return;
556
                }
557
                res = write_long(child, addr, data);
558
                if(res < 0)
559
                        pt_error_return(regs, -res);
560
                else
561
                        pt_succ_return(regs, res);
562
                return;
563
        }
564
 
565
        case PTRACE_GETREGS: {
566
                struct pt_regs *pregs = (struct pt_regs *) addr;
567
                struct pt_regs *cregs = child->tss.kregs;
568
                int rval;
569
 
570
                rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs) - 4);
571
                if(rval) {
572
                        pt_error_return(regs, rval);
573
                        return;
574
                }
575
                pregs->psr = cregs->psr;
576
                pregs->pc = cregs->pc;
577
                pregs->npc = cregs->npc;
578
                pregs->y = cregs->y;
579
                for(rval = 1; rval < 16; rval++)
580
                        pregs->u_regs[rval - 1] = cregs->u_regs[rval];
581
                pt_succ_return(regs, 0);
582
                return;
583
        }
584
 
585
        case PTRACE_SETREGS: {
586
                struct pt_regs *pregs = (struct pt_regs *) addr;
587
                struct pt_regs *cregs = child->tss.kregs;
588
                unsigned long psr;
589
                int rval, i;
590
 
591
                rval = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs) - 4);
592
                if(rval) {
593
                        pt_error_return(regs, rval);
594
                        return;
595
                }
596
                /* Must be careful, tracing process can only set certain
597
                 * bits in the psr.
598
                 */
599
                psr = (pregs->psr) & PSR_ICC;
600
                cregs->psr &= ~PSR_ICC;
601
                cregs->psr |= psr;
602
                if(!((pregs->pc | pregs->npc) & 3)) {
603
                        cregs->pc = pregs->pc;
604
                        cregs->npc = pregs->npc;
605
                }
606
                cregs->y = pregs->y;
607
                for(i = 1; i < 16; i++)
608
                        cregs->u_regs[i] = pregs->u_regs[i-1];
609
                pt_succ_return(regs, 0);
610
                return;
611
        }
612
 
613
        case PTRACE_GETFPREGS: {
614
                struct fps {
615
                        unsigned long regs[32];
616
                        unsigned long fsr;
617
                        unsigned long flags;
618
                        unsigned long extra;
619
                        unsigned long fpqd;
620
                        struct fq {
621
                                unsigned long *insnaddr;
622
                                unsigned long insn;
623
                        } fpq[16];
624
                } *fps = (struct fps *) addr;
625
                int rval, i;
626
 
627
                rval = verify_area(VERIFY_WRITE, fps, sizeof(struct fps));
628
                if(rval) { pt_error_return(regs, rval); return; }
629
                for(i = 0; i < 32; i++)
630
                        fps->regs[i] = child->tss.float_regs[i];
631
                fps->fsr = child->tss.fsr;
632
                fps->fpqd = child->tss.fpqdepth;
633
                fps->flags = fps->extra = 0;
634
                for(i = 0; i < 16; i++) {
635
                        fps->fpq[i].insnaddr = child->tss.fpqueue[i].insn_addr;
636
                        fps->fpq[i].insn = child->tss.fpqueue[i].insn;
637
                }
638
                pt_succ_return(regs, 0);
639
                return;
640
        }
641
 
642
        case PTRACE_SETFPREGS: {
643
                struct fps {
644
                        unsigned long regs[32];
645
                        unsigned long fsr;
646
                        unsigned long flags;
647
                        unsigned long extra;
648
                        unsigned long fpqd;
649
                        struct fq {
650
                                unsigned long *insnaddr;
651
                                unsigned long insn;
652
                        } fpq[16];
653
                } *fps = (struct fps *) addr;
654
                int rval, i;
655
 
656
                rval = verify_area(VERIFY_READ, fps, sizeof(struct fps));
657
                if(rval) { pt_error_return(regs, rval); return; }
658
                for(i = 0; i < 32; i++)
659
                        child->tss.float_regs[i] = fps->regs[i];
660
                child->tss.fsr = fps->fsr;
661
                child->tss.fpqdepth = fps->fpqd;
662
                for(i = 0; i < 16; i++) {
663
                        child->tss.fpqueue[i].insn_addr = fps->fpq[i].insnaddr;
664
                        child->tss.fpqueue[i].insn = fps->fpq[i].insn;
665
                }
666
                pt_succ_return(regs, 0);
667
                return;
668
        }
669
 
670
        case PTRACE_READTEXT:
671
        case PTRACE_READDATA: {
672
                unsigned char *dest = (unsigned char *) addr2;
673
                unsigned long src = addr;
674
                unsigned char tmp;
675
                int res, len = data;
676
 
677
                res = verify_area(VERIFY_WRITE, (void *) dest, len);
678
                if(res) {
679
                        pt_error_return(regs, -res);
680
                        return;
681
                }
682
                while(len) {
683
                        res = read_byte(child, src, &tmp);
684
                        if(res < 0) {
685
                                pt_error_return(regs, -res);
686
                                return;
687
                        }
688
                        *dest = tmp;
689
                        src++; dest++; len--;
690
                }
691
                pt_succ_return(regs, 0);
692
                return;
693
        }
694
 
695
        case PTRACE_WRITETEXT:
696
        case PTRACE_WRITEDATA: {
697
                unsigned char *src = (unsigned char *) addr2;
698
                unsigned long dest = addr;
699
                int res, len = data;
700
 
701
                res = verify_area(VERIFY_READ, (void *) src, len);
702
                if(res) {
703
                        pt_error_return(regs, -res);
704
                        return;
705
                }
706
                while(len) {
707
                        res = write_byte(child, dest, *src);
708
                        if(res < 0) {
709
                                pt_error_return(regs, -res);
710
                                return;
711
                        }
712
                        src++; dest++; len--;
713
                }
714
                pt_succ_return(regs, 0);
715
                return;
716
        }
717
 
718
        case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */
719
                data = 0;
720
                addr = 1;
721
 
722
        case PTRACE_CONT: { /* restart after signal. */
723
                if ((unsigned long) data > NSIG) {
724
                        pt_error_return(regs, EIO);
725
                        return;
726
                }
727
                if (request == PTRACE_SYSCALL)
728
                        child->flags |= PF_TRACESYS;
729
                else
730
                        child->flags &= ~PF_TRACESYS;
731
                child->exit_code = data;
732
                if((addr != 1) & !(addr & 3)) {
733
                        child->tss.kregs->pc = addr;
734
                        child->tss.kregs->npc = addr + 4;
735
                }
736
                wake_up_process(child);
737
                pt_succ_return(regs, 0);
738
                return;
739
        }
740
 
741
/*
742
 * make the child exit.  Best I can do is send it a sigkill.
743
 * perhaps it should be put in the status that it wants to
744
 * exit.
745
 */
746
        case PTRACE_KILL: {
747
                if (child->state == TASK_ZOMBIE) {      /* already dead */
748
                        pt_succ_return(regs, 0);
749
                        return;
750
                }
751
                wake_up_process(child);
752
                child->exit_code = SIGKILL;
753
                pt_succ_return(regs, 0);
754
                return;
755
        }
756
 
757
        case PTRACE_SUNDETACH: { /* detach a process that was attached. */
758
                if ((unsigned long) data > NSIG) {
759
                        pt_error_return(regs, EIO);
760
                        return;
761
                }
762
                child->flags &= ~(PF_PTRACED|PF_TRACESYS);
763
                wake_up_process(child);
764
                child->exit_code = data;
765
                REMOVE_LINKS(child);
766
                child->p_pptr = child->p_opptr;
767
                SET_LINKS(child);
768
                pt_succ_return(regs, 0);
769
                return;
770
        }
771
 
772
        /* PTRACE_DUMPCORE unsupported... */
773
 
774
        default:
775
                pt_error_return(regs, EIO);
776
                return;
777
        }
778
}
779
 
780
asmlinkage void syscall_trace(void)
781
{
782
#ifdef DEBUG_PTRACE
783
        printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
784
#endif
785
        if ((current->flags & (PF_PTRACED|PF_TRACESYS))
786
                        != (PF_PTRACED|PF_TRACESYS))
787
                return;
788
        current->exit_code = SIGTRAP;
789
        current->state = TASK_STOPPED;
790
        current->tss.flags ^= 0x80000000;
791
        notify_parent(current);
792
        schedule();
793
        /*
794
         * this isn't the same as continuing with a signal, but it will do
795
         * for normal use.  strace only continues with a signal if the
796
         * stopping signal is not SIGTRAP.  -brl
797
         */
798
        if (current->exit_code)
799
                current->signal |= (1 << (current->exit_code - 1));
800
        current->exit_code = 0;
801
}

powered by: WebSVN 2.1.0

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