Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=06ee1b687ac91698ccd47fa652d5b3cf1bfcd806
Commit:     06ee1b687ac91698ccd47fa652d5b3cf1bfcd806
Parent:     e39c2891415b3b5c7381ece06bb45b3c7bdd4342
Author:     Roland McGrath <[EMAIL PROTECTED]>
AuthorDate: Wed Jan 30 13:31:01 2008 +0100
Committer:  Ingo Molnar <[EMAIL PROTECTED]>
CommitDate: Wed Jan 30 13:31:01 2008 +0100

    x86: x86 ptrace getreg/putreg cleanup
    
    This cleans up the getreg/putreg functions to move the special cases
    (segment registers and eflags) out into their own subroutines.
    
    Signed-off-by: Roland McGrath <[EMAIL PROTECTED]>
    Signed-off-by: Ingo Molnar <[EMAIL PROTECTED]>
    Signed-off-by: Thomas Gleixner <[EMAIL PROTECTED]>
---
 arch/x86/kernel/ptrace.c |  162 +++++++++++++++++++++++++++-------------------
 1 files changed, 96 insertions(+), 66 deletions(-)

diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index b71226d..eaec75a 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -45,92 +45,122 @@
 static long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
 {
        BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
+       regno >>= 2;
        if (regno > FS)
                --regno;
        return &regs->bx + regno;
 }
 
-static int putreg(struct task_struct *child,
-       unsigned long regno, unsigned long value)
+static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
 {
-       struct pt_regs *regs = task_pt_regs(child);
-       regno >>= 2;
-       switch (regno) {
-       case GS:
-               if (value && (value & 3) != 3)
-                       return -EIO;
-               child->thread.gs = value;
-               if (child == current)
+       /*
+        * Returning the value truncates it to 16 bits.
+        */
+       unsigned int retval;
+       if (offset != offsetof(struct user_regs_struct, gs))
+               retval = *pt_regs_access(task_pt_regs(task), offset);
+       else {
+               retval = task->thread.gs;
+               if (task == current)
+                       savesegment(gs, retval);
+       }
+       return retval;
+}
+
+static int set_segment_reg(struct task_struct *task,
+                          unsigned long offset, u16 value)
+{
+       /*
+        * The value argument was already truncated to 16 bits.
+        */
+       if (value && (value & 3) != 3)
+               return -EIO;
+
+       if (offset != offsetof(struct user_regs_struct, gs))
+               *pt_regs_access(task_pt_regs(task), offset) = value;
+       else {
+               task->thread.gs = value;
+               if (task == current)
                        /*
                         * The user-mode %gs is not affected by
                         * kernel entry, so we must update the CPU.
                         */
                        loadsegment(gs, value);
-               return 0;
-       case DS:
-       case ES:
-       case FS:
-               if (value && (value & 3) != 3)
-                       return -EIO;
-               value &= 0xffff;
-               break;
-       case SS:
-       case CS:
-               if ((value & 3) != 3)
-                       return -EIO;
-               value &= 0xffff;
-               break;
-       case EFL:
-               value &= FLAG_MASK;
-               /*
-                * If the user value contains TF, mark that
-                * it was not "us" (the debugger) that set it.
-                * If not, make sure it stays set if we had.
-                */
-               if (value & X86_EFLAGS_TF)
-                       clear_tsk_thread_flag(child, TIF_FORCED_TF);
-               else if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-                       value |= X86_EFLAGS_TF;
-               value |= regs->flags & ~FLAG_MASK;
-               break;
        }
-       *pt_regs_access(regs, regno) = value;
+
        return 0;
 }
 
-static unsigned long getreg(struct task_struct *child, unsigned long regno)
+static unsigned long get_flags(struct task_struct *task)
 {
-       struct pt_regs *regs = task_pt_regs(child);
-       unsigned long retval = ~0UL;
+       unsigned long retval = task_pt_regs(task)->flags;
+
+       /*
+        * If the debugger set TF, hide it from the readout.
+        */
+       if (test_tsk_thread_flag(task, TIF_FORCED_TF))
+               retval &= ~X86_EFLAGS_TF;
 
-       regno >>= 2;
-       switch (regno) {
-       case EFL:
-               /*
-                * If the debugger set TF, hide it from the readout.
-                */
-               retval = regs->flags;
-               if (test_tsk_thread_flag(child, TIF_FORCED_TF))
-                       retval &= ~X86_EFLAGS_TF;
-               break;
-       case GS:
-               retval = child->thread.gs;
-               if (child == current)
-                       savesegment(gs, retval);
-               break;
-       case DS:
-       case ES:
-       case FS:
-       case SS:
-       case CS:
-               retval = 0xffff;
-               /* fall through */
-       default:
-               retval &= *pt_regs_access(regs, regno);
-       }
        return retval;
 }
 
+static int set_flags(struct task_struct *task, unsigned long value)
+{
+       struct pt_regs *regs = task_pt_regs(task);
+
+       /*
+        * If the user value contains TF, mark that
+        * it was not "us" (the debugger) that set it.
+        * If not, make sure it stays set if we had.
+        */
+       if (value & X86_EFLAGS_TF)
+               clear_tsk_thread_flag(task, TIF_FORCED_TF);
+       else if (test_tsk_thread_flag(task, TIF_FORCED_TF))
+               value |= X86_EFLAGS_TF;
+
+       regs->flags = (regs->flags & ~FLAG_MASK) | (value & FLAG_MASK);
+
+       return 0;
+}
+
+static int putreg(struct task_struct *child,
+                 unsigned long offset, unsigned long value)
+{
+       switch (offset) {
+       case offsetof(struct user_regs_struct, cs):
+       case offsetof(struct user_regs_struct, ds):
+       case offsetof(struct user_regs_struct, es):
+       case offsetof(struct user_regs_struct, fs):
+       case offsetof(struct user_regs_struct, gs):
+       case offsetof(struct user_regs_struct, ss):
+               return set_segment_reg(child, offset, value);
+
+       case offsetof(struct user_regs_struct, flags):
+               return set_flags(child, value);
+       }
+
+       *pt_regs_access(task_pt_regs(child), offset) = value;
+       return 0;
+}
+
+static unsigned long getreg(struct task_struct *task, unsigned long offset)
+{
+       switch (offset) {
+       case offsetof(struct user_regs_struct, cs):
+       case offsetof(struct user_regs_struct, ds):
+       case offsetof(struct user_regs_struct, es):
+       case offsetof(struct user_regs_struct, fs):
+       case offsetof(struct user_regs_struct, gs):
+       case offsetof(struct user_regs_struct, ss):
+               return get_segment_reg(task, offset);
+
+       case offsetof(struct user_regs_struct, flags):
+               return get_flags(task);
+       }
+
+       return *pt_regs_access(task_pt_regs(task), offset);
+}
+
 /*
  * This function is trivial and will be inlined by the compiler.
  * Having it separates the implementation details of debug
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to