diff options
Diffstat (limited to 'arch/um/kernel/ptrace.c')
-rw-r--r-- | arch/um/kernel/ptrace.c | 114 |
1 files changed, 56 insertions, 58 deletions
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index bbc3a4a9a0fa..db55a017e9b9 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -1,35 +1,27 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include "linux/sched.h" | ||
7 | #include "linux/mm.h" | ||
8 | #include "linux/errno.h" | ||
9 | #include "linux/smp_lock.h" | ||
10 | #include "linux/security.h" | ||
11 | #include "linux/ptrace.h" | ||
12 | #include "linux/audit.h" | 6 | #include "linux/audit.h" |
7 | #include "linux/ptrace.h" | ||
8 | #include "linux/sched.h" | ||
9 | #include "asm/uaccess.h" | ||
13 | #ifdef CONFIG_PROC_MM | 10 | #ifdef CONFIG_PROC_MM |
14 | #include "linux/proc_mm.h" | 11 | #include "proc_mm.h" |
15 | #endif | 12 | #endif |
16 | #include "asm/ptrace.h" | ||
17 | #include "asm/uaccess.h" | ||
18 | #include "kern_util.h" | ||
19 | #include "skas_ptrace.h" | 13 | #include "skas_ptrace.h" |
20 | #include "sysdep/ptrace.h" | ||
21 | #include "os.h" | ||
22 | 14 | ||
23 | static inline void set_singlestepping(struct task_struct *child, int on) | 15 | static inline void set_singlestepping(struct task_struct *child, int on) |
24 | { | 16 | { |
25 | if (on) | 17 | if (on) |
26 | child->ptrace |= PT_DTRACE; | 18 | child->ptrace |= PT_DTRACE; |
27 | else | 19 | else |
28 | child->ptrace &= ~PT_DTRACE; | 20 | child->ptrace &= ~PT_DTRACE; |
29 | child->thread.singlestep_syscall = 0; | 21 | child->thread.singlestep_syscall = 0; |
30 | 22 | ||
31 | #ifdef SUBARCH_SET_SINGLESTEPPING | 23 | #ifdef SUBARCH_SET_SINGLESTEPPING |
32 | SUBARCH_SET_SINGLESTEPPING(child, on); | 24 | SUBARCH_SET_SINGLESTEPPING(child, on); |
33 | #endif | 25 | #endif |
34 | } | 26 | } |
35 | 27 | ||
@@ -37,8 +29,8 @@ static inline void set_singlestepping(struct task_struct *child, int on) | |||
37 | * Called by kernel/ptrace.c when detaching.. | 29 | * Called by kernel/ptrace.c when detaching.. |
38 | */ | 30 | */ |
39 | void ptrace_disable(struct task_struct *child) | 31 | void ptrace_disable(struct task_struct *child) |
40 | { | 32 | { |
41 | set_singlestepping(child,0); | 33 | set_singlestepping(child,0); |
42 | } | 34 | } |
43 | 35 | ||
44 | extern int peek_user(struct task_struct * child, long addr, long data); | 36 | extern int peek_user(struct task_struct * child, long addr, long data); |
@@ -50,40 +42,40 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
50 | unsigned long __user *p = (void __user *)(unsigned long)data; | 42 | unsigned long __user *p = (void __user *)(unsigned long)data; |
51 | 43 | ||
52 | switch (request) { | 44 | switch (request) { |
53 | /* when I and D space are separate, these will need to be fixed. */ | 45 | /* read word at location addr. */ |
54 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | 46 | case PTRACE_PEEKTEXT: |
55 | case PTRACE_PEEKDATA: | 47 | case PTRACE_PEEKDATA: |
56 | ret = generic_ptrace_peekdata(child, addr, data); | 48 | ret = generic_ptrace_peekdata(child, addr, data); |
57 | break; | 49 | break; |
58 | 50 | ||
59 | /* read the word at location addr in the USER area. */ | 51 | /* read the word at location addr in the USER area. */ |
60 | case PTRACE_PEEKUSR: | 52 | case PTRACE_PEEKUSR: |
61 | ret = peek_user(child, addr, data); | 53 | ret = peek_user(child, addr, data); |
62 | break; | 54 | break; |
63 | 55 | ||
64 | /* when I and D space are separate, this will have to be fixed. */ | 56 | /* write the word at location addr. */ |
65 | case PTRACE_POKETEXT: /* write the word at location addr. */ | 57 | case PTRACE_POKETEXT: |
66 | case PTRACE_POKEDATA: | 58 | case PTRACE_POKEDATA: |
67 | ret = generic_ptrace_pokedata(child, addr, data); | 59 | ret = generic_ptrace_pokedata(child, addr, data); |
68 | break; | 60 | break; |
69 | 61 | ||
70 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | 62 | /* write the word at location addr in the USER area */ |
71 | ret = poke_user(child, addr, data); | 63 | case PTRACE_POKEUSR: |
72 | break; | 64 | ret = poke_user(child, addr, data); |
65 | break; | ||
73 | 66 | ||
74 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | 67 | /* continue and stop at next (return from) syscall */ |
75 | case PTRACE_CONT: { /* restart after signal. */ | 68 | case PTRACE_SYSCALL: |
69 | /* restart after signal. */ | ||
70 | case PTRACE_CONT: { | ||
76 | ret = -EIO; | 71 | ret = -EIO; |
77 | if (!valid_signal(data)) | 72 | if (!valid_signal(data)) |
78 | break; | 73 | break; |
79 | 74 | ||
80 | set_singlestepping(child, 0); | 75 | set_singlestepping(child, 0); |
81 | if (request == PTRACE_SYSCALL) { | 76 | if (request == PTRACE_SYSCALL) |
82 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 77 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
83 | } | 78 | else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
84 | else { | ||
85 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
86 | } | ||
87 | child->exit_code = data; | 79 | child->exit_code = data; |
88 | wake_up_process(child); | 80 | wake_up_process(child); |
89 | ret = 0; | 81 | ret = 0; |
@@ -91,8 +83,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
91 | } | 83 | } |
92 | 84 | ||
93 | /* | 85 | /* |
94 | * make the child exit. Best I can do is send it a sigkill. | 86 | * make the child exit. Best I can do is send it a sigkill. |
95 | * perhaps it should be put in the status that it wants to | 87 | * perhaps it should be put in the status that it wants to |
96 | * exit. | 88 | * exit. |
97 | */ | 89 | */ |
98 | case PTRACE_KILL: { | 90 | case PTRACE_KILL: { |
@@ -100,7 +92,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
100 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | 92 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ |
101 | break; | 93 | break; |
102 | 94 | ||
103 | set_singlestepping(child, 0); | 95 | set_singlestepping(child, 0); |
104 | child->exit_code = SIGKILL; | 96 | child->exit_code = SIGKILL; |
105 | wake_up_process(child); | 97 | wake_up_process(child); |
106 | break; | 98 | break; |
@@ -111,7 +103,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
111 | if (!valid_signal(data)) | 103 | if (!valid_signal(data)) |
112 | break; | 104 | break; |
113 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 105 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
114 | set_singlestepping(child, 1); | 106 | set_singlestepping(child, 1); |
115 | child->exit_code = data; | 107 | child->exit_code = data; |
116 | /* give it a chance to run. */ | 108 | /* give it a chance to run. */ |
117 | wake_up_process(child); | 109 | wake_up_process(child); |
@@ -180,13 +172,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
180 | break; | 172 | break; |
181 | 173 | ||
182 | case PTRACE_FAULTINFO: { | 174 | case PTRACE_FAULTINFO: { |
183 | /* Take the info from thread->arch->faultinfo, | 175 | /* |
176 | * Take the info from thread->arch->faultinfo, | ||
184 | * but transfer max. sizeof(struct ptrace_faultinfo). | 177 | * but transfer max. sizeof(struct ptrace_faultinfo). |
185 | * On i386, ptrace_faultinfo is smaller! | 178 | * On i386, ptrace_faultinfo is smaller! |
186 | */ | 179 | */ |
187 | ret = copy_to_user(p, &child->thread.arch.faultinfo, | 180 | ret = copy_to_user(p, &child->thread.arch.faultinfo, |
188 | sizeof(struct ptrace_faultinfo)); | 181 | sizeof(struct ptrace_faultinfo)); |
189 | if(ret) | 182 | if (ret) |
190 | break; | 183 | break; |
191 | break; | 184 | break; |
192 | } | 185 | } |
@@ -195,12 +188,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
195 | case PTRACE_LDT: { | 188 | case PTRACE_LDT: { |
196 | struct ptrace_ldt ldt; | 189 | struct ptrace_ldt ldt; |
197 | 190 | ||
198 | if(copy_from_user(&ldt, p, sizeof(ldt))){ | 191 | if (copy_from_user(&ldt, p, sizeof(ldt))) { |
199 | ret = -EIO; | 192 | ret = -EIO; |
200 | break; | 193 | break; |
201 | } | 194 | } |
202 | 195 | ||
203 | /* This one is confusing, so just punt and return -EIO for | 196 | /* |
197 | * This one is confusing, so just punt and return -EIO for | ||
204 | * now | 198 | * now |
205 | */ | 199 | */ |
206 | ret = -EIO; | 200 | ret = -EIO; |
@@ -212,7 +206,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
212 | struct mm_struct *old = child->mm; | 206 | struct mm_struct *old = child->mm; |
213 | struct mm_struct *new = proc_mm_get_mm(data); | 207 | struct mm_struct *new = proc_mm_get_mm(data); |
214 | 208 | ||
215 | if(IS_ERR(new)){ | 209 | if (IS_ERR(new)) { |
216 | ret = PTR_ERR(new); | 210 | ret = PTR_ERR(new); |
217 | break; | 211 | break; |
218 | } | 212 | } |
@@ -226,10 +220,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
226 | } | 220 | } |
227 | #endif | 221 | #endif |
228 | #ifdef PTRACE_ARCH_PRCTL | 222 | #ifdef PTRACE_ARCH_PRCTL |
229 | case PTRACE_ARCH_PRCTL: | 223 | case PTRACE_ARCH_PRCTL: |
230 | /* XXX Calls ptrace on the host - needs some SMP thinking */ | 224 | /* XXX Calls ptrace on the host - needs some SMP thinking */ |
231 | ret = arch_prctl(child, data, (void *) addr); | 225 | ret = arch_prctl(child, data, (void *) addr); |
232 | break; | 226 | break; |
233 | #endif | 227 | #endif |
234 | default: | 228 | default: |
235 | ret = ptrace_request(child, request, addr, data); | 229 | ret = ptrace_request(child, request, addr, data); |
@@ -255,7 +249,8 @@ void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, | |||
255 | force_sig_info(SIGTRAP, &info, tsk); | 249 | force_sig_info(SIGTRAP, &info, tsk); |
256 | } | 250 | } |
257 | 251 | ||
258 | /* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and | 252 | /* |
253 | * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and | ||
259 | * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check | 254 | * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check |
260 | */ | 255 | */ |
261 | void syscall_trace(struct uml_pt_regs *regs, int entryexit) | 256 | void syscall_trace(struct uml_pt_regs *regs, int entryexit) |
@@ -272,7 +267,7 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit) | |||
272 | UPT_SYSCALL_ARG3(regs), | 267 | UPT_SYSCALL_ARG3(regs), |
273 | UPT_SYSCALL_ARG4(regs)); | 268 | UPT_SYSCALL_ARG4(regs)); |
274 | else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), | 269 | else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), |
275 | UPT_SYSCALL_RET(regs)); | 270 | UPT_SYSCALL_RET(regs)); |
276 | } | 271 | } |
277 | 272 | ||
278 | /* Fake a debug trap */ | 273 | /* Fake a debug trap */ |
@@ -285,15 +280,18 @@ void syscall_trace(struct uml_pt_regs *regs, int entryexit) | |||
285 | if (!(current->ptrace & PT_PTRACED)) | 280 | if (!(current->ptrace & PT_PTRACED)) |
286 | return; | 281 | return; |
287 | 282 | ||
288 | /* the 0x80 provides a way for the tracing parent to distinguish | 283 | /* |
289 | between a syscall stop and SIGTRAP delivery */ | 284 | * the 0x80 provides a way for the tracing parent to distinguish |
285 | * between a syscall stop and SIGTRAP delivery | ||
286 | */ | ||
290 | tracesysgood = (current->ptrace & PT_TRACESYSGOOD); | 287 | tracesysgood = (current->ptrace & PT_TRACESYSGOOD); |
291 | ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); | 288 | ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); |
292 | 289 | ||
293 | if (entryexit) /* force do_signal() --> is_syscall() */ | 290 | if (entryexit) /* force do_signal() --> is_syscall() */ |
294 | set_thread_flag(TIF_SIGPENDING); | 291 | set_thread_flag(TIF_SIGPENDING); |
295 | 292 | ||
296 | /* this isn't the same as continuing with a signal, but it will do | 293 | /* |
294 | * this isn't the same as continuing with a signal, but it will do | ||
297 | * for normal use. strace only continues with a signal if the | 295 | * for normal use. strace only continues with a signal if the |
298 | * stopping signal is not SIGTRAP. -brl | 296 | * stopping signal is not SIGTRAP. -brl |
299 | */ | 297 | */ |