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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/arch/ppc64/kernel/ptrace.c
3
 *
4
 *  PowerPC version
5
 *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
6
 *
7
 *  Derived from "arch/m68k/kernel/ptrace.c"
8
 *  Copyright (C) 1994 by Hamish Macdonald
9
 *  Taken from linux/kernel/ptrace.c and modified for M680x0.
10
 *  linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
11
 *
12
 * Modified by Cort Dougan (cort@hq.fsmlabs.com)
13
 * and Paul Mackerras (paulus@linuxcare.com.au).
14
 *
15
 * This file is subject to the terms and conditions of the GNU General
16
 * Public License.  See the file README.legal in the main directory of
17
 * this archive for more details.
18
 */
19
 
20
#include <linux/kernel.h>
21
#include <linux/sched.h>
22
#include <linux/mm.h>
23
#include <linux/smp.h>
24
#include <linux/smp_lock.h>
25
#include <linux/errno.h>
26
#include <linux/ptrace.h>
27
#include <linux/user.h>
28
 
29
#include <asm/uaccess.h>
30
#include <asm/page.h>
31
#include <asm/pgtable.h>
32
#include <asm/system.h>
33
 
34
/*
35
 * Set of msr bits that gdb can change on behalf of a process.
36
 */
37
#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
38
 
39
/*
40
 * does not yet catch signals sent when the child dies.
41
 * in exit.c or in signal.c.
42
 */
43
 
44
/*
45
 * Get contents of register REGNO in task TASK.
46
 */
47
static inline unsigned long get_reg(struct task_struct *task, int regno)
48
{
49
        if (regno < sizeof(struct pt_regs) / sizeof(unsigned long))
50
                return ((unsigned long *)task->thread.regs)[regno];
51
        return (0);
52
}
53
 
54
/*
55
 * Write contents of register REGNO in task TASK.
56
 */
57
static inline int put_reg(struct task_struct *task, int regno,
58
                          unsigned long data)
59
{
60
        if (regno < PT_SOFTE) {
61
                if (regno == PT_MSR)
62
                        data = (data & MSR_DEBUGCHANGE)
63
                                | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
64
                ((unsigned long *)task->thread.regs)[regno] = data;
65
                return 0;
66
        }
67
        return -EIO;
68
}
69
 
70
#ifdef CONFIG_ALTIVEC
71
/*
72
 * Get contents of AltiVec register state in task TASK
73
 */
74
static inline int get_vrregs(unsigned long data, struct task_struct *task)
75
{
76
        return (copy_to_user((void *)data,&task->thread.vr[0],
77
                        offsetof(struct thread_struct,vrsave[2])-
78
                             offsetof(struct thread_struct,vr[0])) ? -EFAULT : 0 );
79
}
80
 
81
/*
82
 * Write contents of AltiVec register state into task TASK.
83
 */
84
static inline int set_vrregs(struct task_struct *task, unsigned long data)
85
{
86
        return (copy_from_user(&task->thread.vr[0],(void *)data,
87
                        offsetof(struct thread_struct,vrsave[2])-
88
                             offsetof(struct thread_struct,vr[0])) ? -EFAULT : 0 );
89
}
90
#endif
91
 
92
static inline void
93
set_single_step(struct task_struct *task)
94
{
95
        struct pt_regs *regs = task->thread.regs;
96
        if (regs != NULL)
97
                regs->msr |= MSR_SE;
98
}
99
 
100
static inline void
101
clear_single_step(struct task_struct *task)
102
{
103
        struct pt_regs *regs = task->thread.regs;
104
        if (regs != NULL)
105
                regs->msr &= ~MSR_SE;
106
}
107
 
108
/*
109
 * Called by kernel/ptrace.c when detaching..
110
 *
111
 * Make sure single step bits etc are not set.
112
 */
113
void ptrace_disable(struct task_struct *child)
114
{
115
        /* make sure the single step bit is not set. */
116
        clear_single_step(child);
117
}
118
 
