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

Subversion Repositories or1k

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

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

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/arch/m68k/kernel/ptrace.c
3
 *
4
 *  Copyright (C) 1994 by Hamish Macdonald
5
 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
6
 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7
 *
8
 * This file is subject to the terms and conditions of the GNU General
9
 * Public License.  See the file COPYING in the main directory of
10
 * this archive for more details.
11
 */
12
 
13
#include <linux/kernel.h>
14
#include <linux/sched.h>
15
#include <linux/mm.h>
16
#include <linux/smp.h>
17
#include <linux/smp_lock.h>
18
#include <linux/errno.h>
19
#include <linux/ptrace.h>
20
#include <linux/user.h>
21
#include <linux/config.h>
22
 
23
#include <asm/uaccess.h>
24
#include <asm/page.h>
25
#include <asm/pgtable.h>
26
#include <asm/system.h>
27
#include <asm/processor.h>
28
 
29
/*
30
 * does not yet catch signals sent when the child dies.
31
 * in exit.c or in signal.c.
32
 */
33
 
34
/* determines which bits in the SR the user has access to. */
35
/* 1 = access 0 = no access */
36
#define SR_MASK 0x001f
37
 
38
/* sets the trace bits. */
39
#define TRACE_BITS 0x8000
40
 
41
/* Find the stack offset for a register, relative to thread.esp0. */
42
#define PT_REG(reg)     ((long)&((struct pt_regs *)0)->reg)
43
#define SW_REG(reg)     ((long)&((struct switch_stack *)0)->reg \
44
                         - sizeof(struct switch_stack))
45
/* Mapping from PT_xxx to the stack offset at which the register is
46
   saved.  Notice that usp has no stack-slot and needs to be treated
47
   specially (see get_reg/put_reg below). */
48
static int regoff[] = {
49
        PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
50
        PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
51
        PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
52
        SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
53
        PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
54
};
55
 
56
/*
57
 * Get contents of register REGNO in task TASK.
58
 */
59
static inline long get_reg(struct task_struct *task, int regno)
60
{
61
        unsigned long *addr;
62
 
63
        if (regno == PT_USP)
64
                addr = &task->thread.usp;
65
        else if (regno < sizeof(regoff)/sizeof(regoff[0]))
66
                addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
67
        else
68
                return 0;
69
        return *addr;
70
}
71
 
72
/*
73
 * Write contents of register REGNO in task TASK.
74
 */
75
static inline int put_reg(struct task_struct *task, int regno,
76
                          unsigned long data)
77
{
78
        unsigned long *addr;
79
 
80
        if (regno == PT_USP)
81
                addr = &task->thread.usp;
82
        else if (regno < sizeof(regoff)/sizeof(regoff[0]))
83
                addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
84
        else
85
                return -1;
86
        *addr = data;
87
        return 0;
88
}
89
 
90
/*
91
 * Called by kernel/ptrace.c when detaching..
92
 *
93
 * Make sure the single step bit is not set.
94
 */
95
void ptrace_disable(struct task_struct *child)
96
{
97
        unsigned long tmp;
98
        /* make sure the single step bit is not set. */
99
        tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
100
        put_reg(child, PT_SR, tmp);
101
}
102
 
