Split up ptrace() into a wrapper that does the copying to and from
user space and a kern_ptrace() implementation. Use the kern_*() version in the Linux emulation code to remove more stack gap uses. Approved by: des
This commit is contained in:
parent
d049443a42
commit
0fc3eadf20
@ -34,6 +34,7 @@
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
@ -246,119 +247,92 @@ linux_proc_write_fpxregs(struct thread *td, struct linux_pt_fpxreg *fpxregs)
|
||||
int
|
||||
linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
|
||||
{
|
||||
struct ptrace_args bsd_args;
|
||||
int error;
|
||||
caddr_t sg;
|
||||
union {
|
||||
struct linux_pt_reg reg;
|
||||
struct linux_pt_fpreg fpreg;
|
||||
struct linux_pt_fpxreg fpxreg;
|
||||
} r;
|
||||
|
||||
sg = stackgap_init();
|
||||
union {
|
||||
struct reg bsd_reg;
|
||||
struct fpreg bsd_fpreg;
|
||||
struct dbreg bsd_dbreg;
|
||||
} u;
|
||||
void *addr;
|
||||
pid_t pid;
|
||||
int error, req;
|
||||
|
||||
error = 0;
|
||||
|
||||
/* by default, just copy data intact */
|
||||
bsd_args.req = uap->req;
|
||||
bsd_args.pid = (pid_t)uap->pid;
|
||||
bsd_args.addr = (caddr_t)uap->addr;
|
||||
bsd_args.data = uap->data;
|
||||
req = uap->req;
|
||||
pid = (pid_t)uap->pid;
|
||||
addr = (void *)uap->addr;
|
||||
|
||||
switch (uap->req) {
|
||||
switch (req) {
|
||||
case PTRACE_TRACEME:
|
||||
case PTRACE_POKETEXT:
|
||||
case PTRACE_POKEDATA:
|
||||
case PTRACE_KILL:
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, req, pid, addr, uap->data);
|
||||
break;
|
||||
case PTRACE_PEEKTEXT:
|
||||
case PTRACE_PEEKDATA: {
|
||||
/* need to preserve return value */
|
||||
int rval = td->td_retval[0];
|
||||
bsd_args.data = 0;
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, req, pid, addr, 0);
|
||||
if (error == 0)
|
||||
error = copyout(td->td_retval,
|
||||
(caddr_t)uap->data, sizeof(l_int));
|
||||
error = copyout(td->td_retval, (caddr_t)uap->data,
|
||||
sizeof(l_int));
|
||||
td->td_retval[0] = rval;
|
||||
break;
|
||||
}
|
||||
case PTRACE_DETACH:
|
||||
bsd_args.req = PT_DETACH;
|
||||
/* fall through */
|
||||
error = kern_ptrace(td, PT_DETACH, pid, (void *)1,
|
||||
map_signum(uap->data));
|
||||
break;
|
||||
case PTRACE_SINGLESTEP:
|
||||
case PTRACE_CONT:
|
||||
bsd_args.data = map_signum(uap->data);
|
||||
bsd_args.addr = (caddr_t)1;
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, req, pid, (void *)1,
|
||||
map_signum(uap->data));
|
||||
break;
|
||||
case PTRACE_ATTACH:
|
||||
bsd_args.req = PT_ATTACH;
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
|
||||
break;
|
||||
case PTRACE_GETREGS: {
|
||||
struct reg *bsd_r;
|
||||
|
||||
bsd_r = (struct reg*)stackgap_alloc(&sg, sizeof(*bsd_r));
|
||||
case PTRACE_GETREGS:
|
||||
/* Linux is using data where FreeBSD is using addr */
|
||||
bsd_args.req = PT_GETREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
|
||||
if (error == 0) {
|
||||
map_regs_to_linux(bsd_r, &r.reg);
|
||||
map_regs_to_linux(&u.bsd_reg, &r.reg);
|
||||
error = copyout(&r.reg, (caddr_t)uap->data,
|
||||
sizeof(r.reg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETREGS: {
|
||||
struct reg *bsd_r;
|
||||
|
||||
bsd_r = (struct reg*)stackgap_alloc(&sg, sizeof(*bsd_r));
|
||||
case PTRACE_SETREGS:
|
||||
/* Linux is using data where FreeBSD is using addr */
|
||||
bsd_args.req = PT_SETREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
error = copyin((caddr_t)uap->data, &r.reg, sizeof(r.reg));
|
||||
if (error == 0) {
|
||||
map_regs_from_linux(bsd_r, &r.reg);
|
||||
error = ptrace(td, &bsd_args);
|
||||
map_regs_from_linux(&u.bsd_reg, &r.reg);
|
||||
error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTRACE_GETFPREGS: {
|
||||
struct fpreg *bsd_r;
|
||||
|
||||
bsd_r = (struct fpreg*)stackgap_alloc(&sg, sizeof(*bsd_r));
|
||||
case PTRACE_GETFPREGS:
|
||||
/* Linux is using data where FreeBSD is using addr */
|
||||
bsd_args.req = PT_GETFPREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, PT_GETFPREGS, pid, &u.bsd_fpreg, 0);
|
||||
if (error == 0) {
|
||||
map_fpregs_to_linux(bsd_r, &r.fpreg);
|
||||
map_fpregs_to_linux(&u.bsd_fpreg, &r.fpreg);
|
||||
error = copyout(&r.fpreg, (caddr_t)uap->data,
|
||||
sizeof(r.fpreg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETFPREGS: {
|
||||
struct fpreg *bsd_r;
|
||||
|
||||
bsd_r = (struct fpreg*)stackgap_alloc(&sg, sizeof(*bsd_r));
|
||||
case PTRACE_SETFPREGS:
|
||||
/* Linux is using data where FreeBSD is using addr */
|
||||
bsd_args.req = PT_SETFPREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
error = copyin((caddr_t)uap->data, &r.fpreg, sizeof(r.fpreg));
|
||||
if (error == 0) {
|
||||
map_fpregs_from_linux(bsd_r, &r.fpreg);
|
||||
error = ptrace(td, &bsd_args);
|
||||
map_fpregs_from_linux(&u.bsd_fpreg, &r.fpreg);
|
||||
error = kern_ptrace(td, PT_SETFPREGS, pid,
|
||||
&u.bsd_fpreg, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETFPXREGS:
|
||||
#ifdef CPU_ENABLE_SSA
|
||||
error = copyin((caddr_t)uap->data, &r.fpxreg,
|
||||
@ -415,7 +389,7 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
|
||||
}
|
||||
|
||||
td2 = FIRST_THREAD_IN_PROC(p);
|
||||
if (uap->req == PTRACE_GETFPXREGS) {
|
||||
if (req == PTRACE_GETFPXREGS) {
|
||||
_PHOLD(p);
|
||||
error = linux_proc_read_fpxregs(td2, &r.fpxreg);
|
||||
_PRELE(p);
|
||||
@ -453,20 +427,12 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
|
||||
* as necessary.
|
||||
*/
|
||||
if (uap->addr < sizeof(struct linux_pt_reg)) {
|
||||
struct reg *bsd_r;
|
||||
|
||||
bsd_r = (struct reg*)stackgap_alloc(&sg,
|
||||
sizeof(*bsd_r));
|
||||
bsd_args.req = PT_GETREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, PT_GETREGS, pid, &u.bsd_reg, 0);
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
map_regs_to_linux(bsd_r, &r.reg);
|
||||
if (uap->req == PTRACE_PEEKUSR) {
|
||||
map_regs_to_linux(&u.bsd_reg, &r.reg);
|
||||
if (req == PTRACE_PEEKUSR) {
|
||||
error = copyout((char *)&r.reg + uap->addr,
|
||||
(caddr_t)uap->data, sizeof(l_int));
|
||||
break;
|
||||
@ -475,11 +441,8 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
|
||||
*(l_int *)((char *)&r.reg + uap->addr) =
|
||||
(l_int)uap->data;
|
||||
|
||||
map_regs_from_linux(bsd_r, &r.reg);
|
||||
bsd_args.req = PT_SETREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
error = ptrace(td, &bsd_args);
|
||||
map_regs_from_linux(&u.bsd_reg, &r.reg);
|
||||
error = kern_ptrace(td, PT_SETREGS, pid, &u.bsd_reg, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -487,29 +450,23 @@ linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
|
||||
*/
|
||||
if (uap->addr >= LINUX_DBREG_OFFSET &&
|
||||
uap->addr <= LINUX_DBREG_OFFSET + LINUX_DBREG_SIZE) {
|
||||
struct dbreg *bsd_r;
|
||||
|
||||
bsd_r = (struct dbreg*)stackgap_alloc(&sg,
|
||||
sizeof(*bsd_r));
|
||||
bsd_args.req = PT_GETDBREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
error = ptrace(td, &bsd_args);
|
||||
error = kern_ptrace(td, PT_GETDBREGS, pid, &u.bsd_dbreg,
|
||||
0);
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
uap->addr -= LINUX_DBREG_OFFSET;
|
||||
if (uap->req == PTRACE_PEEKUSR) {
|
||||
error = copyout((char *)bsd_r + uap->addr,
|
||||
(caddr_t)uap->data, sizeof(l_int));
|
||||
if (req == PTRACE_PEEKUSR) {
|
||||
error = copyout((char *)&u.bsd_dbreg +
|
||||
uap->addr, (caddr_t)uap->data,
|
||||
sizeof(l_int));
|
||||
break;
|
||||
}
|
||||
|
||||
*(l_int *)((char *)bsd_r + uap->addr) = uap->data;
|
||||
bsd_args.req = PT_SETDBREGS;
|
||||
bsd_args.addr = (caddr_t)bsd_r;
|
||||
bsd_args.data = 0;
|
||||
error = ptrace(td, &bsd_args);
|
||||
*(l_int *)((char *)&u.bsd_dbreg + uap->addr) =
|
||||
uap->data;
|
||||
error = kern_ptrace(td, PT_SETDBREGS, pid,
|
||||
&u.bsd_dbreg, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
@ -324,8 +325,6 @@ struct ptrace_args {
|
||||
int
|
||||
ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
/*
|
||||
* XXX this obfuscation is to reduce stack usage, but the register
|
||||
* structs may be too large to put on the stack anyway.
|
||||
@ -336,18 +335,70 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
struct fpreg fpreg;
|
||||
struct reg reg;
|
||||
} r;
|
||||
void *addr;
|
||||
int error = 0;
|
||||
|
||||
addr = &r;
|
||||
switch (uap->req) {
|
||||
case PT_GETREGS:
|
||||
case PT_GETFPREGS:
|
||||
case PT_GETDBREGS:
|
||||
break;
|
||||
case PT_SETREGS:
|
||||
error = copyin(uap->addr, &r.reg, sizeof r.reg);
|
||||
break;
|
||||
case PT_SETFPREGS:
|
||||
error = copyin(uap->addr, &r.fpreg, sizeof r.fpreg);
|
||||
break;
|
||||
case PT_SETDBREGS:
|
||||
error = copyin(uap->addr, &r.dbreg, sizeof r.dbreg);
|
||||
break;
|
||||
case PT_IO:
|
||||
error = copyin(uap->addr, &r.piod, sizeof r.piod);
|
||||
break;
|
||||
default:
|
||||
addr = uap->addr;
|
||||
}
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = kern_ptrace(td, uap->req, uap->pid, addr, uap->data);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
switch (uap->req) {
|
||||
case PT_IO:
|
||||
(void)copyout(&r.piod, uap->addr, sizeof r.piod);
|
||||
break;
|
||||
case PT_GETREGS:
|
||||
error = copyout(&r.reg, uap->addr, sizeof r.reg);
|
||||
break;
|
||||
case PT_GETFPREGS:
|
||||
error = copyout(&r.fpreg, uap->addr, sizeof r.fpreg);
|
||||
break;
|
||||
case PT_GETDBREGS:
|
||||
error = copyout(&r.dbreg, uap->addr, sizeof r.dbreg);
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
struct proc *curp, *p, *pp;
|
||||
struct thread *td2;
|
||||
struct ptrace_io_desc *piod;
|
||||
int error, write, tmp;
|
||||
int proctree_locked = 0;
|
||||
|
||||
curp = td->td_proc;
|
||||
|
||||
/*
|
||||
* Do copyin() early before getting locks and lock proctree before
|
||||
* locking the process.
|
||||
*/
|
||||
switch (uap->req) {
|
||||
/* Lock proctree before locking the process. */
|
||||
switch (req) {
|
||||
case PT_TRACE_ME:
|
||||
case PT_ATTACH:
|
||||
case PT_STEP:
|
||||
@ -356,37 +407,16 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
sx_xlock(&proctree_lock);
|
||||
proctree_locked = 1;
|
||||
break;
|
||||
#ifdef PT_SETREGS
|
||||
case PT_SETREGS:
|
||||
error = copyin(uap->addr, &r.reg, sizeof r.reg);
|
||||
if (error)
|
||||
return (error);
|
||||
break;
|
||||
#endif /* PT_SETREGS */
|
||||
#ifdef PT_SETFPREGS
|
||||
case PT_SETFPREGS:
|
||||
error = copyin(uap->addr, &r.fpreg, sizeof r.fpreg);
|
||||
if (error)
|
||||
return (error);
|
||||
break;
|
||||
#endif /* PT_SETFPREGS */
|
||||
#ifdef PT_SETDBREGS
|
||||
case PT_SETDBREGS:
|
||||
error = copyin(uap->addr, &r.dbreg, sizeof r.dbreg);
|
||||
if (error)
|
||||
return (error);
|
||||
break;
|
||||
#endif /* PT_SETDBREGS */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
write = 0;
|
||||
if (uap->req == PT_TRACE_ME) {
|
||||
if (req == PT_TRACE_ME) {
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
} else {
|
||||
if ((p = pfind(uap->pid)) == NULL) {
|
||||
if ((p = pfind(pid)) == NULL) {
|
||||
if (proctree_locked)
|
||||
sx_xunlock(&proctree_lock);
|
||||
return (ESRCH);
|
||||
@ -409,7 +439,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
/*
|
||||
* Permissions check
|
||||
*/
|
||||
switch (uap->req) {
|
||||
switch (req) {
|
||||
case PT_TRACE_ME:
|
||||
/* Always legal. */
|
||||
break;
|
||||
@ -496,7 +526,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
|
||||
td->td_retval[0] = 0;
|
||||
|
||||
switch (uap->req) {
|
||||
switch (req) {
|
||||
case PT_TRACE_ME:
|
||||
/* set my trace flag and "owner" so it can read/write me */
|
||||
p->p_flag |= P_TRACED;
|
||||
@ -511,21 +541,21 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
p->p_oppid = p->p_pptr->p_pid;
|
||||
if (p->p_pptr != td->td_proc)
|
||||
proc_reparent(p, td->td_proc);
|
||||
uap->data = SIGSTOP;
|
||||
data = SIGSTOP;
|
||||
goto sendsig; /* in PT_CONTINUE below */
|
||||
|
||||
case PT_STEP:
|
||||
case PT_CONTINUE:
|
||||
case PT_DETACH:
|
||||
/* XXX uap->data is used even in the PT_STEP case. */
|
||||
if (uap->req != PT_STEP && (unsigned)uap->data > _SIG_MAXSIG) {
|
||||
/* XXX data is used even in the PT_STEP case. */
|
||||
if (req != PT_STEP && (unsigned)data > _SIG_MAXSIG) {
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
_PHOLD(p);
|
||||
|
||||
if (uap->req == PT_STEP) {
|
||||
if (req == PT_STEP) {
|
||||
error = ptrace_single_step(td2);
|
||||
if (error) {
|
||||
_PRELE(p);
|
||||
@ -533,10 +563,9 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
}
|
||||
}
|
||||
|
||||
if (uap->addr != (caddr_t)1) {
|
||||
if (addr != (void *)1) {
|
||||
fill_kinfo_proc(p, &p->p_uarea->u_kproc);
|
||||
error = ptrace_set_pc(td2,
|
||||
(u_long)(uintfptr_t)uap->addr);
|
||||
error = ptrace_set_pc(td2, (u_long)(uintfptr_t)addr);
|
||||
if (error) {
|
||||
_PRELE(p);
|
||||
goto fail;
|
||||
@ -544,7 +573,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
}
|
||||
_PRELE(p);
|
||||
|
||||
if (uap->req == PT_DETACH) {
|
||||
if (req == PT_DETACH) {
|
||||
/* reset process parent */
|
||||
if (p->p_oppid != p->p_pptr->p_pid) {
|
||||
struct proc *pp;
|
||||
@ -569,14 +598,14 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
sx_xunlock(&proctree_lock);
|
||||
/* deliver or queue signal */
|
||||
if (P_SHOULDSTOP(p)) {
|
||||
p->p_xstat = uap->data;
|
||||
p->p_xstat = data;
|
||||
mtx_lock_spin(&sched_lock);
|
||||
p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SGNL);
|
||||
setrunnable(td2); /* XXXKSE */
|
||||
/* Need foreach kse in proc, ... make_kse_queued(). */
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
} else if (uap->data)
|
||||
psignal(p, uap->data);
|
||||
} else if (data)
|
||||
psignal(p, data);
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
return (0);
|
||||
@ -590,11 +619,11 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
PROC_UNLOCK(p);
|
||||
tmp = 0;
|
||||
/* write = 0 set above */
|
||||
iov.iov_base = write ? (caddr_t)&uap->data : (caddr_t)&tmp;
|
||||
iov.iov_base = write ? (caddr_t)&data : (caddr_t)&tmp;
|
||||
iov.iov_len = sizeof(int);
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = (off_t)(uintptr_t)uap->addr;
|
||||
uio.uio_offset = (off_t)(uintptr_t)addr;
|
||||
uio.uio_resid = sizeof(int);
|
||||
uio.uio_segflg = UIO_SYSSPACE; /* i.e.: the uap */
|
||||
uio.uio_rw = write ? UIO_WRITE : UIO_READ;
|
||||
@ -618,18 +647,16 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
return (error);
|
||||
|
||||
case PT_IO:
|
||||
error = copyin(uap->addr, &r.piod, sizeof r.piod);
|
||||
if (error)
|
||||
return (error);
|
||||
iov.iov_base = r.piod.piod_addr;
|
||||
iov.iov_len = r.piod.piod_len;
|
||||
piod = addr;
|
||||
iov.iov_base = piod->piod_addr;
|
||||
iov.iov_len = piod->piod_len;
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = (off_t)(uintptr_t)r.piod.piod_offs;
|
||||
uio.uio_resid = r.piod.piod_len;
|
||||
uio.uio_offset = (off_t)(uintptr_t)piod->piod_offs;
|
||||
uio.uio_resid = piod->piod_len;
|
||||
uio.uio_segflg = UIO_USERSPACE;
|
||||
uio.uio_td = td;
|
||||
switch (r.piod.piod_op) {
|
||||
switch (piod->piod_op) {
|
||||
case PIOD_READ_D:
|
||||
case PIOD_READ_I:
|
||||
uio.uio_rw = UIO_READ;
|
||||
@ -642,60 +669,53 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
return (EINVAL);
|
||||
}
|
||||
error = proc_rwmem(p, &uio);
|
||||
r.piod.piod_len -= uio.uio_resid;
|
||||
(void)copyout(&r.piod, uap->addr, sizeof r.piod);
|
||||
piod->piod_len -= uio.uio_resid;
|
||||
return (error);
|
||||
|
||||
case PT_KILL:
|
||||
uap->data = SIGKILL;
|
||||
data = SIGKILL;
|
||||
goto sendsig; /* in PT_CONTINUE above */
|
||||
|
||||
case PT_SETREGS:
|
||||
_PHOLD(p);
|
||||
error = proc_write_regs(td2, &r.reg);
|
||||
error = proc_write_regs(td2, addr);
|
||||
_PRELE(p);
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
|
||||
case PT_GETREGS:
|
||||
_PHOLD(p);
|
||||
error = proc_read_regs(td2, &r.reg);
|
||||
error = proc_read_regs(td2, addr);
|
||||
_PRELE(p);
|
||||
PROC_UNLOCK(p);
|
||||
if (error == 0)
|
||||
error = copyout(&r.reg, uap->addr, sizeof r.reg);
|
||||
return (error);
|
||||
|
||||
case PT_SETFPREGS:
|
||||
_PHOLD(p);
|
||||
error = proc_write_fpregs(td2, &r.fpreg);
|
||||
error = proc_write_fpregs(td2, addr);
|
||||
_PRELE(p);
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
|
||||
case PT_GETFPREGS:
|
||||
_PHOLD(p);
|
||||
error = proc_read_fpregs(td2, &r.fpreg);
|
||||
error = proc_read_fpregs(td2, addr);
|
||||
_PRELE(p);
|
||||
PROC_UNLOCK(p);
|
||||
if (error == 0)
|
||||
error = copyout(&r.fpreg, uap->addr, sizeof r.fpreg);
|
||||
return (error);
|
||||
|
||||
case PT_SETDBREGS:
|
||||
_PHOLD(p);
|
||||
error = proc_write_dbregs(td2, &r.dbreg);
|
||||
error = proc_write_dbregs(td2, addr);
|
||||
_PRELE(p);
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
|
||||
case PT_GETDBREGS:
|
||||
_PHOLD(p);
|
||||
error = proc_read_dbregs(td2, &r.dbreg);
|
||||
error = proc_read_dbregs(td2, addr);
|
||||
_PRELE(p);
|
||||
PROC_UNLOCK(p);
|
||||
if (error == 0)
|
||||
error = copyout(&r.dbreg, uap->addr, sizeof r.dbreg);
|
||||
return (error);
|
||||
|
||||
default:
|
||||
|
@ -57,6 +57,8 @@ int kern_mknod(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
int mode, int dev);
|
||||
int kern_open(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
int flags, int mode);
|
||||
int kern_ptrace(struct thread *td, int req, pid_t pid, void *addr,
|
||||
int data);
|
||||
int kern_readlink(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
char *buf, enum uio_seg bufseg, int count);
|
||||
int kern_rename(struct thread *td, char *from, char *to,
|
||||
|
Loading…
x
Reference in New Issue
Block a user