aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/ptrace.c
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-05-28 23:09:12 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-06-04 17:11:18 -0400
commit867e359b97c970a60626d5d76bbe2a8fadbf38fb (patch)
treec5ccbb7f5172e8555977119608ecb1eee3cc37e3 /arch/tile/kernel/ptrace.c
parent5360bd776f73d0a7da571d72a09a03f237e99900 (diff)
arch/tile: core support for Tilera 32-bit chips.
This change is the core kernel support for TILEPro and TILE64 chips. No driver support (except the console driver) is included yet. This includes the relevant Linux headers in asm/; the low-level low-level "Tile architecture" headers in arch/, which are shared with the hypervisor, etc., and are build-system agnostic; and the relevant hypervisor headers in hv/. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Reviewed-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/tile/kernel/ptrace.c')
-rw-r--r--arch/tile/kernel/ptrace.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
new file mode 100644
index 000000000000..468054928e7d
--- /dev/null
+++ b/arch/tile/kernel/ptrace.c
@@ -0,0 +1,203 @@
1/*
2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 *
14 * Copied from i386: Ross Biro 1/23/92
15 */
16
17#include <linux/kernel.h>
18#include <linux/ptrace.h>
19#include <linux/kprobes.h>
20#include <linux/compat.h>
21#include <linux/uaccess.h>
22
23void user_enable_single_step(struct task_struct *child)
24{
25 set_tsk_thread_flag(child, TIF_SINGLESTEP);
26}
27
28void user_disable_single_step(struct task_struct *child)
29{
30 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
31}
32
33/*
34 * This routine will put a word on the process's privileged stack.
35 */
36static void putreg(struct task_struct *task,
37 unsigned long addr, unsigned long value)
38{
39 unsigned int regno = addr / sizeof(unsigned long);
40 struct pt_regs *childregs = task_pt_regs(task);
41 childregs->regs[regno] = value;
42 childregs->flags |= PT_FLAGS_RESTORE_REGS;
43}
44
45static unsigned long getreg(struct task_struct *task, unsigned long addr)
46{
47 unsigned int regno = addr / sizeof(unsigned long);
48 struct pt_regs *childregs = task_pt_regs(task);
49 return childregs->regs[regno];
50}
51
52/*
53 * Called by kernel/ptrace.c when detaching..
54 */
55void ptrace_disable(struct task_struct *child)
56{
57 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
58
59 /*
60 * These two are currently unused, but will be set by arch_ptrace()
61 * and used in the syscall assembly when we do support them.
62 */
63 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
64}
65
66long arch_ptrace(struct task_struct *child, long request, long addr, long data)
67{
68 unsigned long __user *datap;
69 unsigned long tmp;
70 int i;
71 long ret = -EIO;
72
73#ifdef CONFIG_COMPAT
74 if (task_thread_info(current)->status & TS_COMPAT)
75 data = (u32)data;
76 if (task_thread_info(child)->status & TS_COMPAT)
77 addr = (u32)addr;
78#endif
79 datap = (unsigned long __user *)data;
80
81 switch (request) {
82
83 case PTRACE_PEEKUSR: /* Read register from pt_regs. */
84 if (addr & (sizeof(data)-1))
85 break;
86 if (addr < 0 || addr >= PTREGS_SIZE)
87 break;
88 tmp = getreg(child, addr); /* Read register */
89 ret = put_user(tmp, datap);
90 break;
91
92 case PTRACE_POKEUSR: /* Write register in pt_regs. */
93 if (addr & (sizeof(data)-1))
94 break;
95 if (addr < 0 || addr >= PTREGS_SIZE)
96 break;
97 putreg(child, addr, data); /* Write register */
98 break;
99
100 case PTRACE_GETREGS: /* Get all registers from the child. */
101 if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
102 break;
103 for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
104 ret = __put_user(getreg(child, i), datap);
105 if (ret != 0)
106 break;
107 datap++;
108 }
109 break;
110
111 case PTRACE_SETREGS: /* Set all registers in the child. */
112 if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
113 break;
114 for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
115 ret = __get_user(tmp, datap);
116 if (ret != 0)
117 break;
118 putreg(child, i, tmp);
119 datap++;
120 }
121 break;
122
123 case PTRACE_GETFPREGS: /* Get the child FPU state. */
124 case PTRACE_SETFPREGS: /* Set the child FPU state. */
125 break;
126
127 case PTRACE_SETOPTIONS:
128 /* Support TILE-specific ptrace options. */
129 child->ptrace &= ~PT_TRACE_MASK_TILE;
130 tmp = data & PTRACE_O_MASK_TILE;
131 data &= ~PTRACE_O_MASK_TILE;
132 ret = ptrace_request(child, request, addr, data);
133 if (tmp & PTRACE_O_TRACEMIGRATE)
134 child->ptrace |= PT_TRACE_MIGRATE;
135 break;
136
137 default:
138#ifdef CONFIG_COMPAT
139 if (task_thread_info(current)->status & TS_COMPAT) {
140 ret = compat_ptrace_request(child, request,
141 addr, data);
142 break;
143 }
144#endif
145 ret = ptrace_request(child, request, addr, data);
146 break;
147 }
148
149 return ret;
150}
151
152#ifdef CONFIG_COMPAT
153/* Not used; we handle compat issues in arch_ptrace() directly. */
154long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
155 compat_ulong_t addr, compat_ulong_t data)
156{
157 BUG();
158}
159#endif
160
161void do_syscall_trace(void)
162{
163 if (!test_thread_flag(TIF_SYSCALL_TRACE))
164 return;
165
166 if (!(current->ptrace & PT_PTRACED))
167 return;
168
169 /*
170 * The 0x80 provides a way for the tracing parent to distinguish
171 * between a syscall stop and SIGTRAP delivery
172 */
173 ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
174
175 /*
176 * this isn't the same as continuing with a signal, but it will do
177 * for normal use. strace only continues with a signal if the
178 * stopping signal is not SIGTRAP. -brl
179 */
180 if (current->exit_code) {
181 send_sig(current->exit_code, current, 1);
182 current->exit_code = 0;
183 }
184}
185
186void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
187{
188 struct siginfo info;
189
190 memset(&info, 0, sizeof(info));
191 info.si_signo = SIGTRAP;
192 info.si_code = TRAP_BRKPT;
193 info.si_addr = (void __user *) regs->pc;
194
195 /* Send us the fakey SIGTRAP */
196 force_sig_info(SIGTRAP, &info, tsk);
197}
198
199/* Handle synthetic interrupt delivered only by the simulator. */
200void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
201{
202 send_sigtrap(current, regs, fault_num);
203}