119
int sys_ptrace(long request, long pid, long addr, long data)
120
{
121
        struct task_struct *child;
122
        int ret = -EPERM;
123
 
124
        lock_kernel();
125
        if (request == PTRACE_TRACEME) {
126
                /* are we already being traced? */
127
                if (current->ptrace & PT_PTRACED)
128
                        goto out;
129
                /* set the ptrace bit in the process flags. */
130
                current->ptrace |= PT_PTRACED;
131
                ret = 0;
132
                goto out;
133
        }
134
        ret = -ESRCH;
135
        read_lock(&tasklist_lock);
136
        child = find_task_by_pid(pid);
137
        if (child)
138
                get_task_struct(child);
139
        read_unlock(&tasklist_lock);
140
        if (!child)
141
                goto out;
142
 
143
        ret = -EPERM;
144
        if (pid == 1)           /* you may not mess with init */
145
                goto out_tsk;
146
 
147
        if (request == PTRACE_ATTACH) {
148
                ret = ptrace_attach(child);
149
                goto out_tsk;
150
        }
151
 
152
        ret = ptrace_check_attach(child, request == PTRACE_KILL);
153
        if (ret < 0)
154
                goto out_tsk;
155
 
156
        switch (request) {
157
        /* when I and D space are separate, these will need to be fixed. */
158
        case PTRACE_PEEKTEXT: /* read word at location addr. */
159
        case PTRACE_PEEKDATA: {
160
                unsigned long tmp;
161
                int copied;
162
 
163
                copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
164
                ret = -EIO;
165
                if (copied != sizeof(tmp))
166
                        break;
167
                ret = put_user(tmp,(unsigned long *) data);
168
                break;
169
        }
170
 
171
        /* read the word at location addr in the USER area. */
172
        case PTRACE_PEEKUSR: {
173
                unsigned long index;
174
                unsigned long tmp;
175
 
176
                ret = -EIO;
177
                /* convert to index and check */
178
                index = (unsigned long) addr >> 3;
179
                if ((addr & 7) || (index > PT_FPSCR))
180
                        break;
181
 
182
                if (index < PT_FPR0) {
183
                        tmp = get_reg(child, (int)index);
184
                } else {
185
                        if (child->thread.regs->msr & MSR_FP)
186
                                giveup_fpu(child);
187
                        tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
188
                }
189
                ret = put_user(tmp,(unsigned long *) data);
190
                break;
191
        }
192
 
193
        /* If I and D space are separate, this will have to be fixed. */
194
        case PTRACE_POKETEXT: /* write the word at location addr. */
195
        case PTRACE_POKEDATA:
196
                ret = 0;
197
                if (access_process_vm(child, addr, &data, sizeof(data), 1)
198
                                == sizeof(data))
199
                        break;
200
                ret = -EIO;
201
                break;
202
 
203
        /* write the word at location addr in the USER area */
204
        case PTRACE_POKEUSR: {
205
                unsigned long index;
206
 
207
                ret = -EIO;
208
                /* convert to index and check */
209
                index = (unsigned long) addr >> 3;
210
                if ((addr & 7) || (index > PT_FPSCR))
211
                        break;
212
 
213
                if (index == PT_ORIG_R3)
214
                        break;
215
                if (index < PT_FPR0) {
216
                        ret = put_reg(child, index, data);
217
                } else {
218
                        if (child->thread.regs->msr & MSR_FP)
219
                                giveup_fpu(child);
220
                        ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
221
                        ret = 0;
222
                }
223
                break;
224
        }
225
 
226
        case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
227
        case PTRACE_CONT: { /* restart after signal. */
228
                ret = -EIO;
229
                if ((unsigned long) data > _NSIG)
230
                        break;
231
                if (request == PTRACE_SYSCALL)
232
                        child->ptrace |= PT_TRACESYS;
233
                else
234
                        child->ptrace &= ~PT_TRACESYS;
235
                child->exit_code = data;
236
                /* make sure the single step bit is not set. */
237
                clear_single_step(child);
238
                wake_up_process(child);
239
                ret = 0;
240
                break;
241
        }
242
 
243
        /*
244
         * make the child exit.  Best I can do is send it a sigkill.
245
         * perhaps it should be put in the status that it wants to
246
         * exit.
247
         */
248
        case PTRACE_KILL: {
249
                ret = 0;
250
                if (child->state == TASK_ZOMBIE)        /* already dead */
251
                        break;
252
                child->exit_code = SIGKILL;
253
                /* make sure the single step bit is not set. */
254
                clear_single_step(child);
255
                wake_up_process(child);
256
                break;
257
        }
258
 
259
        case PTRACE_SINGLESTEP: {  /* set the trap flag. */
260
                ret = -EIO;
261
                if ((unsigned long) data > _NSIG)
262
                        break;
263
                child->ptrace &= ~PT_TRACESYS;
264
                set_single_step(child);
265
                child->exit_code = data;
266
                /* give it a chance to run. */
267
                wake_up_process(child);
268
                ret = 0;
269
                break;
270
        }
271
 
272
        case PTRACE_DETACH:
273
                ret = ptrace_detach(child, data);
274
                break;
275
 
276
        case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
277
                int i;
278
                unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
279
                unsigned long *tmp = (unsigned long *)addr;
280
 
281
                for (i = 0; i < 32; i++) {
282
                        ret = put_user(*reg, tmp);
283
                        if (ret)
284
                                break;
285
                        reg++;
286
                        tmp++;
287
                }
288
                break;
289
        }
290
 
291
        case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
292
                int i;
293
                unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
294
                unsigned long *tmp = (unsigned long *)addr;
295
 
296
                for (i = 0; i < 32; i++) {
297
                        ret = get_user(*reg, tmp);
298
                        if (ret)
299
                                break;
300
                        reg++;
301
                        tmp++;
302
                }
303
                break;
304
        }
