lkml.org 
[lkml]   [2007]   [Nov]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 17/27] x86-64 ptrace debugreg cleanup
    Date

    This cleans up the 64-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 are made
    global so that the ia32 code can later be changed to call them too.

    Signed-off-by: Roland McGrath <roland@redhat.com>
    ---
    arch/x86/kernel/ptrace_64.c | 140 ++++++++++++++++++++-----------------------
    include/asm-x86/ptrace.h | 3 +
    2 files changed, 69 insertions(+), 74 deletions(-)

    diff --git a/arch/x86/kernel/ptrace_64.c b/arch/x86/kernel/ptrace_64.c
    index 8123ecb..bad8b3c 100644
    --- a/arch/x86/kernel/ptrace_64.c
    +++ b/arch/x86/kernel/ptrace_64.c
    @@ -183,9 +183,63 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno)

    }

    +unsigned long ptrace_get_debugreg(struct task_struct *child, int n)
    +{
    + switch (n) {
    + case 0: return child->thread.debugreg0;
    + case 1: return child->thread.debugreg1;
    + case 2: return child->thread.debugreg2;
    + case 3: return child->thread.debugreg3;
    + case 6: return child->thread.debugreg6;
    + case 7: return child->thread.debugreg7;
    + }
    + return 0;
    +}
    +
    +int ptrace_set_debugreg(struct task_struct *child, int n, unsigned long data)
    +{
    + int i;
    +
    + if (n < 4) {
    + int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
    + if (unlikely(data >= TASK_SIZE_OF(child) - dsize))
    + return -EIO;
    + }
    +
    + switch (n) {
    + case 0: child->thread.debugreg0 = data; break;
    + case 1: child->thread.debugreg1 = data; break;
    + case 2: child->thread.debugreg2 = data; break;
    + case 3: child->thread.debugreg3 = data; break;
    +
    + case 6:
    + if (data >> 32)
    + return -EIO;
    + child->thread.debugreg6 = data;
    + break;
    +
    + case 7:
    + /*
    + * See ptrace_32.c for an explanation of this awkward check.
    + */
    + data &= ~DR_CONTROL_RESERVED;
    + for (i = 0; i < 4; i++)
    + if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
    + return -EIO;
    + child->thread.debugreg7 = data;
    + if (data)
    + set_tsk_thread_flag(child, TIF_DEBUG);
    + else
    + clear_tsk_thread_flag(child, TIF_DEBUG);
    + break;
    + }
    +
    + return 0;
    +}
    +
    long arch_ptrace(struct task_struct *child, long request, long addr, long data)
    {
    - long i, ret;
    + long ret;
    unsigned ui;

    switch (request) {
    @@ -204,32 +258,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
    addr > sizeof(struct user) - 7)
    break;

    - switch (addr) {
    - case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
    + tmp = 0;
    + if (addr < sizeof(struct user_regs_struct))
    tmp = getreg(child, addr);
    - break;
    - case offsetof(struct user, u_debugreg[0]):
    - tmp = child->thread.debugreg0;
    - break;
    - case offsetof(struct user, u_debugreg[1]):
    - tmp = child->thread.debugreg1;
    - break;
    - case offsetof(struct user, u_debugreg[2]):
    - tmp = child->thread.debugreg2;
    - break;
    - case offsetof(struct user, u_debugreg[3]):
    - tmp = child->thread.debugreg3;
    - break;
    - case offsetof(struct user, u_debugreg[6]):
    - tmp = child->thread.debugreg6;
    - break;
    - case offsetof(struct user, u_debugreg[7]):
    - tmp = child->thread.debugreg7;
    - break;
    - default:
    - tmp = 0;
    - break;
    + else if (addr >= offsetof(struct user, u_debugreg[0])) {
    + addr -= offsetof(struct user, u_debugreg[0]);
    + tmp = ptrace_get_debugreg(child, addr / sizeof(long));
    }
    +
    ret = put_user(tmp,(unsigned long __user *) data);
    break;
    }
    @@ -241,63 +277,19 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
    break;

    case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
    - {
    - int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
    ret = -EIO;
    if ((addr & 7) ||
    addr > sizeof(struct user) - 7)
    break;

    - switch (addr) {
    - case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
    + if (addr < sizeof(struct user_regs_struct))
    ret = putreg(child, addr, data);
    - break;
    - /* Disallows to set a breakpoint into the vsyscall */
    - case offsetof(struct user, u_debugreg[0]):
    - if (data >= TASK_SIZE_OF(child) - dsize) break;
    - child->thread.debugreg0 = data;
    - ret = 0;
    - break;
    - case offsetof(struct user, u_debugreg[1]):
    - if (data >= TASK_SIZE_OF(child) - dsize) break;
    - child->thread.debugreg1 = data;
    - ret = 0;
    - break;
    - case offsetof(struct user, u_debugreg[2]):
    - if (data >= TASK_SIZE_OF(child) - dsize) break;
    - child->thread.debugreg2 = data;
    - ret = 0;
    - break;
    - case offsetof(struct user, u_debugreg[3]):
    - if (data >= TASK_SIZE_OF(child) - dsize) break;
    - child->thread.debugreg3 = data;
    - ret = 0;
    - break;
    - case offsetof(struct user, u_debugreg[6]):
    - if (data >> 32)
    - break;
    - child->thread.debugreg6 = data;
    - ret = 0;
    - break;
    - case offsetof(struct user, u_debugreg[7]):
    - /* See arch/i386/kernel/ptrace.c for an explanation of
    - * this awkward check.*/
    - data &= ~DR_CONTROL_RESERVED;
    - for(i=0; i<4; i++)
    - if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
    - break;
    - if (i == 4) {
    - child->thread.debugreg7 = data;
    - if (data)
    - set_tsk_thread_flag(child, TIF_DEBUG);
    - else
    - clear_tsk_thread_flag(child, TIF_DEBUG);
    - ret = 0;
    - }
    - break;
    + else if (addr >= offsetof(struct user, u_debugreg[0])) {
    + addr -= offsetof(struct user, u_debugreg[0]);
    + ret = ptrace_set_debugreg(child,
    + addr / sizeof(long), data);
    }
    break;
    - }

    #ifdef CONFIG_IA32_EMULATION
    /* This makes only sense with 32bit programs. Allow a
    diff --git a/include/asm-x86/ptrace.h b/include/asm-x86/ptrace.h
    index fe75422..d223dec 100644
    --- a/include/asm-x86/ptrace.h
    +++ b/include/asm-x86/ptrace.h
    @@ -110,6 +110,9 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);

    struct task_struct;

    +extern unsigned long ptrace_get_debugreg(struct task_struct *child, int n);
    +extern int ptrace_set_debugreg(struct task_struct *child, int n, unsigned long);
    +
    extern unsigned long
    convert_rip_to_linear(struct task_struct *child, struct pt_regs *regs);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2007-11-25 23:09    [W:4.146 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site