diff options
author | Roland McGrath <roland@redhat.com> | 2008-01-30 07:30:52 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:30:52 -0500 |
commit | d9771e8c50020bb1b4ca9eca9c188874ff126aa4 (patch) | |
tree | 15b057e88bca53d94ddaf4b7789e15f4053fa94b /arch/x86/kernel/ptrace_32.c | |
parent | d0f081758260e9221729cabbc3aba63d89b8c8d4 (diff) |
x86: x86-32 ptrace debugreg cleanup
This cleans up the 32-bit ptrace code to separate the guts of the
debug register access from the implementation of PTRACE_PEEKUSR and
PTRACE_POKEUSR. The new functions ptrace_[gs]et_debugreg match the
new 64-bit entry points for parity, but they don't need to be global.
Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/ptrace_32.c')
-rw-r--r-- | arch/x86/kernel/ptrace_32.c | 119 |
1 files changed, 69 insertions, 50 deletions
diff --git a/arch/x86/kernel/ptrace_32.c b/arch/x86/kernel/ptrace_32.c index a1425e9ad028..512f8412b799 100644 --- a/arch/x86/kernel/ptrace_32.c +++ b/arch/x86/kernel/ptrace_32.c | |||
@@ -119,6 +119,72 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | /* | 121 | /* |
122 | * This function is trivial and will be inlined by the compiler. | ||
123 | * Having it separates the implementation details of debug | ||
124 | * registers from the interface details of ptrace. | ||
125 | */ | ||
126 | static unsigned long ptrace_get_debugreg(struct task_struct *child, int n) | ||
127 | { | ||
128 | return child->thread.debugreg[n]; | ||
129 | } | ||
130 | |||
131 | static int ptrace_set_debugreg(struct task_struct *child, | ||
132 | int n, unsigned long data) | ||
133 | { | ||
134 | if (unlikely(n == 4 || n == 5)) | ||
135 | return -EIO; | ||
136 | |||
137 | if (n < 4 && unlikely(data >= TASK_SIZE - 3)) | ||
138 | return -EIO; | ||
139 | |||
140 | if (n == 7) { | ||
141 | /* | ||
142 | * Sanity-check data. Take one half-byte at once with | ||
143 | * check = (val >> (16 + 4*i)) & 0xf. It contains the | ||
144 | * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits | ||
145 | * 2 and 3 are LENi. Given a list of invalid values, | ||
146 | * we do mask |= 1 << invalid_value, so that | ||
147 | * (mask >> check) & 1 is a correct test for invalid | ||
148 | * values. | ||
149 | * | ||
150 | * R/Wi contains the type of the breakpoint / | ||
151 | * watchpoint, LENi contains the length of the watched | ||
152 | * data in the watchpoint case. | ||
153 | * | ||
154 | * The invalid values are: | ||
155 | * - LENi == 0x10 (undefined), so mask |= 0x0f00. | ||
156 | * - R/Wi == 0x10 (break on I/O reads or writes), so | ||
157 | * mask |= 0x4444. | ||
158 | * - R/Wi == 0x00 && LENi != 0x00, so we have mask |= | ||
159 | * 0x1110. | ||
160 | * | ||
161 | * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54. | ||
162 | * | ||
163 | * See the Intel Manual "System Programming Guide", | ||
164 | * 15.2.4 | ||
165 | * | ||
166 | * Note that LENi == 0x10 is defined on x86_64 in long | ||
167 | * mode (i.e. even for 32-bit userspace software, but | ||
168 | * 64-bit kernel), so the x86_64 mask value is 0x5454. | ||
169 | * See the AMD manual no. 24593 (AMD64 System Programming) | ||
170 | */ | ||
171 | int i; | ||
172 | data &= ~DR_CONTROL_RESERVED; | ||
173 | for (i = 0; i < 4; i++) | ||
174 | if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) | ||
175 | return -EIO; | ||
176 | if (data) | ||
177 | set_tsk_thread_flag(child, TIF_DEBUG); | ||
178 | else | ||
179 | clear_tsk_thread_flag(child, TIF_DEBUG); | ||
180 | } | ||
181 | |||
182 | child->thread.debugreg[n] = data; | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | /* | ||
122 | * Called by kernel/ptrace.c when detaching.. | 188 | * Called by kernel/ptrace.c when detaching.. |
123 | * | 189 | * |
124 | * Make sure the single step bit is not set. | 190 | * Make sure the single step bit is not set. |
@@ -158,7 +224,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
158 | addr <= (long) &dummy->u_debugreg[7]){ | 224 | addr <= (long) &dummy->u_debugreg[7]){ |
159 | addr -= (long) &dummy->u_debugreg[0]; | 225 | addr -= (long) &dummy->u_debugreg[0]; |
160 | addr = addr >> 2; | 226 | addr = addr >> 2; |
161 | tmp = child->thread.debugreg[addr]; | 227 | tmp = ptrace_get_debugreg(child, addr); |
162 | } | 228 | } |
163 | ret = put_user(tmp, datap); | 229 | ret = put_user(tmp, datap); |
164 | break; | 230 | break; |
@@ -188,56 +254,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
188 | ret = -EIO; | 254 | ret = -EIO; |
189 | if(addr >= (long) &dummy->u_debugreg[0] && | 255 | if(addr >= (long) &dummy->u_debugreg[0] && |
190 | addr <= (long) &dummy->u_debugreg[7]){ | 256 | addr <= (long) &dummy->u_debugreg[7]){ |
191 | |||
192 | if(addr == (long) &dummy->u_debugreg[4]) break; | ||
193 | if(addr == (long) &dummy->u_debugreg[5]) break; | ||
194 | if(addr < (long) &dummy->u_debugreg[4] && | ||
195 | ((unsigned long) data) >= TASK_SIZE-3) break; | ||
196 | |||
197 | /* Sanity-check data. Take one half-byte at once with | ||
198 | * check = (val >> (16 + 4*i)) & 0xf. It contains the | ||
199 | * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits | ||
200 | * 2 and 3 are LENi. Given a list of invalid values, | ||
201 | * we do mask |= 1 << invalid_value, so that | ||
202 | * (mask >> check) & 1 is a correct test for invalid | ||
203 | * values. | ||
204 | * | ||
205 | * R/Wi contains the type of the breakpoint / | ||
206 | * watchpoint, LENi contains the length of the watched | ||
207 | * data in the watchpoint case. | ||
208 | * | ||
209 | * The invalid values are: | ||
210 | * - LENi == 0x10 (undefined), so mask |= 0x0f00. | ||
211 | * - R/Wi == 0x10 (break on I/O reads or writes), so | ||
212 | * mask |= 0x4444. | ||
213 | * - R/Wi == 0x00 && LENi != 0x00, so we have mask |= | ||
214 | * 0x1110. | ||
215 | * | ||
216 | * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54. | ||
217 | * | ||
218 | * See the Intel Manual "System Programming Guide", | ||
219 | * 15.2.4 | ||
220 | * | ||
221 | * Note that LENi == 0x10 is defined on x86_64 in long | ||
222 | * mode (i.e. even for 32-bit userspace software, but | ||
223 | * 64-bit kernel), so the x86_64 mask value is 0x5454. | ||
224 | * See the AMD manual no. 24593 (AMD64 System | ||
225 | * Programming)*/ | ||
226 | |||
227 | if(addr == (long) &dummy->u_debugreg[7]) { | ||
228 | data &= ~DR_CONTROL_RESERVED; | ||
229 | for(i=0; i<4; i++) | ||
230 | if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1) | ||
231 | goto out_tsk; | ||
232 | if (data) | ||
233 | set_tsk_thread_flag(child, TIF_DEBUG); | ||
234 | else | ||
235 | clear_tsk_thread_flag(child, TIF_DEBUG); | ||
236 | } | ||
237 | addr -= (long) &dummy->u_debugreg; | 257 | addr -= (long) &dummy->u_debugreg; |
238 | addr = addr >> 2; | 258 | addr = addr >> 2; |
239 | child->thread.debugreg[addr] = data; | 259 | ret = ptrace_set_debugreg(child, addr, data); |
240 | ret = 0; | ||
241 | } | 260 | } |
242 | break; | 261 | break; |
243 | 262 | ||
@@ -335,7 +354,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
335 | ret = ptrace_request(child, request, addr, data); | 354 | ret = ptrace_request(child, request, addr, data); |
336 | break; | 355 | break; |
337 | } | 356 | } |
338 | out_tsk: | 357 | |
339 | return ret; | 358 | return ret; |
340 | } | 359 | } |
341 | 360 | ||