diff options
| -rw-r--r-- | arch/um/kernel/ptrace.c | 79 | ||||
| -rw-r--r-- | arch/um/sys-i386/ptrace.c | 40 | ||||
| -rw-r--r-- | arch/um/sys-ppc/ptrace.c | 40 | ||||
| -rw-r--r-- | arch/um/sys-x86_64/ptrace.c | 44 |
4 files changed, 153 insertions, 50 deletions
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 3efa59a941a4..2b75d8d9ba73 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
| @@ -19,15 +19,30 @@ | |||
| 19 | #include "skas_ptrace.h" | 19 | #include "skas_ptrace.h" |
| 20 | #include "sysdep/ptrace.h" | 20 | #include "sysdep/ptrace.h" |
| 21 | 21 | ||
| 22 | static inline void set_singlestepping(struct task_struct *child, int on) | ||
| 23 | { | ||
| 24 | if (on) | ||
| 25 | child->ptrace |= PT_DTRACE; | ||
| 26 | else | ||
| 27 | child->ptrace &= ~PT_DTRACE; | ||
| 28 | child->thread.singlestep_syscall = 0; | ||
| 29 | |||
| 30 | #ifdef SUBARCH_SET_SINGLESTEPPING | ||
| 31 | SUBARCH_SET_SINGLESTEPPING(child, on) | ||
| 32 | #endif | ||
| 33 | } | ||
| 34 | |||
| 22 | /* | 35 | /* |
| 23 | * Called by kernel/ptrace.c when detaching.. | 36 | * Called by kernel/ptrace.c when detaching.. |
| 24 | */ | 37 | */ |
| 25 | void ptrace_disable(struct task_struct *child) | 38 | void ptrace_disable(struct task_struct *child) |
| 26 | { | 39 | { |
| 27 | child->ptrace &= ~PT_DTRACE; | 40 | set_singlestepping(child,0); |
| 28 | child->thread.singlestep_syscall = 0; | ||
| 29 | } | 41 | } |
| 30 | 42 | ||
| 43 | extern int peek_user(struct task_struct * child, long addr, long data); | ||
| 44 | extern int poke_user(struct task_struct * child, long addr, long data); | ||
| 45 | |||
| 31 | long sys_ptrace(long request, long pid, long addr, long data) | 46 | long sys_ptrace(long request, long pid, long addr, long data) |
| 32 | { | 47 | { |
| 33 | struct task_struct *child; | 48 | struct task_struct *child; |
| @@ -67,6 +82,10 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
| 67 | goto out_tsk; | 82 | goto out_tsk; |
| 68 | } | 83 | } |
| 69 | 84 | ||
| 85 | #ifdef SUBACH_PTRACE_SPECIAL | ||
| 86 | SUBARCH_PTRACE_SPECIAL(child,request,addr,data) | ||
| 87 | #endif | ||
| 88 | |||
| 70 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | 89 | ret = ptrace_check_attach(child, request == PTRACE_KILL); |
| 71 | if (ret < 0) | 90 | if (ret < 0) |
| 72 | goto out_tsk; | 91 | goto out_tsk; |
| @@ -87,28 +106,9 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
| 87 | } | 106 | } |
| 88 | 107 | ||
| 89 | /* read the word at location addr in the USER area. */ | 108 | /* read the word at location addr in the USER area. */ |
| 90 | case PTRACE_PEEKUSR: { | 109 | case PTRACE_PEEKUSR: |
| 91 | unsigned long tmp; | 110 | ret = peek_user(child, addr, data); |
| 92 | 111 | break; | |
| 93 | ret = -EIO; | ||
| 94 | if ((addr & 3) || addr < 0) | ||
| 95 | break; | ||
| 96 | |||
| 97 | tmp = 0; /* Default return condition */ | ||
| 98 | if(addr < MAX_REG_OFFSET){ | ||
| 99 | tmp = getreg(child, addr); | ||
| 100 | } | ||
| 101 | #if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT) | ||
| 102 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 103 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 104 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 105 | addr = addr >> 2; | ||
| 106 | tmp = child->thread.arch.debugregs[addr]; | ||
| 107 | } | ||
| 108 | #endif | ||
| 109 | ret = put_user(tmp, (unsigned long __user *) data); | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | 112 | ||
| 113 | /* when I and D space are separate, this will have to be fixed. */ | 113 | /* when I and D space are separate, this will have to be fixed. */ |
| 114 | case PTRACE_POKETEXT: /* write the word at location addr. */ | 114 | case PTRACE_POKETEXT: /* write the word at location addr. */ |
| @@ -121,26 +121,8 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
| 121 | break; | 121 | break; |
| 122 | 122 | ||
| 123 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | 123 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ |
| 124 | ret = -EIO; | 124 | ret = poke_user(child, addr, data); |
| 125 | if ((addr & 3) || addr < 0) | 125 | break; |
| 126 | break; | ||
| 127 | |||
| 128 | if (addr < MAX_REG_OFFSET) { | ||
| 129 | ret = putreg(child, addr, data); | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | #if defined(CONFIG_UML_X86) && !defined(CONFIG_64BIT) | ||
| 133 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 134 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 135 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 136 | addr = addr >> 2; | ||
| 137 | if((addr == 4) || (addr == 5)) break; | ||
| 138 | child->thread.arch.debugregs[addr] = data; | ||
| 139 | ret = 0; | ||
| 140 | } | ||
| 141 | #endif | ||
| 142 | |||
| 143 | break; | ||
| 144 | 126 | ||
| 145 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | 127 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ |
| 146 | case PTRACE_CONT: { /* restart after signal. */ | 128 | case PTRACE_CONT: { /* restart after signal. */ |
| @@ -148,8 +130,7 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
| 148 | if (!valid_signal(data)) | 130 | if (!valid_signal(data)) |
| 149 | break; | 131 | break; |
| 150 | 132 | ||
| 151 | child->ptrace &= ~PT_DTRACE; | 133 | set_singlestepping(child, 0); |
| 152 | child->thread.singlestep_syscall = 0; | ||
| 153 | if (request == PTRACE_SYSCALL) { | 134 | if (request == PTRACE_SYSCALL) { |
| 154 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 135 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
| 155 | } | 136 | } |
| @@ -172,8 +153,7 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
| 172 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | 153 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ |
| 173 | break; | 154 | break; |
| 174 | 155 | ||
| 175 | child->ptrace &= ~PT_DTRACE; | 156 | set_singlestepping(child, 0); |
| 176 | child->thread.singlestep_syscall = 0; | ||
| 177 | child->exit_code = SIGKILL; | 157 | child->exit_code = SIGKILL; |
| 178 | wake_up_process(child); | 158 | wake_up_process(child); |
| 179 | break; | 159 | break; |
| @@ -184,8 +164,7 @@ long sys_ptrace(long request, long pid, long addr, long data) | |||
| 184 | if (!valid_signal(data)) | 164 | if (!valid_signal(data)) |
| 185 | break; | 165 | break; |
| 186 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 166 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
| 187 | child->ptrace |= PT_DTRACE; | 167 | set_singlestepping(child, 1); |
| 188 | child->thread.singlestep_syscall = 0; | ||
| 189 | child->exit_code = data; | 168 | child->exit_code = data; |
| 190 | /* give it a chance to run. */ | 169 | /* give it a chance to run. */ |
| 191 | wake_up_process(child); | 170 | wake_up_process(child); |
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index e470d28cdf84..e839ce65ad28 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c | |||
| @@ -73,6 +73,25 @@ int putreg(struct task_struct *child, int regno, unsigned long value) | |||
| 73 | return 0; | 73 | return 0; |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | int poke_user(struct task_struct *child, long addr, long data) | ||
| 77 | { | ||
| 78 | if ((addr & 3) || addr < 0) | ||
| 79 | return -EIO; | ||
| 80 | |||
| 81 | if (addr < MAX_REG_OFFSET) | ||
| 82 | return putreg(child, addr, data); | ||
| 83 | |||
| 84 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 85 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 86 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 87 | addr = addr >> 2; | ||
| 88 | if((addr == 4) || (addr == 5)) return -EIO; | ||
| 89 | child->thread.arch.debugregs[addr] = data; | ||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | return -EIO; | ||
| 93 | } | ||
| 94 | |||
| 76 | unsigned long getreg(struct task_struct *child, int regno) | 95 | unsigned long getreg(struct task_struct *child, int regno) |
| 77 | { | 96 | { |
| 78 | unsigned long retval = ~0UL; | 97 | unsigned long retval = ~0UL; |
| @@ -93,6 +112,27 @@ unsigned long getreg(struct task_struct *child, int regno) | |||
| 93 | return retval; | 112 | return retval; |
| 94 | } | 113 | } |
| 95 | 114 | ||
| 115 | int peek_user(struct task_struct *child, long addr, long data) | ||
| 116 | { | ||
| 117 | /* read the word at location addr in the USER area. */ | ||
| 118 | unsigned long tmp; | ||
| 119 | |||
| 120 | if ((addr & 3) || addr < 0) | ||
| 121 | return -EIO; | ||
| 122 | |||
| 123 | tmp = 0; /* Default return condition */ | ||
| 124 | if(addr < MAX_REG_OFFSET){ | ||
| 125 | tmp = getreg(child, addr); | ||
| 126 | } | ||
| 127 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 128 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 129 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 130 | addr = addr >> 2; | ||
| 131 | tmp = child->thread.arch.debugregs[addr]; | ||
| 132 | } | ||
| 133 | return put_user(tmp, (unsigned long *) data); | ||
| 134 | } | ||
| 135 | |||
| 96 | struct i387_fxsave_struct { | 136 | struct i387_fxsave_struct { |
| 97 | unsigned short cwd; | 137 | unsigned short cwd; |
| 98 | unsigned short swd; | 138 | unsigned short swd; |
diff --git a/arch/um/sys-ppc/ptrace.c b/arch/um/sys-ppc/ptrace.c index a971366d3277..8e71b47f2b8e 100644 --- a/arch/um/sys-ppc/ptrace.c +++ b/arch/um/sys-ppc/ptrace.c | |||
| @@ -8,6 +8,25 @@ int putreg(struct task_struct *child, unsigned long regno, | |||
| 8 | return 0; | 8 | return 0; |
| 9 | } | 9 | } |
| 10 | 10 | ||
| 11 | int poke_user(struct task_struct *child, long addr, long data) | ||
| 12 | { | ||
| 13 | if ((addr & 3) || addr < 0) | ||
| 14 | return -EIO; | ||
| 15 | |||
| 16 | if (addr < MAX_REG_OFFSET) | ||
| 17 | return putreg(child, addr, data); | ||
| 18 | |||
| 19 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 20 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 21 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 22 | addr = addr >> 2; | ||
| 23 | if((addr == 4) || (addr == 5)) return -EIO; | ||
| 24 | child->thread.arch.debugregs[addr] = data; | ||
| 25 | return 0; | ||
| 26 | } | ||
| 27 | return -EIO; | ||
| 28 | } | ||
| 29 | |||
| 11 | unsigned long getreg(struct task_struct *child, unsigned long regno) | 30 | unsigned long getreg(struct task_struct *child, unsigned long regno) |
| 12 | { | 31 | { |
| 13 | unsigned long retval = ~0UL; | 32 | unsigned long retval = ~0UL; |
| @@ -16,6 +35,27 @@ unsigned long getreg(struct task_struct *child, unsigned long regno) | |||
| 16 | return retval; | 35 | return retval; |
| 17 | } | 36 | } |
| 18 | 37 | ||
| 38 | int peek_user(struct task_struct *child, long addr, long data) | ||
| 39 | { | ||
| 40 | /* read the word at location addr in the USER area. */ | ||
| 41 | unsigned long tmp; | ||
| 42 | |||
| 43 | if ((addr & 3) || addr < 0) | ||
| 44 | return -EIO; | ||
| 45 | |||
| 46 | tmp = 0; /* Default return condition */ | ||
| 47 | if(addr < MAX_REG_OFFSET){ | ||
| 48 | tmp = getreg(child, addr); | ||
| 49 | } | ||
| 50 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 51 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 52 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 53 | addr = addr >> 2; | ||
| 54 | tmp = child->thread.arch.debugregs[addr]; | ||
| 55 | } | ||
| 56 | return put_user(tmp, (unsigned long *) data); | ||
| 57 | } | ||
| 58 | |||
| 19 | /* | 59 | /* |
| 20 | * Overrides for Emacs so that we follow Linus's tabbing style. | 60 | * Overrides for Emacs so that we follow Linus's tabbing style. |
| 21 | * Emacs will notice this stuff at the end of the file and automatically | 61 | * Emacs will notice this stuff at the end of the file and automatically |
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index 8c146b2a1e00..b593bb256f2c 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c | |||
| @@ -62,6 +62,27 @@ int putreg(struct task_struct *child, int regno, unsigned long value) | |||
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | int poke_user(struct task_struct *child, long addr, long data) | ||
| 66 | { | ||
| 67 | if ((addr & 3) || addr < 0) | ||
| 68 | return -EIO; | ||
| 69 | |||
| 70 | if (addr < MAX_REG_OFFSET) | ||
| 71 | return putreg(child, addr, data); | ||
| 72 | |||
| 73 | #if 0 /* Need x86_64 debugregs handling */ | ||
| 74 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 75 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 76 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 77 | addr = addr >> 2; | ||
| 78 | if((addr == 4) || (addr == 5)) return -EIO; | ||
| 79 | child->thread.arch.debugregs[addr] = data; | ||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | #endif | ||
| 83 | return -EIO; | ||
| 84 | } | ||
| 85 | |||
| 65 | unsigned long getreg(struct task_struct *child, int regno) | 86 | unsigned long getreg(struct task_struct *child, int regno) |
| 66 | { | 87 | { |
| 67 | unsigned long retval = ~0UL; | 88 | unsigned long retval = ~0UL; |
| @@ -84,6 +105,29 @@ unsigned long getreg(struct task_struct *child, int regno) | |||
| 84 | return retval; | 105 | return retval; |
| 85 | } | 106 | } |
| 86 | 107 | ||
| 108 | int peek_user(struct task_struct *child, long addr, long data) | ||
| 109 | { | ||
| 110 | /* read the word at location addr in the USER area. */ | ||
| 111 | unsigned long tmp; | ||
| 112 | |||
| 113 | if ((addr & 3) || addr < 0) | ||
| 114 | return -EIO; | ||
| 115 | |||
| 116 | tmp = 0; /* Default return condition */ | ||
| 117 | if(addr < MAX_REG_OFFSET){ | ||
| 118 | tmp = getreg(child, addr); | ||
| 119 | } | ||
| 120 | #if 0 /* Need x86_64 debugregs handling */ | ||
| 121 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | ||
| 122 | (addr <= offsetof(struct user, u_debugreg[7]))){ | ||
| 123 | addr -= offsetof(struct user, u_debugreg[0]); | ||
| 124 | addr = addr >> 2; | ||
| 125 | tmp = child->thread.arch.debugregs[addr]; | ||
| 126 | } | ||
| 127 | #endif | ||
| 128 | return put_user(tmp, (unsigned long *) data); | ||
| 129 | } | ||
| 130 | |||
| 87 | void arch_switch(void) | 131 | void arch_switch(void) |
| 88 | { | 132 | { |
| 89 | /* XXX | 133 | /* XXX |
