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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [m68knommu/] [kernel/] [ptrace.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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