aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-01-30 07:30:52 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:30:52 -0500
commitd9771e8c50020bb1b4ca9eca9c188874ff126aa4 (patch)
tree15b057e88bca53d94ddaf4b7789e15f4053fa94b /arch/x86
parentd0f081758260e9221729cabbc3aba63d89b8c8d4 (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')
-rw-r--r--arch/x86/kernel/ptrace_32.c119
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 */
126static unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
127{
128 return child->thread.debugreg[n];
129}
130
131static 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