Add helper functions proc_readmem() and proc_writemem().
These helper functions can be used to read in or write a buffer from or to an arbitrary process' address space. Without them, this can only be done using proc_rwmem(), which requires the caller to fill out a uio. This is onerous and results in code duplication; the new functions provide a simpler interface which is sufficient for most existing callers of proc_rwmem(). This change also adds a manual page for proc_rwmem() and the new functions. Reviewed by: jhb, kib Differential Revision: https://reviews.freebsd.org/D4245
This commit is contained in:
parent
23d63288c2
commit
711fbd17ec
@ -239,6 +239,7 @@ MAN= accept_filter.9 \
|
||||
printf.9 \
|
||||
prison_check.9 \
|
||||
priv.9 \
|
||||
proc_rwmem.9 \
|
||||
pseudofs.9 \
|
||||
psignal.9 \
|
||||
random.9 \
|
||||
@ -1340,6 +1341,8 @@ MLINKS+=printf.9 log.9 \
|
||||
printf.9 uprintf.9
|
||||
MLINKS+=priv.9 priv_check.9 \
|
||||
priv.9 priv_check_cred.9
|
||||
MLINKS+=proc_rwmem.9 proc_readmem.9 \
|
||||
proc_rwmem.9 proc_writemem.9
|
||||
MLINKS+=psignal.9 gsignal.9 \
|
||||
psignal.9 pgsignal.9 \
|
||||
psignal.9 tdsignal.9
|
||||
|
@ -598,41 +598,21 @@ set_dbregs(struct thread *td, struct dbreg *regs)
|
||||
|
||||
|
||||
static int
|
||||
ptrace_read_int(struct thread *td, vm_offset_t addr, u_int32_t *v)
|
||||
ptrace_read_int(struct thread *td, vm_offset_t addr, uint32_t *v)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
|
||||
PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
|
||||
iov.iov_base = (caddr_t) v;
|
||||
iov.iov_len = sizeof(u_int32_t);
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = (off_t)addr;
|
||||
uio.uio_resid = sizeof(u_int32_t);
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_rw = UIO_READ;
|
||||
uio.uio_td = td;
|
||||
return proc_rwmem(td->td_proc, &uio);
|
||||
if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v))
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ptrace_write_int(struct thread *td, vm_offset_t addr, u_int32_t v)
|
||||
ptrace_write_int(struct thread *td, vm_offset_t addr, uint32_t v)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
|
||||
PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
|
||||
iov.iov_base = (caddr_t) &v;
|
||||
iov.iov_len = sizeof(u_int32_t);
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = (off_t)addr;
|
||||
uio.uio_resid = sizeof(u_int32_t);
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_rw = UIO_WRITE;
|
||||
uio.uio_td = td;
|
||||
return proc_rwmem(td->td_proc, &uio);
|
||||
if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v))
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static u_int
|
||||
|
@ -59,44 +59,32 @@
|
||||
#else
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
static int
|
||||
proc_ops(int op, proc_t *p, void *kaddr, off_t uaddr, size_t len)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
|
||||
iov.iov_base = kaddr;
|
||||
iov.iov_len = len;
|
||||
uio.uio_offset = uaddr;
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_resid = len;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_td = curthread;
|
||||
uio.uio_rw = op;
|
||||
PHOLD(p);
|
||||
if (proc_rwmem(p, &uio) != 0) {
|
||||
PRELE(p);
|
||||
return (-1);
|
||||
}
|
||||
PRELE(p);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
return (proc_ops(UIO_READ, p, kaddr, uaddr, len));
|
||||
PHOLD(p);
|
||||
n = proc_readmem(curthread, p, uaddr, kaddr, len);
|
||||
PRELE(p);
|
||||
if (n != len)
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
return (proc_ops(UIO_WRITE, p, kaddr, uaddr, len));
|
||||
PHOLD(p);
|
||||
n = proc_writemem(curthread, p, uaddr, kaddr, len);
|
||||
PRELE(p);
|
||||
if (n != len)
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* illumos */
|
||||
#ifdef __i386__
|
||||
#define r_rax r_eax
|
||||
|
@ -43,44 +43,30 @@
|
||||
#define OP_RA(x) (((x) & 0x001F0000) >> 16)
|
||||
#define OP_RB(x) (((x) & 0x0000F100) >> 11)
|
||||
|
||||
|
||||
static int
|
||||
proc_ops(int op, proc_t *p, void *kaddr, off_t uaddr, size_t len)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
|
||||
iov.iov_base = kaddr;
|
||||
iov.iov_len = len;
|
||||
uio.uio_offset = uaddr;
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_resid = len;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_td = curthread;
|
||||
uio.uio_rw = op;
|
||||
PHOLD(p);
|
||||
if (proc_rwmem(p, &uio) != 0) {
|
||||
PRELE(p);
|
||||
return (-1);
|
||||
}
|
||||
PRELE(p);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
return (proc_ops(UIO_READ, p, kaddr, uaddr, len));
|
||||
PHOLD(p);
|
||||
n = proc_readmem(curthread, p, uaddr, kaddr, len);
|
||||
PRELE(p);
|
||||
if (n <= 0 || n < len)
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
return (proc_ops(UIO_WRITE, p, kaddr, uaddr, len));
|
||||
PHOLD(p);
|
||||
n = proc_writemem(curthread, p, uaddr, kaddr, len);
|
||||
PRELE(p);
|
||||
if (n <= 0 || n < len)
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1525,51 +1525,21 @@ pargs_drop(struct pargs *pa)
|
||||
pargs_free(pa);
|
||||
}
|
||||
|
||||
static int
|
||||
proc_read_mem(struct thread *td, struct proc *p, vm_offset_t offset, void* buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
|
||||
iov.iov_base = (caddr_t)buf;
|
||||
iov.iov_len = len;
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = offset;
|
||||
uio.uio_resid = (ssize_t)len;
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_rw = UIO_READ;
|
||||
uio.uio_td = td;
|
||||
|
||||
return (proc_rwmem(p, &uio));
|
||||
}
|
||||
|
||||
static int
|
||||
proc_read_string(struct thread *td, struct proc *p, const char *sptr, char *buf,
|
||||
size_t len)
|
||||
{
|
||||
size_t i;
|
||||
int error;
|
||||
ssize_t n;
|
||||
|
||||
error = proc_read_mem(td, p, (vm_offset_t)sptr, buf, len);
|
||||
/*
|
||||
* Reading the chunk may validly return EFAULT if the string is shorter
|
||||
* than the chunk and is aligned at the end of the page, assuming the
|
||||
* next page is not mapped. So if EFAULT is returned do a fallback to
|
||||
* one byte read loop.
|
||||
* This may return a short read if the string is shorter than the chunk
|
||||
* and is aligned at the end of the page, and the following page is not
|
||||
* mapped.
|
||||
*/
|
||||
if (error == EFAULT) {
|
||||
for (i = 0; i < len; i++, buf++, sptr++) {
|
||||
error = proc_read_mem(td, p, (vm_offset_t)sptr, buf, 1);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (*buf == '\0')
|
||||
break;
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
return (error);
|
||||
n = proc_readmem(td, p, (vm_offset_t)sptr, buf, len);
|
||||
if (n <= 0)
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define PROC_AUXV_MAX 256 /* Safety limit on auxv size. */
|
||||
@ -1593,10 +1563,10 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp,
|
||||
size_t vsize, size;
|
||||
int i, error;
|
||||
|
||||
error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
|
||||
&pss, sizeof(pss));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
error = 0;
|
||||
if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss,
|
||||
sizeof(pss)) != sizeof(pss))
|
||||
return (ENOMEM);
|
||||
switch (type) {
|
||||
case PROC_ARG:
|
||||
vptr = (vm_offset_t)PTRIN(pss.ps_argvstr);
|
||||
@ -1618,9 +1588,9 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp,
|
||||
if (vptr % 4 != 0)
|
||||
return (ENOEXEC);
|
||||
for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) {
|
||||
error = proc_read_mem(td, p, ptr, &aux, sizeof(aux));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) !=
|
||||
sizeof(aux))
|
||||
return (ENOMEM);
|
||||
if (aux.a_type == AT_NULL)
|
||||
break;
|
||||
ptr += sizeof(aux);
|
||||
@ -1635,9 +1605,10 @@ get_proc_vector32(struct thread *td, struct proc *p, char ***proc_vectorp,
|
||||
return (EINVAL);
|
||||
}
|
||||
proc_vector32 = malloc(size, M_TEMP, M_WAITOK);
|
||||
error = proc_read_mem(td, p, vptr, proc_vector32, size);
|
||||
if (error != 0)
|
||||
if (proc_readmem(td, p, vptr, proc_vector32, size) != size) {
|
||||
error = ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
if (type == PROC_AUX) {
|
||||
*proc_vectorp = (char **)proc_vector32;
|
||||
*vsizep = vsize;
|
||||
@ -1663,16 +1634,15 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp,
|
||||
vm_offset_t vptr, ptr;
|
||||
char **proc_vector;
|
||||
size_t vsize, size;
|
||||
int error, i;
|
||||
int i;
|
||||
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
if (SV_PROC_FLAG(p, SV_ILP32) != 0)
|
||||
return (get_proc_vector32(td, p, proc_vectorp, vsizep, type));
|
||||
#endif
|
||||
error = proc_read_mem(td, p, (vm_offset_t)(p->p_sysent->sv_psstrings),
|
||||
&pss, sizeof(pss));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (proc_readmem(td, p, (vm_offset_t)p->p_sysent->sv_psstrings, &pss,
|
||||
sizeof(pss)) != sizeof(pss))
|
||||
return (ENOMEM);
|
||||
switch (type) {
|
||||
case PROC_ARG:
|
||||
vptr = (vm_offset_t)pss.ps_argvstr;
|
||||
@ -1709,9 +1679,9 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp,
|
||||
* to the allocated proc_vector.
|
||||
*/
|
||||
for (ptr = vptr, i = 0; i < PROC_AUXV_MAX; i++) {
|
||||
error = proc_read_mem(td, p, ptr, &aux, sizeof(aux));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (proc_readmem(td, p, ptr, &aux, sizeof(aux)) !=
|
||||
sizeof(aux))
|
||||
return (ENOMEM);
|
||||
if (aux.a_type == AT_NULL)
|
||||
break;
|
||||
ptr += sizeof(aux);
|
||||
@ -1732,12 +1702,9 @@ get_proc_vector(struct thread *td, struct proc *p, char ***proc_vectorp,
|
||||
return (EINVAL); /* In case we are built without INVARIANTS. */
|
||||
}
|
||||
proc_vector = malloc(size, M_TEMP, M_WAITOK);
|
||||
if (proc_vector == NULL)
|
||||
return (ENOMEM);
|
||||
error = proc_read_mem(td, p, vptr, proc_vector, size);
|
||||
if (error != 0) {
|
||||
if (proc_readmem(td, p, vptr, proc_vector, size) != size) {
|
||||
free(proc_vector, M_TEMP);
|
||||
return (error);
|
||||
return (ENOMEM);
|
||||
}
|
||||
*proc_vectorp = proc_vector;
|
||||
*vsizep = vsize;
|
||||
|
@ -252,6 +252,7 @@ proc_rwmem(struct proc *p, struct uio *uio)
|
||||
* from exiting out from under us until this operation completes.
|
||||
*/
|
||||
PROC_ASSERT_HELD(p);
|
||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED);
|
||||
|
||||
/*
|
||||
* The map we want...
|
||||
@ -327,6 +328,49 @@ proc_rwmem(struct proc *p, struct uio *uio)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
proc_iop(struct thread *td, struct proc *p, vm_offset_t va, void *buf,
|
||||
size_t len, enum uio_rw rw)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
ssize_t slen;
|
||||
int error;
|
||||
|
||||
MPASS(len < SSIZE_MAX);
|
||||
slen = (ssize_t)len;
|
||||
|
||||
iov.iov_base = (caddr_t)buf;
|
||||
iov.iov_len = len;
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = va;
|
||||
uio.uio_resid = slen;
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_rw = rw;
|
||||
uio.uio_td = td;
|
||||
error = proc_rwmem(p, &uio);
|
||||
if (uio.uio_resid == slen)
|
||||
return (-1);
|
||||
return (slen - uio.uio_resid);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
proc_readmem(struct thread *td, struct proc *p, vm_offset_t va, void *buf,
|
||||
size_t len)
|
||||
{
|
||||
|
||||
return (proc_iop(td, p, va, buf, len, UIO_READ));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
proc_writemem(struct thread *td, struct proc *p, vm_offset_t va, void *buf,
|
||||
size_t len)
|
||||
{
|
||||
|
||||
return (proc_iop(td, p, va, buf, len, UIO_WRITE));
|
||||
}
|
||||
|
||||
static int
|
||||
ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve)
|
||||
{
|
||||
@ -644,7 +688,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
struct thread *td2 = NULL, *td3;
|
||||
struct ptrace_io_desc *piod = NULL;
|
||||
struct ptrace_lwpinfo *pl;
|
||||
int error, write, tmp, num;
|
||||
int error, num, tmp;
|
||||
int proctree_locked = 0;
|
||||
lwpid_t tid = 0, *buf;
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
@ -674,7 +718,6 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
break;
|
||||
}
|
||||
|
||||
write = 0;
|
||||
if (req == PT_TRACE_ME) {
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
@ -1033,46 +1076,28 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
case PT_WRITE_I:
|
||||
case PT_WRITE_D:
|
||||
td2->td_dbgflags |= TDB_USERWR;
|
||||
write = 1;
|
||||
/* FALLTHROUGH */
|
||||
PROC_UNLOCK(p);
|
||||
error = 0;
|
||||
if (proc_writemem(td, p, (off_t)(uintptr_t)addr, &data,
|
||||
sizeof(int)) != sizeof(int))
|
||||
error = ENOMEM;
|
||||
else
|
||||
CTR3(KTR_PTRACE, "PT_WRITE: pid %d: %p <= %#x",
|
||||
p->p_pid, addr, data);
|
||||
PROC_LOCK(p);
|
||||
break;
|
||||
|
||||
case PT_READ_I:
|
||||
case PT_READ_D:
|
||||
PROC_UNLOCK(p);
|
||||
tmp = 0;
|
||||
/* write = 0 set above */
|
||||
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)addr;
|
||||
uio.uio_resid = sizeof(int);
|
||||
uio.uio_segflg = UIO_SYSSPACE; /* i.e.: the uap */
|
||||
uio.uio_rw = write ? UIO_WRITE : UIO_READ;
|
||||
uio.uio_td = td;
|
||||
error = proc_rwmem(p, &uio);
|
||||
if (uio.uio_resid != 0) {
|
||||
/*
|
||||
* XXX proc_rwmem() doesn't currently return ENOSPC,
|
||||
* so I think write() can bogusly return 0.
|
||||
* XXX what happens for short writes? We don't want
|
||||
* to write partial data.
|
||||
* XXX proc_rwmem() returns EPERM for other invalid
|
||||
* addresses. Convert this to EINVAL. Does this
|
||||
* clobber returns of EPERM for other reasons?
|
||||
*/
|
||||
if (error == 0 || error == ENOSPC || error == EPERM)
|
||||
error = EINVAL; /* EOF */
|
||||
}
|
||||
if (!write)
|
||||
td->td_retval[0] = tmp;
|
||||
if (error == 0) {
|
||||
if (write)
|
||||
CTR3(KTR_PTRACE, "PT_WRITE: pid %d: %p <= %#x",
|
||||
p->p_pid, addr, data);
|
||||
else
|
||||
CTR3(KTR_PTRACE, "PT_READ: pid %d: %p >= %#x",
|
||||
p->p_pid, addr, tmp);
|
||||
}
|
||||
error = tmp = 0;
|
||||
if (proc_readmem(td, p, (off_t)(uintptr_t)addr, &tmp,
|
||||
sizeof(int)) != sizeof(int))
|
||||
error = ENOMEM;
|
||||
else
|
||||
CTR3(KTR_PTRACE, "PT_READ: pid %d: %p >= %#x",
|
||||
p->p_pid, addr, tmp);
|
||||
td->td_retval[0] = tmp;
|
||||
PROC_LOCK(p);
|
||||
break;
|
||||
|
||||
|
@ -214,39 +214,19 @@ ptrace_set_pc(struct thread *td, unsigned long addr)
|
||||
static int
|
||||
ptrace_read_int(struct thread *td, off_t addr, int *v)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
|
||||
PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
|
||||
iov.iov_base = (caddr_t) v;
|
||||
iov.iov_len = sizeof(int);
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = (off_t)addr;
|
||||
uio.uio_resid = sizeof(int);
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_rw = UIO_READ;
|
||||
uio.uio_td = td;
|
||||
return proc_rwmem(td->td_proc, &uio);
|
||||
if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v))
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ptrace_write_int(struct thread *td, off_t addr, int v)
|
||||
{
|
||||
struct iovec iov;
|
||||
struct uio uio;
|
||||
|
||||
PROC_LOCK_ASSERT(td->td_proc, MA_NOTOWNED);
|
||||
iov.iov_base = (caddr_t) &v;
|
||||
iov.iov_len = sizeof(int);
|
||||
uio.uio_iov = &iov;
|
||||
uio.uio_iovcnt = 1;
|
||||
uio.uio_offset = (off_t)addr;
|
||||
uio.uio_resid = sizeof(int);
|
||||
uio.uio_segflg = UIO_SYSSPACE;
|
||||
uio.uio_rw = UIO_WRITE;
|
||||
uio.uio_td = td;
|
||||
return proc_rwmem(td->td_proc, &uio);
|
||||
if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v))
|
||||
return (ENOMEM);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -166,6 +166,10 @@ int proc_read_dbregs(struct thread *_td, struct dbreg *_dbreg);
|
||||
int proc_write_dbregs(struct thread *_td, struct dbreg *_dbreg);
|
||||
int proc_sstep(struct thread *_td);
|
||||
int proc_rwmem(struct proc *_p, struct uio *_uio);
|
||||
ssize_t proc_readmem(struct thread *_td, struct proc *_p, vm_offset_t _va,
|
||||
void *_buf, size_t _len);
|
||||
ssize_t proc_writemem(struct thread *_td, struct proc *_p, vm_offset_t _va,
|
||||
void *_buf, size_t _len);
|
||||
#ifdef COMPAT_FREEBSD32
|
||||
struct reg32;
|
||||
struct fpreg32;
|
||||
|
Loading…
Reference in New Issue
Block a user