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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [or32/] [kernel/] [ptrace.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1624 jcastillo
/*
2
 *  linux/arch/m68knommu/kernel/ptrace.c
3
 *
4
 *  Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
5
 *                      Kenneth Albanowski <kjahds@kjahds.com>,
6
 *                      The Silver Hammer Group, Ltd.
7
 *
8
 *  Based on:
9
 *
10
 *  linux/arch/m68k/kernel/ptrace
11
 *
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
 * This file is subject to the terms and conditions of the GNU General
17
 * Public License.  See the file COPYING in the main directory of
18
 * this archive for more details.
19
 */
20
 
21
#include <stddef.h>
22
#include <linux/kernel.h>
23
#include <linux/sched.h>
24
#include <linux/string.h>
25
 
26
#include <linux/mm.h>
27
#include <linux/errno.h>
28
#include <linux/ptrace.h>
29
#include <linux/user.h>
30
 
31
#include <asm/segment.h>
32
#include <asm/page.h>
33
#include <asm/pgtable.h>
34
#include <asm/system.h>
35
 
36
/*
37
 * does not yet catch signals sent when the child dies.
38
 * in exit.c or in signal.c.
39
 */
40
 
41
/* determines which bits in the SR the user has access to. */
42
/* 1 = access 0 = no access */
43
#define SR_MASK 0x001f
44
 
45
/* sets the trace bits. */
46
#define TRACE_BITS 0x8000
47
 
48
/* Mapping from PT_xxx to the stack offset at which the register is
49
   saved.  Notice that usp has no stack-slot and needs to be treated
50
   specially (see get_reg/put_reg below). */
51
static int regoff[] = {0,0,0,0,0,0};
52
 
53
/* change a pid into a task struct. */
54
static inline struct task_struct * get_task(int pid)
55
{
56
        int i;
57
 
58
        for (i = 1; i < NR_TASKS; i++) {
59
                if (task[i] != NULL && (task[i]->pid == pid))
60
                        return task[i];
61
        }
62
        return NULL;
63
}
64
 
65
/*
66
 * Get contents of register REGNO in task TASK.
67
 */
68
static inline long get_reg(struct task_struct *task, int regno)
69
{
70
        unsigned long *addr;
71
/* SIMON */
72
#if 0
73
        if (regno == PT_USP)
74
                addr = &task->tss.usp;
75
        else if (regno < sizeof(regoff)/sizeof(regoff[0]))
76
                addr = (unsigned long *)(task->tss.esp0 + regoff[regno]);
77
        else
78
                return 0;
79
#endif
80
        return *addr;
81
}
82
 
83
/*
84
 * Write contents of register REGNO in task TASK.
85
 */
86
static inline int put_reg(struct task_struct *task, int regno,
87
                          unsigned long data)
88
{
89
/* SIMON */
90
#if 0
91
        unsigned long *addr;
92
        if (regno == PT_USP)
93
                addr = &task->tss.usp;
94
        else if (regno < sizeof(regoff)/sizeof(regoff[0]))
95
                addr = (unsigned long *) (task->tss.esp0 + regoff[regno]);
96
        else
97
                return -1;
98
        *addr = data;
99
#endif
100
        return 0;
101
}
102
 
103
inline
104
static unsigned long get_long(struct task_struct * tsk,
105
        struct vm_area_struct * vma, unsigned long addr)
106
{
107
        return *(unsigned long*)addr;
108
}
109
 
110
inline
111
static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
112
        unsigned long data)
113
{
114
        *(unsigned long*)addr = data;
115
}
116
 
117
 
118
inline
119
static int read_long(struct task_struct * tsk, unsigned long addr,
120
        unsigned long * result)
121
{
122
        *result = *(unsigned long *)addr;
123
        return 0;
124
}
125
 
126
inline
127
static int write_long(struct task_struct * tsk, unsigned long addr,
128
        unsigned long data)