305
 
306
        case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
307
                int i;
308
                unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
309
                unsigned long *tmp = (unsigned long *)addr;
310
 
311
                if (child->thread.regs->msr & MSR_FP)
312
                        giveup_fpu(child);
313
 
314
                for (i = 0; i < 32; i++) {
315
                        ret = put_user(*reg, tmp);
316
                        if (ret)
317
                                break;
318
                        reg++;
319
                        tmp++;
320
                }
321
                break;
322
        }
323
 
324
        case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
325
                int i;
326
                unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
327
                unsigned long *tmp = (unsigned long *)addr;
328
 
329
                if (child->thread.regs->msr & MSR_FP)
330
                        giveup_fpu(child);
331
 
332
                for (i = 0; i < 32; i++) {
333
                        ret = get_user(*reg, tmp);
334
                        if (ret)
335
                                break;
336
                        reg++;
337
                        tmp++;
338
                }
339
                break;
340
        }
341
#ifdef CONFIG_ALTIVEC
342
        case PTRACE_GETVRREGS:
343
                /* Get the child altivec register state. */
344
                if (child->thread.regs->msr & MSR_VEC)
345
                        giveup_altivec(child);
346
                ret = get_vrregs(data, child);
347
                break;
348
 
349
        case PTRACE_SETVRREGS:
350
                /* Set the child altivec register state. */
351
                /* this is to clear the MSR_VEC bit to force a reload
352
                 * of register state from memory */
353
                if (child->thread.regs->msr & MSR_VEC)
354
                        giveup_altivec(child);
355
                ret = set_vrregs(child,data);
356
                break;
357
#endif
358
 
359
        default:
360
                ret = -EIO;
361
                break;
362
        }
363
out_tsk:
364
        free_task_struct(child);
365
out:
366
        unlock_kernel();
367
        return ret;
368
}
369
 
370
void syscall_trace(void)
371
{
372
  if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
373
                        != (PT_PTRACED|PT_TRACESYS))
374
                return;
375
        current->exit_code = SIGTRAP;
376
        current->state = TASK_STOPPED;
377
        notify_parent(current, SIGCHLD);
378
        schedule();
379
        /*
380
         * this isn't the same as continuing with a signal, but it will do
381
         * for normal use.  strace only continues with a signal if the
382
         * stopping signal is not SIGTRAP.  -brl
383
         */
384
        if (current->exit_code) {
385
                send_sig(current->exit_code, current, 1);
386
                current->exit_code = 0;
387
        }
388
}

powered by: WebSVN 2.1.0

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