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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [avr32/] [kernel/] [ptrace.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Copyright (C) 2004-2006 Atmel Corporation
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License version 2 as
6
 * published by the Free Software Foundation.
7
 */
8
#undef DEBUG
9
#include <linux/kernel.h>
10
#include <linux/sched.h>
11
#include <linux/mm.h>
12
#include <linux/ptrace.h>
13
#include <linux/errno.h>
14
#include <linux/user.h>
15
#include <linux/security.h>
16
#include <linux/unistd.h>
17
#include <linux/notifier.h>
18
 
19
#include <asm/traps.h>
20
#include <asm/uaccess.h>
21
#include <asm/ocd.h>
22
#include <asm/mmu_context.h>
23
#include <linux/kdebug.h>
24
 
25
static struct pt_regs *get_user_regs(struct task_struct *tsk)
26
{
27
        return (struct pt_regs *)((unsigned long)task_stack_page(tsk) +
28
                                  THREAD_SIZE - sizeof(struct pt_regs));
29
}
30
 
31
static void ptrace_single_step(struct task_struct *tsk)
32
{
33
        pr_debug("ptrace_single_step: pid=%u, PC=0x%08lx, SR=0x%08lx\n",
34
                 tsk->pid, task_pt_regs(tsk)->pc, task_pt_regs(tsk)->sr);
35
 
36
        /*
37
         * We can't schedule in Debug mode, so when TIF_BREAKPOINT is
38
         * set, the system call or exception handler will do a
39
         * breakpoint to enter monitor mode before returning to
40
         * userspace.
41
         *
42
         * The monitor code will then notice that TIF_SINGLE_STEP is
43
         * set and return to userspace with single stepping enabled.
44
         * The CPU will then enter monitor mode again after exactly
45
         * one instruction has been executed, and the monitor code
46
         * will then send a SIGTRAP to the process.
47
         */
48
        set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
49
        set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
50
}
51
 
52
/*
53
 * Called by kernel/ptrace.c when detaching
54
 *
55
 * Make sure any single step bits, etc. are not set
56
 */
57
void ptrace_disable(struct task_struct *child)
58
{
59
        clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
60
        clear_tsk_thread_flag(child, TIF_BREAKPOINT);
61
}
62
 
63
/*
64
 * Read the word at offset "offset" into the task's "struct user". We
65
 * actually access the pt_regs struct stored on the kernel stack.
66
 */
67
static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
68
                            unsigned long __user *data)
69
{
70
        unsigned long *regs;
71
        unsigned long value;
72
 
73
        if (offset & 3 || offset >= sizeof(struct user)) {
74
                printk("ptrace_read_user: invalid offset 0x%08lx\n", offset);
75
                return -EIO;
76
        }
77
 
78
        regs = (unsigned long *)get_user_regs(tsk);
79
 
80
        value = 0;
81
        if (offset < sizeof(struct pt_regs))
82
                value = regs[offset / sizeof(regs[0])];
83
 
84
        pr_debug("ptrace_read_user(%s[%u], %#lx, %p) -> %#lx\n",
85
                 tsk->comm, tsk->pid, offset, data, value);
86
 
87
        return put_user(value, data);
88
}
89
 
90
/*
91
 * Write the word "value" to offset "offset" into the task's "struct
92
 * user". We actually access the pt_regs struct stored on the kernel
93
 * stack.
94
 */
95
static int ptrace_write_user(struct task_struct *tsk, unsigned long offset,
96
                             unsigned long value)
97
{
98
        unsigned long *regs;
99
 
100
        pr_debug("ptrace_write_user(%s[%u], %#lx, %#lx)\n",
101
                        tsk->comm, tsk->pid, offset, value);
102
 
103
        if (offset & 3 || offset >= sizeof(struct user)) {
104
                pr_debug("  invalid offset 0x%08lx\n", offset);
105
                return -EIO;
106
        }
107
 
108
        if (offset >= sizeof(struct pt_regs))
109
                return 0;
110
 
111
        regs = (unsigned long *)get_user_regs(tsk);
112
        regs[offset / sizeof(regs[0])] = value;
113
 
114
        return 0;
115
}
116
 
117
static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
118
{
119
        struct pt_regs *regs = get_user_regs(tsk);
120
 
121
        return copy_to_user(uregs, regs, sizeof(*regs)) ? -EFAULT : 0;
122
}
123
 
124
static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
125
{
126
        struct pt_regs newregs;
127
        int ret;
128
 
129
        ret = -EFAULT;
130
        if (copy_from_user(&newregs, uregs, sizeof(newregs)) == 0) {
131
                struct pt_regs *regs = get_user_regs(tsk);
132
 
133
                ret = -EINVAL;
134
                if (valid_user_regs(&newregs)) {
135
                        *regs = newregs;
136
                        ret = 0;
137
                }
138
        }
139
 
140
        return ret;
141
}
142
 