103
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
104
{
105
        struct task_struct *child;
106
        int ret;
107
 
108
        lock_kernel();
109
        ret = -EPERM;
110
        if (request == PTRACE_TRACEME) {
111
                /* are we already being traced? */
112
                if (current->ptrace & PT_PTRACED)
113
                        goto out;
114
                /* set the ptrace bit in the process flags. */
115
                current->ptrace |= PT_PTRACED;
116
                ret = 0;
117
                goto out;
118
        }
119
        ret = -ESRCH;
120
        read_lock(&tasklist_lock);
121
        child = find_task_by_pid(pid);
122
        if (child)
123
                get_task_struct(child);
124
        read_unlock(&tasklist_lock);
125
        if (!child)
126
                goto out;
127
 
128
        ret = -EPERM;
129
        if (pid == 1)           /* you may not mess with init */
130
                goto out_tsk;
131
 
132
        if (request == PTRACE_ATTACH) {
133
                ret = ptrace_attach(child);
134
                goto out_tsk;
135
        }
136
 
137
        ret = ptrace_check_attach(child, request == PTRACE_KILL);
138
        if (ret < 0)
139
                goto out_tsk;
140
 
141
        switch (request) {
142
        /* when I and D space are separate, these will need to be fixed. */
143
                case PTRACE_PEEKTEXT: /* read word at location addr. */
144
                case PTRACE_PEEKDATA: {
145
                        unsigned long tmp;
146
                        int copied;
147
 
148
                        copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
149
                        ret = -EIO;
150
                        if (copied != sizeof(tmp))
151
                                break;
152
                        ret = put_user(tmp,(unsigned long *) data);
153
                        break;
154
                }
155
 
156
        /* read the word at location addr in the USER area. */
157
                case PTRACE_PEEKUSR: {
158
                        unsigned long tmp;
159
 
160
                        ret = -EIO;
161
                        if ((addr & 3) || addr < 0 ||
162
                            addr > sizeof(struct user) - 3)
163
                                break;
164
 
165
                        tmp = 0;  /* Default return condition */
166
                        addr = addr >> 2; /* temporary hack. */
167
                        ret = -EIO;
168
                        if (addr < 19) {
169
                                tmp = get_reg(child, addr);
170
                                if (addr == PT_SR)
171
                                        tmp >>= 16;
172
                        } else if (addr >= 21 && addr < 49) {
173
                                tmp = child->thread.fp[addr - 21];
174
#ifdef CONFIG_M68KFPU_EMU
175
                                /* Convert internal fpu reg representation
176
                                 * into long double format
177
                                 */
178
                                if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
179
                                        tmp = ((tmp & 0xffff0000) << 15) |
180
                                              ((tmp & 0x0000ffff) << 16);
181
#endif
182
                        } else
183
                                break;
184
                        ret = put_user(tmp,(unsigned long *) data);
185
                        break;
186
                }
187
 
188
      /* when I and D space are separate, this will have to be fixed. */
189
                case PTRACE_POKETEXT: /* write the word at location addr. */
190
                case PTRACE_POKEDATA:
191
                        ret = 0;
192
                        if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
193
                                break;
194
                        ret = -EIO;
195
                        break;
196
 
197
                case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
198
                        ret = -EIO;
199
                        if ((addr & 3) || addr < 0 ||
200
                            addr > sizeof(struct user) - 3)
201
                                break;
202
 
203
                        addr = addr >> 2; /* temporary hack. */
204
 
205
                        if (addr == PT_SR) {
206
                                data &= SR_MASK;
207
                                data <<= 16;
208
                                data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
209
                        }
210
                        if (addr < 19) {
211
                                if (put_reg(child, addr, data))
212
                                        break;
213
                                ret = 0;
214
                                break;
215
                        }
216
                        if (addr >= 21 && addr < 48)
217
                        {
218
#ifdef CONFIG_M68KFPU_EMU
219
                                /* Convert long double format
220
                                 * into internal fpu reg representation
221
                                 */
222
                                if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
223
                                        data = (unsigned long)data << 15;
224
                                        data = (data & 0xffff0000) |
225
                                               ((data & 0x0000ffff) >> 1);
226
                                }
227
#endif
228
                                child->thread.fp[addr - 21] = data;
229
                                ret = 0;
230
                        }
231
                        break;
232
 
233
                case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
234
                case PTRACE_CONT: { /* restart after signal. */
235
                        long tmp;
236
 
237
                        ret = -EIO;
238
                        if ((unsigned long) data > _NSIG)
239
                                break;
240
                        if (request == PTRACE_SYSCALL)
241
                                child->ptrace |= PT_TRACESYS;
242
                        else
243
                                child->ptrace &= ~PT_TRACESYS;
244
                        child->exit_code = data;
245
                        /* make sure the single step bit is not set. */
246
                        tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
247
                        put_reg(child, PT_SR, tmp);
248
                        wake_up_process(child);
249
                        ret = 0;
250
                        break;
251
                }
252
 
253
/*
254
 * make the child exit.  Best I can do is send it a sigkill.
255
 * perhaps it should be put in the status that it wants to
256
 * exit.
257
 */
258
                case PTRACE_KILL: {
259
                        long tmp;
260
 
261
                        ret = 0;
262
                        if (child->state == TASK_ZOMBIE) /* already dead */
263
                                break;
264
                        child->exit_code = SIGKILL;
265
        /* make sure the single step bit is not set. */
266
                        tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
267
                        put_reg(child, PT_SR, tmp);
268
                        wake_up_process(child);
269
                        break;
270
                }
271
 
272
                case PTRACE_SINGLESTEP: {  /* set the trap flag. */
273
                        long tmp;
274
 
275
                        ret = -EIO;
276
                        if ((unsigned long) data > _NSIG)
277
                                break;
278
                        child->ptrace &= ~PT_TRACESYS;
279
                        tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
280
                        put_reg(child, PT_SR, tmp);
281
 
282
                        child->exit_code = data;
283
        /* give it a chance to run. */
284
                        wake_up_process(child);
285
                        ret = 0;
286
                        break;
287
                }
288
 
289
                case PTRACE_DETACH:     /* detach a process that was attached. */
290
                        ret = ptrace_detach(child, data);
291
                        break;
292
 
293
                case PTRACE_GETREGS: { /* Get all gp regs from the child. */
294
                        int i;
295
                        unsigned long tmp;
296
                        for (i = 0; i < 19; i++) {
297
                            tmp = get_reg(child, i);
298
                            if (i == PT_SR)
299
                                tmp >>= 16;
300
                            if (put_user(tmp, (unsigned long *) data)) {
301
                                ret = -EFAULT;
302
                                break;
303
                            }
304
                            data += sizeof(long);
305
                        }
306
                        ret = 0;
307
                        break;
308
                }
309
 
310
                case PTRACE_SETREGS: { /* Set all gp regs in the child. */
311
                        int i;
312
                        unsigned long tmp;
313
                        for (i = 0; i < 19; i++) {
314
                            if (get_user(tmp, (unsigned long *) data)) {
315
                                ret = -EFAULT;
316
                                break;
317
                            }
318
                            if (i == PT_SR) {
319
                                tmp &= SR_MASK;
320
                                tmp <<= 16;
321
                                tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
322
                            }
323
                            put_reg(child, i, tmp);
324
                            data += sizeof(long);
325
                        }
326
                        ret = 0;
327
                        break;
328
                }
329
 
330
                case PTRACE_GETFPREGS: { /* Get the child FPU state. */
331
                        ret = 0;
332
                        if (copy_to_user((void *)data, &child->thread.fp,
333
                                         sizeof(struct user_m68kfp_struct)))
334
                                ret = -EFAULT;
335
                        break;
336
                }
337
 
338
                case PTRACE_SETFPREGS: { /* Set the child FPU state. */
339
                        ret = 0;
340
                        if (copy_from_user(&child->thread.fp, (void *)data,
341
                                           sizeof(struct user_m68kfp_struct)))
342
                                ret = -EFAULT;
343
                        break;
344
                }
345
 
346
                default:
347
                        ret = -EIO;
348
                        break;
349
        }
350
out_tsk:
351
        free_task_struct(child);
352
out:
353
        unlock_kernel();
354
        return ret;
355
}
356
 
357
asmlinkage void syscall_trace(void)
358
{
359
        if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
360
                        != (PT_PTRACED|PT_TRACESYS))
361
                return;
362
        current->exit_code = SIGTRAP;
363
        current->state = TASK_STOPPED;
364
        notify_parent(current, SIGCHLD);
365
        schedule();
366
        /*
367
         * this isn't the same as continuing with a signal, but it will do
368
         * for normal use.  strace only continues with a signal if the
369
         * stopping signal is not SIGTRAP.  -brl
370
         */
371
        if (current->exit_code) {
372
                send_sig(current->exit_code, current, 1);
373
                current->exit_code = 0;
374
        }
375
}

powered by: WebSVN 2.1.0

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