From b553de7435158c71a373b2869b20f2a411b4867e Mon Sep 17 00:00:00 2001 From: Susumu Komae Date: Fri, 6 Mar 2015 19:18:32 +0900 Subject: [PATCH] supports PTRACE_GETREGSET, PTRACE_SETREGSET. supports PTRACE_GETFPREGS, PTRACE_SETFPREGS. refs #421 --- arch/x86/kernel/syscall.c | 66 +++++++++++++++++++++ kernel/include/process.h | 2 + kernel/syscall.c | 120 +++++++++++++++++++++++++++++++++----- 3 files changed, 175 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/syscall.c b/arch/x86/kernel/syscall.c index 112f34ed..5873b1cb 100644 --- a/arch/x86/kernel/syscall.c +++ b/arch/x86/kernel/syscall.c @@ -23,12 +23,14 @@ #include #include #include +#include void terminate(int, int, ihk_mc_user_context_t *); int copy_from_user(void *dst, const void *src, size_t siz); int copy_to_user(void *dst, const void *src, size_t siz); int write_process_vm(struct process_vm *vm, void *dst, const void *src, size_t siz); long do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact); +extern void save_fp_regs(struct process *proc); //#define DEBUG_PRINT_SC @@ -368,6 +370,70 @@ void set_single_step(struct process *proc) proc->uctx->gpr.rflags |= RFLAGS_TF; } +long ptrace_read_fpregs(struct process *proc, void *fpregs) +{ + save_fp_regs(proc); + if (proc->fp_regs == NULL) { + return -ENOMEM; + } + return copy_to_user(fpregs, &proc->fp_regs->i387, + sizeof(struct i387_fxsave_struct)); +} + +long ptrace_write_fpregs(struct process *proc, void *fpregs) +{ + save_fp_regs(proc); + if (proc->fp_regs == NULL) { + return -ENOMEM; + } + return copy_from_user(&proc->fp_regs->i387, fpregs, + sizeof(struct i387_fxsave_struct)); +} + +long ptrace_read_regset(struct process *proc, long type, struct iovec *iov) +{ + long rc = -EINVAL; + + switch (type) { + case NT_X86_XSTATE: + save_fp_regs(proc); + if (proc->fp_regs == NULL) { + return -ENOMEM; + } + if (iov->iov_len > sizeof(fp_regs_struct)) { + iov->iov_len = sizeof(fp_regs_struct); + } + rc = copy_to_user(&iov->iov_base, proc->fp_regs, iov->iov_len); + break; + default: + kprintf("ptrace_read_regset: not supported type 0x%x\n", type); + break; + } + return rc; +} + +long ptrace_write_regset(struct process *proc, long type, struct iovec *iov) +{ + long rc = -EINVAL; + + switch (type) { + case NT_X86_XSTATE: + save_fp_regs(proc); + if (proc->fp_regs == NULL) { + return -ENOMEM; + } + if (iov->iov_len > sizeof(fp_regs_struct)) { + iov->iov_len = sizeof(fp_regs_struct); + } + rc = copy_from_user(proc->fp_regs, &iov->iov_base, iov->iov_len); + break; + default: + kprintf("ptrace_write_regset: not supported type 0x%x\n", type); + break; + } + return rc; +} + extern void coredump(struct process *proc, void *regs); void ptrace_report_signal(struct process *proc, int sig) diff --git a/kernel/include/process.h b/kernel/include/process.h index f8975ebb..f4a5cae2 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -111,6 +111,8 @@ #define PTRACE_EVENT_VFORK_DONE 5 #define PTRACE_EVENT_EXIT 6 +#define NT_X86_XSTATE 0x202 /* x86 XSAVE extended state */ + #define SIGNAL_STOP_STOPPED 0x1 /* The process has been stopped by SIGSTOP */ #define SIGNAL_STOP_CONTINUED 0x2 /* The process has been resumed by SIGCONT */ diff --git a/kernel/syscall.c b/kernel/syscall.c index c6381b8f..0443bafd 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -2907,6 +2907,102 @@ static long ptrace_arch_prctl(int pid, long code, long addr) return rc; } +extern long ptrace_read_fpregs(struct process *proc, void *fpregs); +extern long ptrace_write_fpregs(struct process *proc, void *fpregs); + +static long ptrace_getfpregs(int pid, long data) +{ + long rc = -EIO; + struct process *child; + ihk_spinlock_t *savelock; + unsigned long irqstate; + + child = findthread_and_lock(pid, -1, &savelock, &irqstate); + if (!child) + return -ESRCH; + if (child->ftn->status == PS_TRACED) { + rc = ptrace_read_fpregs(child, (void *)data); + } + ihk_mc_spinlock_unlock(savelock, irqstate); + + return rc; +} + +static long ptrace_setfpregs(int pid, long data) +{ + long rc = -EIO; + struct process *child; + ihk_spinlock_t *savelock; + unsigned long irqstate; + + child = findthread_and_lock(pid, -1, &savelock, &irqstate); + if (!child) + return -ESRCH; + if (child->ftn->status == PS_TRACED) { + rc = ptrace_write_fpregs(child, (void *)data); + } + ihk_mc_spinlock_unlock(savelock, irqstate); + + return rc; +} + +extern long ptrace_read_regset(struct process *proc, long type, struct iovec *iov); +extern long ptrace_write_regset(struct process *proc, long type, struct iovec *iov); + +static long ptrace_getregset(int pid, long type, long data) +{ + long rc = -EIO; + struct process *child; + ihk_spinlock_t *savelock; + unsigned long irqstate; + + child = findthread_and_lock(pid, -1, &savelock, &irqstate); + if (!child) + return -ESRCH; + if (child->ftn->status == PS_TRACED) { + struct iovec iov; + + rc = copy_from_user(&iov, (struct iovec *)data, sizeof(iov)); + if (rc == 0) { + rc = ptrace_read_regset(child, type, &iov); + } + if (rc == 0) { + rc = copy_to_user(&((struct iovec *)data)->iov_len, + &iov.iov_len, sizeof(iov.iov_len)); + } + } + ihk_mc_spinlock_unlock(savelock, irqstate); + + return rc; +} + +static long ptrace_setregset(int pid, long type, long data) +{ + long rc = -EIO; + struct process *child; + ihk_spinlock_t *savelock; + unsigned long irqstate; + + child = findthread_and_lock(pid, -1, &savelock, &irqstate); + if (!child) + return -ESRCH; + if (child->ftn->status == PS_TRACED) { + struct iovec iov; + + rc = copy_from_user(&iov, (struct iovec *)data, sizeof(iov)); + if (rc == 0) { + rc = ptrace_write_regset(child, type, &iov); + } + if (rc == 0) { + rc = copy_to_user(&((struct iovec *)data)->iov_len, + &iov.iov_len, sizeof(iov.iov_len)); + } + } + ihk_mc_spinlock_unlock(savelock, irqstate); + + return rc; +} + static long ptrace_peektext(int pid, long addr, long data) { long rc = -EIO; @@ -3351,10 +3447,12 @@ SYSCALL_DECLARE(ptrace) error = ptrace_wakeup_sig(pid, request, data); break; case PTRACE_GETFPREGS: - dkprintf("ptrace: unimplemented ptrace(PTRACE_GETFPREGS) called.\n"); + dkprintf("ptrace: PTRACE_GETFPREGS: data=%p\n", data); + error = ptrace_getfpregs(pid, data); break; case PTRACE_SETFPREGS: - dkprintf("ptrace: unimplemented ptrace(PTRACE_SETFPREGS) called.\n"); + dkprintf("ptrace: PTRACE_SETFPREGS: data=%p\n", data); + error = ptrace_setfpregs(pid, data); break; case PTRACE_SETREGS: error = ptrace_setregs(pid, data); @@ -3368,29 +3466,25 @@ SYSCALL_DECLARE(ptrace) dkprintf("ptrace: PTRACE_DETACH: data=%d\n", data); error = ptrace_detach(pid, data); break; - case PTRACE_GETFPXREGS: - dkprintf("ptrace: unimplemented ptrace(PTRACE_GETFPXREGS) called.\n"); - break; case PTRACE_SYSCALL: dkprintf("ptrace: PTRACE_SYSCALL: data=%d\n", data); error = ptrace_wakeup_sig(pid, request, data); break; case PTRACE_GETSIGINFO: - dkprintf("ptrace: unimplemented ptrace(PTRACE_GETSIGINFO) called.\n"); + dkprintf("ptrace: PTRACE_GETSIGINFO: data=%p\n", data); error = ptrace_getsiginfo(pid, (siginfo_t *)data); break; case PTRACE_SETSIGINFO: - dkprintf("ptrace: unimplemented ptrace(PTRACE_SETSIGINFO) called.\n"); + dkprintf("ptrace: PTRACE_SETSIGINFO: data=%p\n", data); error = ptrace_setsiginfo(pid, (siginfo_t *)data); break; case PTRACE_GETREGSET: - dkprintf("ptrace: unimplemented ptrace(PTRACE_GETREGSET) called.\n"); + dkprintf("ptrace: PTRACE_GETREGSET: addr=0x%x, data=%p\n", addr, data); + error = ptrace_getregset(pid, addr, data); break; case PTRACE_SETREGSET: - dkprintf("ptrace: unimplemented ptrace(PTRACE_SETREGSET) called.\n"); - break; - case PTRACE_GET_THREAD_AREA: - dkprintf("ptrace: unimplemented ptrace(PTRACE_GET_THREAD_AREA) called.\n"); + dkprintf("ptrace: PTRACE_SETREGSET: addr=0x%x, data=%p\n", addr, data); + error = ptrace_setregset(pid, addr, data); break; case PTRACE_ARCH_PRCTL: error = ptrace_arch_prctl(pid, data, addr); @@ -3401,7 +3495,7 @@ SYSCALL_DECLARE(ptrace) error = ptrace_geteventmsg(pid, data); break; default: - dkprintf("ptrace: unimplemented ptrace called.\n"); + kprintf("ptrace: unimplemented ptrace(%d) called.\n", request); break; }