x86: x86-32 ptrace debugreg cleanup
authorRoland McGrath <roland@redhat.com>
Wed, 30 Jan 2008 12:30:52 +0000 (13:30 +0100)
committerIngo Molnar <mingo@elte.hu>
Wed, 30 Jan 2008 12:30:52 +0000 (13:30 +0100)
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>
arch/x86/kernel/ptrace_32.c

index a1425e9ad0284a0f304a6dd93a265291963cbe8c..512f8412b799f14f31e7c3ab0be2e15c5bf87823 100644 (file)
@@ -118,6 +118,72 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)
        return retval;
 }
 
+/*
+ * This function is trivial and will be inlined by the compiler.
+ * Having it separates the implementation details of debug
+ * registers from the interface details of ptrace.
+ */
+static unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
+{
+       return child->thread.debugreg[n];
+}
+
+static int ptrace_set_debugreg(struct task_struct *child,
+                              int n, unsigned long data)
+{
+       if (unlikely(n == 4 || n == 5))
+               return -EIO;
+
+       if (n < 4 && unlikely(data >= TASK_SIZE - 3))
+               return -EIO;
+
+       if (n == 7) {
+               /*
+                * Sanity-check data. Take one half-byte at once with
+                * check = (val >> (16 + 4*i)) & 0xf. It contains the
+                * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits
+                * 2 and 3 are LENi. Given a list of invalid values,
+                * we do mask |= 1 << invalid_value, so that
+                * (mask >> check) & 1 is a correct test for invalid
+                * values.
+                *
+                * R/Wi contains the type of the breakpoint /
+                * watchpoint, LENi contains the length of the watched
+                * data in the watchpoint case.
+                *
+                * The invalid values are:
+                * - LENi == 0x10 (undefined), so mask |= 0x0f00.
+                * - R/Wi == 0x10 (break on I/O reads or writes), so
+                *   mask |= 0x4444.
+                * - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
+                *   0x1110.
+                *
+                * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54.
+                *
+                * See the Intel Manual "System Programming Guide",
+                * 15.2.4
+                *
+                * Note that LENi == 0x10 is defined on x86_64 in long
+                * mode (i.e. even for 32-bit userspace software, but
+                * 64-bit kernel), so the x86_64 mask value is 0x5454.
+                * See the AMD manual no. 24593 (AMD64 System Programming)
+                */
+               int i;
+               data &= ~DR_CONTROL_RESERVED;
+               for (i = 0; i < 4; i++)
+                       if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
+                               return -EIO;
+               if (data)
+                       set_tsk_thread_flag(child, TIF_DEBUG);
+               else
+                       clear_tsk_thread_flag(child, TIF_DEBUG);
+       }
+
+       child->thread.debugreg[n] = data;
+
+       return 0;
+}
+
 /*
  * Called by kernel/ptrace.c when detaching..
  *
@@ -158,7 +224,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                   addr <= (long) &dummy->u_debugreg[7]){
                        addr -= (long) &dummy->u_debugreg[0];
                        addr = addr >> 2;
-                       tmp = child->thread.debugreg[addr];
+                       tmp = ptrace_get_debugreg(child, addr);
                }
                ret = put_user(tmp, datap);
                break;
@@ -188,56 +254,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                  ret = -EIO;
                  if(addr >= (long) &dummy->u_debugreg[0] &&
                     addr <= (long) &dummy->u_debugreg[7]){
-
-                         if(addr == (long) &dummy->u_debugreg[4]) break;
-                         if(addr == (long) &dummy->u_debugreg[5]) break;
-                         if(addr < (long) &dummy->u_debugreg[4] &&
-                            ((unsigned long) data) >= TASK_SIZE-3) break;
-                         
-                         /* Sanity-check data. Take one half-byte at once with
-                          * check = (val >> (16 + 4*i)) & 0xf. It contains the
-                          * R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits
-                          * 2 and 3 are LENi. Given a list of invalid values,
-                          * we do mask |= 1 << invalid_value, so that
-                          * (mask >> check) & 1 is a correct test for invalid
-                          * values.
-                          *
-                          * R/Wi contains the type of the breakpoint /
-                          * watchpoint, LENi contains the length of the watched
-                          * data in the watchpoint case.
-                          *
-                          * The invalid values are:
-                          * - LENi == 0x10 (undefined), so mask |= 0x0f00.
-                          * - R/Wi == 0x10 (break on I/O reads or writes), so
-                          *   mask |= 0x4444.
-                          * - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
-                          *   0x1110.
-                          *
-                          * Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54.
-                          *
-                          * See the Intel Manual "System Programming Guide",
-                          * 15.2.4
-                          *
-                          * Note that LENi == 0x10 is defined on x86_64 in long
-                          * mode (i.e. even for 32-bit userspace software, but
-                          * 64-bit kernel), so the x86_64 mask value is 0x5454.
-                          * See the AMD manual no. 24593 (AMD64 System
-                          * Programming)*/
-
-                         if(addr == (long) &dummy->u_debugreg[7]) {
-                                 data &= ~DR_CONTROL_RESERVED;
-                                 for(i=0; i<4; i++)
-                                         if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
-                                                 goto out_tsk;
-                                 if (data)
-                                         set_tsk_thread_flag(child, TIF_DEBUG);
-                                 else
-                                         clear_tsk_thread_flag(child, TIF_DEBUG);
-                         }
                          addr -= (long) &dummy->u_debugreg;
                          addr = addr >> 2;
-                         child->thread.debugreg[addr] = data;
-                         ret = 0;
+                         ret = ptrace_set_debugreg(child, addr, data);
                  }
                  break;
 
@@ -335,7 +354,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                ret = ptrace_request(child, request, addr, data);
                break;
        }
- out_tsk:
+
        return ret;
 }