129
{
130
        *(unsigned long *)addr = data;
131
        return 0;
132
}
133
 
134
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
135
{
136
/* SIMON */
137
#if 0
138
        struct task_struct *child;
139
        struct user * dummy;
140
        dummy = NULL;
141
 
142
        if (request == PTRACE_TRACEME) {
143
                /* are we already being traced? */
144
                if (current->flags & PF_PTRACED)
145
                        return -EPERM;
146
                /* set the ptrace bit in the process flags. */
147
                current->flags |= PF_PTRACED;
148
                return 0;
149
        }
150
        if (pid == 1)           /* you may not mess with init */
151
                return -EPERM;
152
        if (!(child = get_task(pid)))
153
                return -ESRCH;
154
        if (request == PTRACE_ATTACH) {
155
                if (child == current)
156
                        return -EPERM;
157
                if ((!child->dumpable ||
158
                    (current->uid != child->euid) ||
159
                    (current->uid != child->suid) ||
160
                    (current->uid != child->uid) ||
161
                    (current->gid != child->egid) ||
162
                    (current->gid != child->sgid) ||
163
                    (current->gid != child->gid)) && !suser())
164
                        return -EPERM;
165
                /* the same process cannot be attached many times */
166
                if (child->flags & PF_PTRACED)
167
                        return -EPERM;
168
                child->flags |= PF_PTRACED;
169
                if (child->p_pptr != current) {
170
                        REMOVE_LINKS(child);
171
                        child->p_pptr = current;
172
                        SET_LINKS(child);
173
                }
174
                send_sig(SIGSTOP, child, 1);
175
                return 0;
176
        }
177
        if (!(child->flags & PF_PTRACED))
178
                return -ESRCH;
179
        if (child->state != TASK_STOPPED) {
180
                if (request != PTRACE_KILL)
181
                        return -ESRCH;
182
        }
183
        if (child->p_pptr != current)
184
                return -ESRCH;
185
 
186
        switch (request) {
187
        /* when I and D space are separate, these will need to be fixed. */
188
                case PTRACE_PEEKTEXT: /* read word at location addr. */
189
                case PTRACE_PEEKDATA: {
190
                        unsigned long tmp;
191
                        int res;
192
 
193
                        res = read_long(child, addr, &tmp);
194
                        if (res < 0)
195
                                return res;
196
                        res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
197
                        if (!res)
198
                                put_user(tmp, (unsigned long *) data);
199
                        return res;
200
                }
201
 
202
        /* read the word at location addr in the USER area. */
203
                case PTRACE_PEEKUSR: {
204
                        unsigned long tmp;
205
                        int res;
206
 
207
                        if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
208
                                return -EIO;
209
 
210
                        res = verify_area(VERIFY_WRITE, (void *) data,
211
                                          sizeof(long));
212
                        if (res)
213
                                return res;
214
                        tmp = 0;  /* Default return condition */
215
                        addr = addr >> 2; /* temporary hack. */
216
                        if (addr < 19) {
217
                                tmp = get_reg(child, addr);
218
                                if (addr == PT_SR)
219
                                        tmp >>= 16;
220
                        }
221
                        else if (addr >= 21 && addr < 49)
222
                                tmp = child->tss.fp[addr - 21];
223
                        else if (addr == 49)
224
                                tmp = child->mm->start_code;
225
                        else if (addr == 50)
226
                                tmp = child->mm->start_data;
227
                        else
228
                                return -EIO;
229
                        put_user(tmp,(unsigned long *) data);
230
                        return 0;
231
                }
232
 
233
      /* when I and D space are separate, this will have to be fixed. */
234
                case PTRACE_POKETEXT: /* write the word at location addr. */
235
                case PTRACE_POKEDATA:
236
                        return write_long(child,addr,data);
237
 
238
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
239
                        if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
240
                                return -EIO;
241
 
242
                        addr = addr >> 2; /* temporary hack. */
243
 
244
                        if (addr == PT_ORIG_D0)
245
                                return -EIO;
246
                        if (addr == PT_SR) {
247
                                data &= SR_MASK;
248
                                data <<= 16;
249
                                data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
250
                        }
251
                        if (addr < 19) {
252
                                if (put_reg(child, addr, data))
253
                                        return -EIO;
254
                                return 0;
255
                        }
256
                        if (addr >= 21 && addr < 48)
257
                        {
258
                                child->tss.fp[addr - 21] = data;
259
                                return 0;
260
                        }
261
                        return -EIO;
262
 
263
                case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
264
                case PTRACE_CONT: { /* restart after signal. */
265
                        long tmp;
266
 
267
                        if ((unsigned long) data >= NSIG)
268
                                return -EIO;
269
                        if (request == PTRACE_SYSCALL)
270
                                child->flags |= PF_TRACESYS;
271
                        else
272
                                child->flags &= ~PF_TRACESYS;
273
                        child->exit_code = data;
274
                        wake_up_process(child);
275
                        /* make sure the single step bit is not set. */
276
                        tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
277
                        put_reg(child, PT_SR, tmp);
278
                        return 0;
279
                }
280
 
281
/*
282
 * make the child exit.  Best I can do is send it a sigkill.
283
 * perhaps it should be put in the status that it wants to
284
 * exit.
285
 */
286
                case PTRACE_KILL: {
287
                        long tmp;
288
 
289
                        if (child->state == TASK_ZOMBIE) /* already dead */
290
                                return 0;
291
                        wake_up_process(child);
292
                        child->exit_code = SIGKILL;
293
        /* make sure the single step bit is not set. */
294
                        tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
295
                        put_reg(child, PT_SR, tmp);
296
                        return 0;
297
                }
298
 
299
                case PTRACE_SINGLESTEP: {  /* set the trap flag. */
300
                        long tmp;
301
 
302
                        if ((unsigned long) data >= NSIG)
303
                                return -EIO;
304
                        child->flags &= ~PF_TRACESYS;
305
                        tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
306
                        put_reg(child, PT_SR, tmp);
307
 
308
                        wake_up_process(child);
309
                        child->exit_code = data;
310
        /* give it a chance to run. */
311
                        return 0;
312
                }
313
 
314
                case PTRACE_DETACH: { /* detach a process that was attached. */
315
                        long tmp;
316
 
317
                        if ((unsigned long) data >= NSIG)
318
                                return -EIO;
319
                        child->flags &= ~(PF_PTRACED|PF_TRACESYS);
320
                        wake_up_process(child);
321
                        child->exit_code = data;
322
                        REMOVE_LINKS(child);
323
                        child->p_pptr = child->p_opptr;
324
                        SET_LINKS(child);
325
                        /* make sure the single step bit is not set. */
326
                        tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
327
                        put_reg(child, PT_SR, tmp);
328
                        return 0;
329
                }
330
 
331
                default:
332
                        return -EIO;
333
        }
334
#endif
335
        return 0;
336
}
337
 
338
asmlinkage void syscall_trace(void)
339
{
340
        if ((current->flags & (PF_PTRACED|PF_TRACESYS))
341
                        != (PF_PTRACED|PF_TRACESYS))
342
                return;
343
        current->exit_code = SIGTRAP;
344
        current->state = TASK_STOPPED;
345
        notify_parent(current, SIGCHLD);
346
        schedule();
347
        /*
348
         * this isn't the same as continuing with a signal, but it will do
349
         * for normal use.  strace only continues with a signal if the
350
         * stopping signal is not SIGTRAP.  -brl
351
         */
352
        if (current->exit_code)
353
                current->signal |= (1 << (current->exit_code - 1));
354
        current->exit_code = 0;
355
        return;
356
}

powered by: WebSVN 2.1.0

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