143
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
144
{
145
        int ret;
146
 
147
        pr_debug("ptrace: Enabling monitor mode...\n");
148
        ocd_write(DC, ocd_read(DC) | (1 << OCD_DC_MM_BIT)
149
                        | (1 << OCD_DC_DBE_BIT));
150
 
151
        switch (request) {
152
        /* Read the word at location addr in the child process */
153
        case PTRACE_PEEKTEXT:
154
        case PTRACE_PEEKDATA:
155
                ret = generic_ptrace_peekdata(child, addr, data);
156
                break;
157
 
158
        case PTRACE_PEEKUSR:
159
                ret = ptrace_read_user(child, addr,
160
                                       (unsigned long __user *)data);
161
                break;
162
 
163
        /* Write the word in data at location addr */
164
        case PTRACE_POKETEXT:
165
        case PTRACE_POKEDATA:
166
                ret = generic_ptrace_pokedata(child, addr, data);
167
                break;
168
 
169
        case PTRACE_POKEUSR:
170
                ret = ptrace_write_user(child, addr, data);
171
                break;
172
 
173
        /* continue and stop at next (return from) syscall */
174
        case PTRACE_SYSCALL:
175
        /* restart after signal */
176
        case PTRACE_CONT:
177
                ret = -EIO;
178
                if (!valid_signal(data))
179
                        break;
180
                if (request == PTRACE_SYSCALL)
181
                        set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
182
                else
183
                        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
184
                child->exit_code = data;
185
                /* XXX: Are we sure no breakpoints are active here? */
186
                wake_up_process(child);
187
                ret = 0;
188
                break;
189
 
190
        /*
191
         * Make the child exit. Best I can do is send it a
192
         * SIGKILL. Perhaps it should be put in the status that it
193
         * wants to exit.
194
         */
195
        case PTRACE_KILL:
196
                ret = 0;
197
                if (child->exit_state == EXIT_ZOMBIE)
198
                        break;
199
                child->exit_code = SIGKILL;
200
                wake_up_process(child);
201
                break;
202
 
203
        /*
204
         * execute single instruction.
205
         */
206
        case PTRACE_SINGLESTEP:
207
                ret = -EIO;
208
                if (!valid_signal(data))
209
                        break;
210
                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
211
                ptrace_single_step(child);
212
                child->exit_code = data;
213
                wake_up_process(child);
214
                ret = 0;
215
                break;
216
 
217
        case PTRACE_GETREGS:
218
                ret = ptrace_getregs(child, (void __user *)data);
219
                break;
220
 
221
        case PTRACE_SETREGS:
222
                ret = ptrace_setregs(child, (const void __user *)data);
223
                break;
224
 
225
        default:
226
                ret = ptrace_request(child, request, addr, data);
227
                break;
228
        }
229
 
230
        return ret;
231
}
232
 
233
asmlinkage void syscall_trace(void)
234
{
235
        if (!test_thread_flag(TIF_SYSCALL_TRACE))
236
                return;
237
        if (!(current->ptrace & PT_PTRACED))
238
                return;
239
 
240
        /* The 0x80 provides a way for the tracing parent to
241
         * distinguish between a syscall stop and SIGTRAP delivery */
242
        ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
243
                                 ? 0x80 : 0));
244
 
245
        /*
246
         * this isn't the same as continuing with a signal, but it
247
         * will do for normal use.  strace only continues with a
248
         * signal if the stopping signal is not SIGTRAP.  -brl
249
         */
250
        if (current->exit_code) {
251
                pr_debug("syscall_trace: sending signal %d to PID %u\n",
252
                         current->exit_code, current->pid);
253
                send_sig(current->exit_code, current, 1);
254
                current->exit_code = 0;
255
        }
256
}
257
 
258
/*
259
 * debug_trampoline() is an assembly stub which will store all user
260
 * registers on the stack and execute a breakpoint instruction.
261
 *
262
 * If we single-step into an exception handler which runs with
263
 * interrupts disabled the whole time so it doesn't have to check for
264
 * pending work, its return address will be modified so that it ends
265
 * up returning to debug_trampoline.
266
 *
267
 * If the exception handler decides to store the user context and
268
 * enable interrupts after all, it will restore the original return
269
 * address and status register value. Before it returns, it will
270
 * notice that TIF_BREAKPOINT is set and execute a breakpoint
271
 * instruction.
272
 */
273
extern void debug_trampoline(void);
274
 
