diff options
author | Christoph Hellwig <hch@lst.de> | 2010-03-10 18:22:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:39 -0500 |
commit | 1bd095083558928cc3b36b826422d69bcd743dca (patch) | |
tree | 5cfe9d39ac4da51e438dc87b6ef1203565ae21ac /arch/um | |
parent | 55436c91652b45be576b91ec96a8d65f6b7447fa (diff) |
um: 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.
XXX: I'm not sure arch_has_single_step() is placed in the exactly correct
location, please verify in which of the ptrace headers it should really
be.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/include/asm/ptrace-generic.h | 2 | ||||
-rw-r--r-- | arch/um/kernel/ptrace.c | 70 |
2 files changed, 18 insertions, 54 deletions
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h index 6c8899013c92..2cd899f75a3c 100644 --- a/arch/um/include/asm/ptrace-generic.h +++ b/arch/um/include/asm/ptrace-generic.h | |||
@@ -16,6 +16,8 @@ struct pt_regs { | |||
16 | struct uml_pt_regs regs; | 16 | struct uml_pt_regs regs; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | #define arch_has_single_step() (1) | ||
20 | |||
19 | #define EMPTY_REGS { .regs = EMPTY_UML_PT_REGS } | 21 | #define EMPTY_REGS { .regs = EMPTY_UML_PT_REGS } |
20 | 22 | ||
21 | #define PT_REGS_IP(r) UPT_IP(&(r)->regs) | 23 | #define PT_REGS_IP(r) UPT_IP(&(r)->regs) |
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 8e3d69e4fcb5..484509948ee9 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -12,16 +12,25 @@ | |||
12 | #endif | 12 | #endif |
13 | #include "skas_ptrace.h" | 13 | #include "skas_ptrace.h" |
14 | 14 | ||
15 | static inline void set_singlestepping(struct task_struct *child, int on) | 15 | |
16 | |||
17 | void user_enable_single_step(struct task_struct *child) | ||
16 | { | 18 | { |
17 | if (on) | 19 | child->ptrace |= PT_DTRACE; |
18 | child->ptrace |= PT_DTRACE; | ||
19 | else | ||
20 | child->ptrace &= ~PT_DTRACE; | ||
21 | child->thread.singlestep_syscall = 0; | 20 | child->thread.singlestep_syscall = 0; |
22 | 21 | ||
23 | #ifdef SUBARCH_SET_SINGLESTEPPING | 22 | #ifdef SUBARCH_SET_SINGLESTEPPING |
24 | SUBARCH_SET_SINGLESTEPPING(child, on); | 23 | SUBARCH_SET_SINGLESTEPPING(child, 1); |
24 | #endif | ||
25 | } | ||
26 | |||
27 | void user_disable_single_step(struct task_struct *child) | ||
28 | { | ||
29 | child->ptrace &= ~PT_DTRACE; | ||
30 | child->thread.singlestep_syscall = 0; | ||
31 | |||
32 | #ifdef SUBARCH_SET_SINGLESTEPPING | ||
33 | SUBARCH_SET_SINGLESTEPPING(child, 0); | ||
25 | #endif | 34 | #endif |
26 | } | 35 | } |
27 | 36 | ||
@@ -30,7 +39,7 @@ static inline void set_singlestepping(struct task_struct *child, int on) | |||
30 | */ | 39 | */ |
31 | void ptrace_disable(struct task_struct *child) | 40 | void ptrace_disable(struct task_struct *child) |
32 | { | 41 | { |
33 | set_singlestepping(child,0); | 42 | user_disable_single_step(child); |
34 | } | 43 | } |
35 | 44 | ||
36 | extern int peek_user(struct task_struct * child, long addr, long data); | 45 | extern int peek_user(struct task_struct * child, long addr, long data); |
@@ -69,53 +78,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
69 | ret = -EIO; | 78 | ret = -EIO; |
70 | break; | 79 | break; |
71 | 80 | ||
72 | /* continue and stop at next (return from) syscall */ | ||
73 | case PTRACE_SYSCALL: | ||
74 | /* restart after signal. */ | ||
75 | case PTRACE_CONT: { | ||
76 | ret = -EIO; | ||
77 | if (!valid_signal(data)) | ||
78 | break; | ||
79 | |||
80 | set_singlestepping(child, 0); | ||
81 | if (request == PTRACE_SYSCALL) | ||
82 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
83 | else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
84 | child->exit_code = data; | ||
85 | wake_up_process(child); | ||
86 | ret = 0; | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * make the child exit. Best I can do is send it a sigkill. | ||
92 | * perhaps it should be put in the status that it wants to | ||
93 | * exit. | ||
94 | */ | ||
95 | case PTRACE_KILL: { | ||
96 | ret = 0; | ||
97 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
98 | break; | ||
99 | |||
100 | set_singlestepping(child, 0); | ||
101 | child->exit_code = SIGKILL; | ||
102 | wake_up_process(child); | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | case PTRACE_SINGLESTEP: { /* set the trap flag. */ | ||
107 | ret = -EIO; | ||
108 | if (!valid_signal(data)) | ||
109 | break; | ||
110 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
111 | set_singlestepping(child, 1); | ||
112 | child->exit_code = data; | ||
113 | /* give it a chance to run. */ | ||
114 | wake_up_process(child); | ||
115 | ret = 0; | ||
116 | break; | ||
117 | } | ||
118 | |||
119 | #ifdef PTRACE_GETREGS | 81 | #ifdef PTRACE_GETREGS |
120 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ | 82 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ |
121 | if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) { | 83 | if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) { |