supports PTRACE_GETREGSET, PTRACE_SETREGSET.

supports PTRACE_GETFPREGS, PTRACE_SETFPREGS.

refs #421
This commit is contained in:
Susumu Komae
2015-03-06 19:18:32 +09:00
committed by postpeta
parent 6a82412d64
commit b553de7435
3 changed files with 175 additions and 13 deletions

View File

@ -23,12 +23,14 @@
#include <string.h>
#include <errno.h>
#include <kmalloc.h>
#include <uio.h>
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)

View File

@ -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 */

View File

@ -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;
}