aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/microblaze/include/asm/ptrace.h68
-rw-r--r--arch/microblaze/kernel/ptrace.c182
2 files changed, 250 insertions, 0 deletions
diff --git a/arch/microblaze/include/asm/ptrace.h b/arch/microblaze/include/asm/ptrace.h
new file mode 100644
index 000000000000..f1f03486428a
--- /dev/null
+++ b/arch/microblaze/include/asm/ptrace.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2006 Atmark Techno, Inc.
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 */
8
9#ifndef _ASM_MICROBLAZE_PTRACE_H
10#define _ASM_MICROBLAZE_PTRACE_H
11
12#ifndef __ASSEMBLY__
13#include <linux/types.h>
14
15typedef unsigned long microblaze_reg_t;
16
17struct pt_regs {
18 microblaze_reg_t r0;
19 microblaze_reg_t r1;
20 microblaze_reg_t r2;
21 microblaze_reg_t r3;
22 microblaze_reg_t r4;
23 microblaze_reg_t r5;
24 microblaze_reg_t r6;
25 microblaze_reg_t r7;
26 microblaze_reg_t r8;
27 microblaze_reg_t r9;
28 microblaze_reg_t r10;
29 microblaze_reg_t r11;
30 microblaze_reg_t r12;
31 microblaze_reg_t r13;
32 microblaze_reg_t r14;
33 microblaze_reg_t r15;
34 microblaze_reg_t r16;
35 microblaze_reg_t r17;
36 microblaze_reg_t r18;
37 microblaze_reg_t r19;
38 microblaze_reg_t r20;
39 microblaze_reg_t r21;
40 microblaze_reg_t r22;
41 microblaze_reg_t r23;
42 microblaze_reg_t r24;
43 microblaze_reg_t r25;
44 microblaze_reg_t r26;
45 microblaze_reg_t r27;
46 microblaze_reg_t r28;
47 microblaze_reg_t r29;
48 microblaze_reg_t r30;
49 microblaze_reg_t r31;
50 microblaze_reg_t pc;
51 microblaze_reg_t msr;
52 microblaze_reg_t ear;
53 microblaze_reg_t esr;
54 microblaze_reg_t fsr;
55 int kernel_mode;
56};
57
58#define kernel_mode(regs) ((regs)->kernel_mode)
59#define user_mode(regs) (!kernel_mode(regs))
60
61#define instruction_pointer(regs) ((regs)->pc)
62#define profile_pc(regs) instruction_pointer(regs)
63
64void show_regs(struct pt_regs *);
65
66#endif /* __ASSEMBLY__ */
67
68#endif /* _ASM_MICROBLAZE_PTRACE_H */
diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c
new file mode 100644
index 000000000000..3171e39e3220
--- /dev/null
+++ b/arch/microblaze/kernel/ptrace.c
@@ -0,0 +1,182 @@
1/*
2 * `ptrace' system call
3 *
4 * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
5 * Copyright (C) 2007-2009 PetaLogix
6 * Copyright (C) 2004-2007 John Williams <john.williams@petalogix.com>
7 *
8 * derived from arch/v850/kernel/ptrace.c
9 *
10 * Copyright (C) 2002,03 NEC Electronics Corporation
11 * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
12 *
13 * Derived from arch/mips/kernel/ptrace.c:
14 *
15 * Copyright (C) 1992 Ross Biro
16 * Copyright (C) Linus Torvalds
17 * Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
18 * Copyright (C) 1996 David S. Miller
19 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
20 * Copyright (C) 1999 MIPS Technologies, Inc.
21 *
22 * This file is subject to the terms and conditions of the GNU General
23 * Public License. See the file COPYING in the main directory of this
24 * archive for more details.
25 */
26
27#include <linux/kernel.h>
28#include <linux/mm.h>
29#include <linux/sched.h>
30#include <linux/smp_lock.h>
31#include <linux/ptrace.h>
32#include <linux/signal.h>
33
34#include <linux/errno.h>
35#include <linux/ptrace.h>
36#include <asm/processor.h>
37#include <linux/uaccess.h>
38#include <asm/asm-offsets.h>
39
40/* Returns the address where the register at REG_OFFS in P is stashed away. */
41static microblaze_reg_t *reg_save_addr(unsigned reg_offs,
42 struct task_struct *t)
43{
44 struct pt_regs *regs;
45
46 /*
47 * Three basic cases:
48 *
49 * (1) A register normally saved before calling the scheduler, is
50 * available in the kernel entry pt_regs structure at the top
51 * of the kernel stack. The kernel trap/irq exit path takes
52 * care to save/restore almost all registers for ptrace'd
53 * processes.
54 *
55 * (2) A call-clobbered register, where the process P entered the
56 * kernel via [syscall] trap, is not stored anywhere; that's
57 * OK, because such registers are not expected to be preserved
58 * when the trap returns anyway (so we don't actually bother to
59 * test for this case).
60 *
61 * (3) A few registers not used at all by the kernel, and so
62 * normally never saved except by context-switches, are in the
63 * context switch state.
64 */
65
66 /* Register saved during kernel entry (or not available). */
67 regs = task_pt_regs(t);
68
69 return (microblaze_reg_t *)((char *)regs + reg_offs);
70}
71
72long arch_ptrace(struct task_struct *child, long request, long addr, long data)
73{
74 int rval;
75 unsigned long val = 0;
76 unsigned long copied;
77
78 switch (request) {
79 case PTRACE_PEEKTEXT: /* read word at location addr. */
80 case PTRACE_PEEKDATA:
81 pr_debug("PEEKTEXT/PEEKDATA at %08lX\n", addr);
82 copied = access_process_vm(child, addr, &val, sizeof(val), 0);
83 rval = -EIO;
84 if (copied != sizeof(val))
85 break;
86 rval = put_user(val, (unsigned long *)data);
87 break;
88
89 case PTRACE_POKETEXT: /* write the word at location addr. */
90 case PTRACE_POKEDATA:
91 pr_debug("POKETEXT/POKEDATA to %08lX\n", addr);
92 rval = 0;
93 if (access_process_vm(child, addr, &data, sizeof(data), 1)
94 == sizeof(data))
95 break;
96 rval = -EIO;
97 break;
98
99 /* Read/write the word at location ADDR in the registers. */
100 case PTRACE_PEEKUSR:
101 case PTRACE_POKEUSR:
102 pr_debug("PEEKUSR/POKEUSR : 0x%08lx\n", addr);
103 rval = 0;
104 if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
105 /*
106 * Special requests that don't actually correspond
107 * to offsets in struct pt_regs.
108 */
109 if (addr == PT_TEXT_ADDR) {
110 val = child->mm->start_code;
111 } else if (addr == PT_DATA_ADDR) {
112 val = child->mm->start_data;
113 } else if (addr == PT_TEXT_LEN) {
114 val = child->mm->end_code
115 - child->mm->start_code;
116 } else {
117 rval = -EIO;
118 }
119 } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
120 microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
121 if (request == PTRACE_PEEKUSR)
122 val = *reg_addr;
123 else
124 *reg_addr = data;
125 } else
126 rval = -EIO;
127
128 if (rval == 0 && request == PTRACE_PEEKUSR)
129 rval = put_user(val, (unsigned long *)data);
130 break;
131 /* Continue and stop at next (return from) syscall */
132 case PTRACE_SYSCALL:
133 pr_debug("PTRACE_SYSCALL\n");
134 case PTRACE_SINGLESTEP:
135 pr_debug("PTRACE_SINGLESTEP\n");
136 /* Restart after a signal. */
137 case PTRACE_CONT:
138 pr_debug("PTRACE_CONT\n");
139 rval = -EIO;
140 if (!valid_signal(data))
141 break;
142
143 if (request == PTRACE_SYSCALL)
144 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
145 else
146 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
147
148 child->exit_code = data;
149 pr_debug("wakeup_process\n");
150 wake_up_process(child);
151 rval = 0;
152 break;
153
154 /*
155 * make the child exit. Best I can do is send it a sigkill.
156 * perhaps it should be put in the status that it wants to
157 * exit.
158 */
159 case PTRACE_KILL:
160 pr_debug("PTRACE_KILL\n");
161 rval = 0;
162 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
163 break;
164 child->exit_code = SIGKILL;
165 wake_up_process(child);
166 break;
167
168 case PTRACE_DETACH: /* detach a process that was attached. */
169 pr_debug("PTRACE_DETACH\n");
170 rval = ptrace_detach(child, data);
171 break;
172 default:
173 /* rval = ptrace_request(child, request, addr, data); noMMU */
174 rval = -EIO;
175 }
176 return rval;
177}
178
179void ptrace_disable(struct task_struct *child)
180{
181 /* nothing to do */
182}