275
asmlinkage struct pt_regs *do_debug(struct pt_regs *regs)
276
{
277
        struct thread_info      *ti;
278
        unsigned long           trampoline_addr;
279
        u32                     status;
280
        u32                     ctrl;
281
        int                     code;
282
 
283
        status = ocd_read(DS);
284
        ti = current_thread_info();
285
        code = TRAP_BRKPT;
286
 
287
        pr_debug("do_debug: status=0x%08x PC=0x%08lx SR=0x%08lx tif=0x%08lx\n",
288
                        status, regs->pc, regs->sr, ti->flags);
289
 
290
        if (!user_mode(regs)) {
291
                unsigned long   die_val = DIE_BREAKPOINT;
292
 
293
                if (status & (1 << OCD_DS_SSS_BIT))
294
                        die_val = DIE_SSTEP;
295
 
296
                if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP)
297
                                == NOTIFY_STOP)
298
                        return regs;
299
 
300
                if ((status & (1 << OCD_DS_SWB_BIT))
301
                                && test_and_clear_ti_thread_flag(
302
                                        ti, TIF_BREAKPOINT)) {
303
                        /*
304
                         * Explicit breakpoint from trampoline or
305
                         * exception/syscall/interrupt handler.
306
                         *
307
                         * The real saved regs are on the stack right
308
                         * after the ones we saved on entry.
309
                         */
310
                        regs++;
311
                        pr_debug("  -> TIF_BREAKPOINT done, adjusted regs:"
312
                                        "PC=0x%08lx SR=0x%08lx\n",
313
                                        regs->pc, regs->sr);
314
                        BUG_ON(!user_mode(regs));
315
 
316
                        if (test_thread_flag(TIF_SINGLE_STEP)) {
317
                                pr_debug("Going to do single step...\n");
318
                                return regs;
319
                        }
320
 
321
                        /*
322
                         * No TIF_SINGLE_STEP means we're done
323
                         * stepping over a syscall. Do the trap now.
324
                         */
325
                        code = TRAP_TRACE;
326
                } else if ((status & (1 << OCD_DS_SSS_BIT))
327
                                && test_ti_thread_flag(ti, TIF_SINGLE_STEP)) {
328
 
329
                        pr_debug("Stepped into something, "
330
                                        "setting TIF_BREAKPOINT...\n");
331
                        set_ti_thread_flag(ti, TIF_BREAKPOINT);
332
 
333
                        /*
334
                         * We stepped into an exception, interrupt or
335
                         * syscall handler. Some exception handlers
336
                         * don't check for pending work, so we need to
337
                         * set up a trampoline just in case.
338
                         *
339
                         * The exception entry code will undo the
340
                         * trampoline stuff if it does a full context
341
                         * save (which also means that it'll check for
342
                         * pending work later.)
343
                         */
344
                        if ((regs->sr & MODE_MASK) == MODE_EXCEPTION) {
345
                                trampoline_addr
346
                                        = (unsigned long)&debug_trampoline;
347
 
348
                                pr_debug("Setting up trampoline...\n");
349
                                ti->rar_saved = sysreg_read(RAR_EX);
350
                                ti->rsr_saved = sysreg_read(RSR_EX);
351
                                sysreg_write(RAR_EX, trampoline_addr);
352
                                sysreg_write(RSR_EX, (MODE_EXCEPTION
353
                                                        | SR_EM | SR_GM));
354
                                BUG_ON(ti->rsr_saved & MODE_MASK);
355
                        }
356
 
357
                        /*
358
                         * If we stepped into a system call, we
359
                         * shouldn't do a single step after we return
360
                         * since the return address is right after the
361
                         * "scall" instruction we were told to step
362
                         * over.
363
                         */
364
                        if ((regs->sr & MODE_MASK) == MODE_SUPERVISOR) {
365
                                pr_debug("Supervisor; no single step\n");
366
                                clear_ti_thread_flag(ti, TIF_SINGLE_STEP);
367
                        }
368
 
369
                        ctrl = ocd_read(DC);
370
                        ctrl &= ~(1 << OCD_DC_SS_BIT);
371
                        ocd_write(DC, ctrl);
372
 
373
                        return regs;
374
                } else {
375
                        printk(KERN_ERR "Unexpected OCD_DS value: 0x%08x\n",
376
                                        status);
377
                        printk(KERN_ERR "Thread flags: 0x%08lx\n", ti->flags);
378
                        die("Unhandled debug trap in kernel mode",
379
                                        regs, SIGTRAP);
380
                }
381
        } else if (status & (1 << OCD_DS_SSS_BIT)) {
382
                /* Single step in user mode */
383
                code = TRAP_TRACE;
384
 
385
                ctrl = ocd_read(DC);
386
                ctrl &= ~(1 << OCD_DC_SS_BIT);
387
                ocd_write(DC, ctrl);
388
        }
389
 
390
        pr_debug("Sending SIGTRAP: code=%d PC=0x%08lx SR=0x%08lx\n",
391
                        code, regs->pc, regs->sr);
392
 
393
        clear_thread_flag(TIF_SINGLE_STEP);
394
        _exception(SIGTRAP, regs, code, instruction_pointer(regs));
395
 
396
        return regs;
397
}

powered by: WebSVN 2.1.0

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