diff options
author | Paul Mundt <lethal@linux-sh.org> | 2008-07-30 06:09:31 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-08-01 15:39:33 -0400 |
commit | c459dbf294b4a3d70490a468a7ca3907fb2c2f57 (patch) | |
tree | c78866944d8e03247b6d5072987cd7f7c558caef | |
parent | c4637d475170ca0d99973efd07df727012db6cd1 (diff) |
sh: ptrace single stepping cleanups.
This converts the single stepping done by sh/sh64 ptrace implementations
to use the generic user_enable/disable_single_step(), and subsequently
rips out a lot of ptrace request cases that are now handled generically.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r-- | arch/sh/include/asm/ptrace.h | 9 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_32.c | 93 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_64.c | 77 |
3 files changed, 39 insertions, 140 deletions
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h index 643ab5a7cf3b..b86aeabba61a 100644 --- a/arch/sh/include/asm/ptrace.h +++ b/arch/sh/include/asm/ptrace.h | |||
@@ -104,6 +104,15 @@ struct pt_dspregs { | |||
104 | 104 | ||
105 | extern void show_regs(struct pt_regs *); | 105 | extern void show_regs(struct pt_regs *); |
106 | 106 | ||
107 | /* | ||
108 | * These are defined as per linux/ptrace.h. | ||
109 | */ | ||
110 | struct task_struct; | ||
111 | |||
112 | #define arch_has_single_step() (1) | ||
113 | extern void user_enable_single_step(struct task_struct *); | ||
114 | extern void user_disable_single_step(struct task_struct *); | ||
115 | |||
107 | #ifdef CONFIG_SH_DSP | 116 | #ifdef CONFIG_SH_DSP |
108 | #define task_pt_regs(task) \ | 117 | #define task_pt_regs(task) \ |
109 | ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \ | 118 | ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \ |
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index e9bd4b2aa9c2..ff66f97c564d 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
@@ -58,7 +58,23 @@ static inline int put_stack_long(struct task_struct *task, int offset, | |||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | static void ptrace_disable_singlestep(struct task_struct *child) | 61 | void user_enable_single_step(struct task_struct *child) |
62 | { | ||
63 | struct pt_regs *regs = task_pt_regs(child); | ||
64 | long pc; | ||
65 | |||
66 | pc = get_stack_long(child, (long)®s->pc); | ||
67 | |||
68 | /* Next scheduling will set up UBC */ | ||
69 | if (child->thread.ubc_pc == 0) | ||
70 | ubc_usercnt += 1; | ||
71 | |||
72 | child->thread.ubc_pc = pc; | ||
73 | |||
74 | set_tsk_thread_flag(child, TIF_SINGLESTEP); | ||
75 | } | ||
76 | |||
77 | void user_disable_single_step(struct task_struct *child) | ||
62 | { | 78 | { |
63 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); | 79 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); |
64 | 80 | ||
@@ -82,7 +98,7 @@ static void ptrace_disable_singlestep(struct task_struct *child) | |||
82 | */ | 98 | */ |
83 | void ptrace_disable(struct task_struct *child) | 99 | void ptrace_disable(struct task_struct *child) |
84 | { | 100 | { |
85 | ptrace_disable_singlestep(child); | 101 | user_disable_single_step(child); |
86 | } | 102 | } |
87 | 103 | ||
88 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 104 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
@@ -91,12 +107,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
91 | int ret; | 107 | int ret; |
92 | 108 | ||
93 | switch (request) { | 109 | switch (request) { |
94 | /* when I and D space are separate, these will need to be fixed. */ | ||
95 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | ||
96 | case PTRACE_PEEKDATA: | ||
97 | ret = generic_ptrace_peekdata(child, addr, data); | ||
98 | break; | ||
99 | |||
100 | /* read the word at location addr in the USER area. */ | 110 | /* read the word at location addr in the USER area. */ |
101 | case PTRACE_PEEKUSR: { | 111 | case PTRACE_PEEKUSR: { |
102 | unsigned long tmp; | 112 | unsigned long tmp; |
@@ -126,12 +136,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
126 | break; | 136 | break; |
127 | } | 137 | } |
128 | 138 | ||
129 | /* when I and D space are separate, this will have to be fixed. */ | ||
130 | case PTRACE_POKETEXT: /* write the word at location addr. */ | ||
131 | case PTRACE_POKEDATA: | ||
132 | ret = generic_ptrace_pokedata(child, addr, data); | ||
133 | break; | ||
134 | |||
135 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | 139 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ |
136 | ret = -EIO; | 140 | ret = -EIO; |
137 | if ((addr & 3) || addr < 0 || | 141 | if ((addr & 3) || addr < 0 || |
@@ -152,67 +156,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
152 | } | 156 | } |
153 | break; | 157 | break; |
154 | 158 | ||
155 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | ||
156 | case PTRACE_CONT: { /* restart after signal. */ | ||
157 | ret = -EIO; | ||
158 | if (!valid_signal(data)) | ||
159 | break; | ||
160 | if (request == PTRACE_SYSCALL) | ||
161 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
162 | else | ||
163 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
164 | |||
165 | ptrace_disable_singlestep(child); | ||
166 | |||
167 | child->exit_code = data; | ||
168 | wake_up_process(child); | ||
169 | ret = 0; | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * make the child exit. Best I can do is send it a sigkill. | ||
175 | * perhaps it should be put in the status that it wants to | ||
176 | * exit. | ||
177 | */ | ||
178 | case PTRACE_KILL: { | ||
179 | ret = 0; | ||
180 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
181 | break; | ||
182 | ptrace_disable_singlestep(child); | ||
183 | child->exit_code = SIGKILL; | ||
184 | wake_up_process(child); | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | case PTRACE_SINGLESTEP: { /* set the trap flag. */ | ||
189 | long pc; | ||
190 | struct pt_regs *regs = NULL; | ||
191 | |||
192 | ret = -EIO; | ||
193 | if (!valid_signal(data)) | ||
194 | break; | ||
195 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
196 | if ((child->ptrace & PT_DTRACE) == 0) { | ||
197 | /* Spurious delayed TF traps may occur */ | ||
198 | child->ptrace |= PT_DTRACE; | ||
199 | } | ||
200 | |||
201 | pc = get_stack_long(child, (long)®s->pc); | ||
202 | |||
203 | /* Next scheduling will set up UBC */ | ||
204 | if (child->thread.ubc_pc == 0) | ||
205 | ubc_usercnt += 1; | ||
206 | child->thread.ubc_pc = pc; | ||
207 | |||
208 | set_tsk_thread_flag(child, TIF_SINGLESTEP); | ||
209 | child->exit_code = data; | ||
210 | /* give it a chance to run. */ | ||
211 | wake_up_process(child); | ||
212 | ret = 0; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | #ifdef CONFIG_SH_DSP | 159 | #ifdef CONFIG_SH_DSP |
217 | case PTRACE_GETDSPREGS: { | 160 | case PTRACE_GETDSPREGS: { |
218 | unsigned long dp; | 161 | unsigned long dp; |
diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index 7d8776260953..108f3962e39a 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c | |||
@@ -121,18 +121,23 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data) | |||
121 | return 0; | 121 | return 0; |
122 | } | 122 | } |
123 | 123 | ||
124 | void user_enable_single_step(struct task_struct *child) | ||
125 | { | ||
126 | struct pt_regs *regs = child->thread.uregs; | ||
127 | |||
128 | regs->sr |= SR_SSTEP; /* auto-resetting upon exception */ | ||
129 | } | ||
130 | |||
131 | void user_disable_single_step(struct task_struct *child) | ||
132 | { | ||
133 | regs->sr &= ~SR_SSTEP; | ||
134 | } | ||
124 | 135 | ||
125 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 136 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) |
126 | { | 137 | { |
127 | int ret; | 138 | int ret; |
128 | 139 | ||
129 | switch (request) { | 140 | switch (request) { |
130 | /* when I and D space are separate, these will need to be fixed. */ | ||
131 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | ||
132 | case PTRACE_PEEKDATA: | ||
133 | ret = generic_ptrace_peekdata(child, addr, data); | ||
134 | break; | ||
135 | |||
136 | /* read the word at location addr in the USER area. */ | 141 | /* read the word at location addr in the USER area. */ |
137 | case PTRACE_PEEKUSR: { | 142 | case PTRACE_PEEKUSR: { |
138 | unsigned long tmp; | 143 | unsigned long tmp; |
@@ -155,12 +160,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
155 | break; | 160 | break; |
156 | } | 161 | } |
157 | 162 | ||
158 | /* when I and D space are separate, this will have to be fixed. */ | ||
159 | case PTRACE_POKETEXT: /* write the word at location addr. */ | ||
160 | case PTRACE_POKEDATA: | ||
161 | ret = generic_ptrace_pokedata(child, addr, data); | ||
162 | break; | ||
163 | |||
164 | case PTRACE_POKEUSR: | 163 | case PTRACE_POKEUSR: |
165 | /* write the word at location addr in the USER area. We must | 164 | /* write the word at location addr in the USER area. We must |
166 | disallow any changes to certain SR bits or u_fpvalid, since | 165 | disallow any changes to certain SR bits or u_fpvalid, since |
@@ -192,58 +191,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
192 | } | 191 | } |
193 | break; | 192 | break; |
194 | 193 | ||
195 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | ||
196 | case PTRACE_CONT: { /* restart after signal. */ | ||
197 | ret = -EIO; | ||
198 | if (!valid_signal(data)) | ||
199 | break; | ||
200 | if (request == PTRACE_SYSCALL) | ||
201 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
202 | else | ||
203 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
204 | child->exit_code = data; | ||
205 | wake_up_process(child); | ||
206 | ret = 0; | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * make the child exit. Best I can do is send it a sigkill. | ||
212 | * perhaps it should be put in the status that it wants to | ||
213 | * exit. | ||
214 | */ | ||
215 | case PTRACE_KILL: { | ||
216 | ret = 0; | ||
217 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
218 | break; | ||
219 | child->exit_code = SIGKILL; | ||
220 | wake_up_process(child); | ||
221 | break; | ||
222 | } | ||
223 | |||
224 | case PTRACE_SINGLESTEP: { /* set the trap flag. */ | ||
225 | struct pt_regs *regs; | ||
226 | |||
227 | ret = -EIO; | ||
228 | if (!valid_signal(data)) | ||
229 | break; | ||
230 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
231 | if ((child->ptrace & PT_DTRACE) == 0) { | ||
232 | /* Spurious delayed TF traps may occur */ | ||
233 | child->ptrace |= PT_DTRACE; | ||
234 | } | ||
235 | |||
236 | regs = child->thread.uregs; | ||
237 | |||
238 | regs->sr |= SR_SSTEP; /* auto-resetting upon exception */ | ||
239 | |||
240 | child->exit_code = data; | ||
241 | /* give it a chance to run. */ | ||
242 | wake_up_process(child); | ||
243 | ret = 0; | ||
244 | break; | ||
245 | } | ||
246 | |||
247 | default: | 194 | default: |
248 | ret = ptrace_request(child, request, addr, data); | 195 | ret = ptrace_request(child, request, addr, data); |
249 | break; | 196 | break; |
@@ -341,5 +288,5 @@ asmlinkage void do_software_break_point(unsigned long long vec, | |||
341 | */ | 288 | */ |
342 | void ptrace_disable(struct task_struct *child) | 289 | void ptrace_disable(struct task_struct *child) |
343 | { | 290 | { |
344 | /* nothing to do.. */ | 291 | user_disable_single_step(child); |
345 | } | 292 | } |