diff options
author | Christoph Hellwig <hch@lst.de> | 2010-03-10 18:23:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:39 -0500 |
commit | 290ba3aef58ff21c977585ff6b687e457f80bf54 (patch) | |
tree | efce6dc709b93798f588e0825602a6cc3b73786d /arch/cris | |
parent | 8313809ef3bfa8fa366d416add2150787235f192 (diff) |
cris arch-v32: use generic ptrace_resume code
Use the generic ptrace_resume code for PTRACE_SYSCALL, PTRACE_CONT,
PTRACE_KILL and PTRACE_SINGLESTEP. This implies defining
arch_has_single_step in <asm/ptrace.h> and implementing the
user_enable_single_step and user_disable_single_step functions, which also
causes the breakpoint information to be cleared on fork, which could be
considered a bug fix.
Also the TIF_SYSCALL_TRACE thread flag is now cleared on PTRACE_KILL which
it previously wasn't which is consistent with all architectures using the
modern ptrace code.
The way breakpoints are disabled is entirely inconsistent currently, I
tried to make some sense of it, but I suspect all of the content of
ptrace_disable should be moved into user_disable_single_step, this
defintively needs some revisting as the current patch changes behaviour in
not quite designed ways.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Mikael Starvik <starvik@axis.com>
Cc: Jesper Nilsson <jesper.nilsson@axis.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/cris')
-rw-r--r-- | arch/cris/arch-v32/kernel/ptrace.c | 109 | ||||
-rw-r--r-- | arch/cris/include/arch-v32/arch/ptrace.h | 1 |
2 files changed, 31 insertions, 79 deletions
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index dd401473f5b5..f4ebd1e7d0f5 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c | |||
@@ -78,6 +78,35 @@ int put_reg(struct task_struct *task, unsigned int regno, unsigned long data) | |||
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | 80 | ||
81 | void user_enable_single_step(struct task_struct *child) | ||
82 | { | ||
83 | unsigned long tmp; | ||
84 | |||
85 | /* | ||
86 | * Set up SPC if not set already (in which case we have no other | ||
87 | * choice but to trust it). | ||
88 | */ | ||
89 | if (!get_reg(child, PT_SPC)) { | ||
90 | /* In case we're stopped in a delay slot. */ | ||
91 | tmp = get_reg(child, PT_ERP) & ~1; | ||
92 | put_reg(child, PT_SPC, tmp); | ||
93 | } | ||
94 | tmp = get_reg(child, PT_CCS) | SBIT_USER; | ||
95 | put_reg(child, PT_CCS, tmp); | ||
96 | } | ||
97 | |||
98 | void user_disable_single_step(struct task_struct *child) | ||
99 | { | ||
100 | put_reg(child, PT_SPC, 0); | ||
101 | |||
102 | if (!get_debugreg(child->pid, PT_BP_CTRL)) { | ||
103 | unsigned long tmp; | ||
104 | /* If no h/w bp configured, disable S bit. */ | ||
105 | tmp = get_reg(child, PT_CCS) & ~SBIT_USER; | ||
106 | put_reg(child, PT_CCS, tmp); | ||
107 | } | ||
108 | } | ||
109 | |||
81 | /* | 110 | /* |
82 | * Called by kernel/ptrace.c when detaching. | 111 | * Called by kernel/ptrace.c when detaching. |
83 | * | 112 | * |
@@ -89,8 +118,7 @@ ptrace_disable(struct task_struct *child) | |||
89 | unsigned long tmp; | 118 | unsigned long tmp; |
90 | 119 | ||
91 | /* Deconfigure SPC and S-bit. */ | 120 | /* Deconfigure SPC and S-bit. */ |
92 | tmp = get_reg(child, PT_CCS) & ~SBIT_USER; | 121 | user_disable_single_step(child); |
93 | put_reg(child, PT_CCS, tmp); | ||
94 | put_reg(child, PT_SPC, 0); | 122 | put_reg(child, PT_SPC, 0); |
95 | 123 | ||
96 | /* Deconfigure any watchpoints associated with the child. */ | 124 | /* Deconfigure any watchpoints associated with the child. */ |
@@ -169,83 +197,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
169 | ret = 0; | 197 | ret = 0; |
170 | break; | 198 | break; |
171 | 199 | ||
172 | case PTRACE_SYSCALL: | ||
173 | case PTRACE_CONT: | ||
174 | ret = -EIO; | ||
175 | |||
176 | if (!valid_signal(data)) | ||
177 | break; | ||
178 | |||
179 | /* Continue means no single-step. */ | ||
180 | put_reg(child, PT_SPC, 0); | ||
181 | |||
182 | if (!get_debugreg(child->pid, PT_BP_CTRL)) { | ||
183 | unsigned long tmp; | ||
184 | /* If no h/w bp configured, disable S bit. */ | ||
185 | tmp = get_reg(child, PT_CCS) & ~SBIT_USER; | ||
186 | put_reg(child, PT_CCS, tmp); | ||
187 | } | ||
188 | |||
189 | if (request == PTRACE_SYSCALL) { | ||
190 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
191 | } | ||
192 | else { | ||
193 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
194 | } | ||
195 | |||
196 | child->exit_code = data; | ||
197 | |||
198 | /* TODO: make sure any pending breakpoint is killed */ | ||
199 | wake_up_process(child); | ||
200 | ret = 0; | ||
201 | |||
202 | break; | ||
203 | |||
204 | /* Make the child exit by sending it a sigkill. */ | ||
205 | case PTRACE_KILL: | ||
206 | ret = 0; | ||
207 | |||
208 | if (child->exit_state == EXIT_ZOMBIE) | ||
209 | break; | ||
210 | |||
211 | child->exit_code = SIGKILL; | ||
212 | |||
213 | /* Deconfigure single-step and h/w bp. */ | ||
214 | ptrace_disable(child); | ||
215 | |||
216 | /* TODO: make sure any pending breakpoint is killed */ | ||
217 | wake_up_process(child); | ||
218 | break; | ||
219 | |||
220 | /* Set the trap flag. */ | ||
221 | case PTRACE_SINGLESTEP: { | ||
222 | unsigned long tmp; | ||
223 | ret = -EIO; | ||
224 | |||
225 | /* Set up SPC if not set already (in which case we have | ||
226 | no other choice but to trust it). */ | ||
227 | if (!get_reg(child, PT_SPC)) { | ||
228 | /* In case we're stopped in a delay slot. */ | ||
229 | tmp = get_reg(child, PT_ERP) & ~1; | ||
230 | put_reg(child, PT_SPC, tmp); | ||
231 | } | ||
232 | tmp = get_reg(child, PT_CCS) | SBIT_USER; | ||
233 | put_reg(child, PT_CCS, tmp); | ||
234 | |||
235 | if (!valid_signal(data)) | ||
236 | break; | ||
237 | |||
238 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
239 | |||
240 | /* TODO: set some clever breakpoint mechanism... */ | ||
241 | |||
242 | child->exit_code = data; | ||
243 | wake_up_process(child); | ||
244 | ret = 0; | ||
245 | break; | ||
246 | |||
247 | } | ||
248 | |||
249 | /* Get all GP registers from the child. */ | 200 | /* Get all GP registers from the child. */ |
250 | case PTRACE_GETREGS: { | 201 | case PTRACE_GETREGS: { |
251 | int i; | 202 | int i; |
diff --git a/arch/cris/include/arch-v32/arch/ptrace.h b/arch/cris/include/arch-v32/arch/ptrace.h index 41f4e8662bc2..ffca8d0f2e17 100644 --- a/arch/cris/include/arch-v32/arch/ptrace.h +++ b/arch/cris/include/arch-v32/arch/ptrace.h | |||
@@ -108,6 +108,7 @@ struct switch_stack { | |||
108 | 108 | ||
109 | #ifdef __KERNEL__ | 109 | #ifdef __KERNEL__ |
110 | 110 | ||
111 | #define arch_has_single_step() (1) | ||
111 | #define user_mode(regs) (((regs)->ccs & (1 << (U_CCS_BITNR + CCS_SHIFT))) != 0) | 112 | #define user_mode(regs) (((regs)->ccs & (1 << (U_CCS_BITNR + CCS_SHIFT))) != 0) |
112 | #define instruction_pointer(regs) ((regs)->erp) | 113 | #define instruction_pointer(regs) ((regs)->erp) |
113 | extern void show_regs(struct pt_regs *); | 114 | extern void show_regs(struct pt_regs *); |