summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/ia32/ia32_reg.c224
-rw-r--r--sys/compat/ia32/ia32_reg.h141
-rw-r--r--sys/conf/files.amd641
-rw-r--r--sys/conf/files.ia641
-rw-r--r--sys/fs/procfs/procfs_dbregs.c49
-rw-r--r--sys/fs/procfs/procfs_fpregs.c49
-rw-r--r--sys/fs/procfs/procfs_ioctl.c35
-rw-r--r--sys/fs/procfs/procfs_map.c27
-rw-r--r--sys/fs/procfs/procfs_regs.c49
-rw-r--r--sys/ia64/ia32/ia32_reg.c82
-rw-r--r--sys/kern/imgact_elf.c50
-rw-r--r--sys/kern/kern_clock.c33
-rw-r--r--sys/kern/sys_process.c200
-rw-r--r--sys/sys/ptrace.h11
14 files changed, 908 insertions, 44 deletions
diff --git a/sys/amd64/ia32/ia32_reg.c b/sys/amd64/ia32/ia32_reg.c
new file mode 100644
index 0000000..4f75e4d
--- /dev/null
+++ b/sys/amd64/ia32/ia32_reg.c
@@ -0,0 +1,224 @@
+/*-
+ * Copyright (c) 2005 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/exec.h>
+#include <sys/fcntl.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/mman.h>
+#include <sys/namei.h>
+#include <sys/pioctl.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+#include <sys/resourcevar.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+#include <sys/stat.h>
+#include <sys/sx.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/vnode.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+
+#include <compat/freebsd32/freebsd32_util.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+#include <machine/fpu.h>
+#include <compat/ia32/ia32_reg.h>
+#include <machine/psl.h>
+#include <machine/segments.h>
+#include <machine/specialreg.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/cpufunc.h>
+
+#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
+#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
+
+int
+fill_regs32(struct thread *td, struct reg32 *regs)
+{
+ struct pcb *pcb;
+ struct trapframe *tp;
+
+ tp = td->td_frame;
+ pcb = td->td_pcb;
+ regs->r_fs = pcb->pcb_fs;
+ regs->r_es = pcb->pcb_es;
+ regs->r_ds = pcb->pcb_ds;
+ regs->r_edi = tp->tf_rdi;
+ regs->r_esi = tp->tf_rsi;
+ regs->r_ebp = tp->tf_rbp;
+ regs->r_ebx = tp->tf_rbx;
+ regs->r_edx = tp->tf_rdx;
+ regs->r_ecx = tp->tf_rcx;
+ regs->r_eax = tp->tf_rax;
+ regs->r_eip = tp->tf_rip;
+ regs->r_cs = tp->tf_cs;
+ regs->r_eflags = tp->tf_rflags;
+ regs->r_esp = tp->tf_rsp;
+ regs->r_ss = tp->tf_ss;
+ regs->r_gs = pcb->pcb_gs;
+ return (0);
+}
+
+int
+set_regs32(struct thread *td, struct reg32 *regs)
+{
+ struct pcb *pcb;
+ struct trapframe *tp;
+
+ tp = td->td_frame;
+ if (!EFL_SECURE(regs->r_eflags, tp->tf_rflags) || !CS_SECURE(regs->r_cs))
+ return (EINVAL);
+ pcb = td->td_pcb;
+ load_fs(regs->r_fs);
+ pcb->pcb_fs = regs->r_fs;
+ load_es(regs->r_es);
+ pcb->pcb_es = regs->r_es;
+ load_ds(regs->r_ds);
+ pcb->pcb_ds = regs->r_ds;
+ tp->tf_rdi = regs->r_edi;
+ tp->tf_rsi = regs->r_esi;
+ tp->tf_rbp = regs->r_ebp;
+ tp->tf_rbx = regs->r_ebx;
+ tp->tf_rdx = regs->r_edx;
+ tp->tf_rcx = regs->r_ecx;
+ tp->tf_rax = regs->r_eax;
+ tp->tf_rip = regs->r_eip;
+ tp->tf_cs = regs->r_cs;
+ tp->tf_rflags = regs->r_eflags;
+ tp->tf_rsp = regs->r_esp;
+ tp->tf_ss = regs->r_ss;
+ load_gs(regs->r_gs);
+ pcb->pcb_gs = regs->r_gs;
+ return (0);
+}
+
+int
+fill_fpregs32(struct thread *td, struct fpreg32 *regs)
+{
+ struct save87 *sv_87 = (struct save87 *)regs;
+ struct env87 *penv_87 = &sv_87->sv_env;
+ struct savefpu *sv_fpu = &td->td_pcb->pcb_save;
+ struct envxmm *penv_xmm = &sv_fpu->sv_env;
+ int i;
+
+ bzero(regs, sizeof(*regs));
+
+ /* FPU control/status */
+ penv_87->en_cw = penv_xmm->en_cw;
+ penv_87->en_sw = penv_xmm->en_sw;
+ penv_87->en_tw = penv_xmm->en_tw;
+ /*
+ * XXX for en_fip/fcs/foo/fos, check if the fxsave format
+ * uses the old-style layout for 32 bit user apps. If so,
+ * read the ip and operand segment registers from there.
+ * For now, use the process's %cs/%ds.
+ */
+ penv_87->en_fip = penv_xmm->en_rip;
+ penv_87->en_fcs = td->td_frame->tf_cs;
+ penv_87->en_opcode = penv_xmm->en_opcode;
+ penv_87->en_foo = penv_xmm->en_rdp;
+ penv_87->en_fos = td->td_pcb->pcb_ds;
+
+ /* FPU registers */
+ for (i = 0; i < 8; ++i)
+ sv_87->sv_ac[i] = sv_fpu->sv_fp[i].fp_acc;
+
+ return (0);
+}
+
+int
+set_fpregs32(struct thread *td, struct fpreg32 *regs)
+{
+ struct save87 *sv_87 = (struct save87 *)regs;
+ struct env87 *penv_87 = &sv_87->sv_env;
+ struct savefpu *sv_fpu = &td->td_pcb->pcb_save;
+ struct envxmm *penv_xmm = &sv_fpu->sv_env;
+ int i;
+
+ /* FPU control/status */
+ penv_xmm->en_cw = penv_87->en_cw;
+ penv_xmm->en_sw = penv_87->en_sw;
+ penv_xmm->en_tw = penv_87->en_tw;
+ penv_xmm->en_rip = penv_87->en_fip;
+ /* penv_87->en_fcs and en_fos ignored, see above */
+ penv_xmm->en_opcode = penv_87->en_opcode;
+ penv_xmm->en_rdp = penv_87->en_foo;
+
+ /* FPU registers */
+ for (i = 0; i < 8; ++i)
+ sv_fpu->sv_fp[i].fp_acc = sv_87->sv_ac[i];
+ for (i = 8; i < 16; ++i)
+ bzero(&sv_fpu->sv_fp[i].fp_acc, sizeof(sv_fpu->sv_fp[i].fp_acc));
+
+ return (0);
+}
+
+int
+fill_dbregs32(struct thread *td, struct dbreg32 *regs)
+{
+ struct dbreg dr;
+ int err, i;
+
+ err = fill_dbregs(td, &dr);
+ for (i = 0; i < 8; i++)
+ regs->dr[i] = dr.dr[i];
+ for (i = 8; i < 16; i++)
+ regs->dr[i] = 0;
+ return (err);
+}
+
+int
+set_dbregs32(struct thread *td, struct dbreg32 *regs)
+{
+ struct dbreg dr;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ dr.dr[i] = regs->dr[i];
+ for (i = 8; i < 16; i++)
+ dr.dr[i] = 0;
+ return (set_dbregs(td, &dr));
+}
diff --git a/sys/compat/ia32/ia32_reg.h b/sys/compat/ia32/ia32_reg.h
new file mode 100644
index 0000000..5a9cdf2
--- /dev/null
+++ b/sys/compat/ia32/ia32_reg.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)reg.h 5.5 (Berkeley) 1/18/91
+ * $FreeBSD$
+ */
+
+#ifndef _COMPAT_IA32_IA32_REG_H_
+#define _COMPAT_IA32_IA32_REG_H_
+
+/*
+ * Register set accessible via /proc/$pid/regs and PT_{SET,GET}REGS.
+ */
+struct reg32 {
+ unsigned int r_fs;
+ unsigned int r_es;
+ unsigned int r_ds;
+ unsigned int r_edi;
+ unsigned int r_esi;
+ unsigned int r_ebp;
+ unsigned int r_isp;
+ unsigned int r_ebx;
+ unsigned int r_edx;
+ unsigned int r_ecx;
+ unsigned int r_eax;
+ unsigned int r_trapno;
+ unsigned int r_err;
+ unsigned int r_eip;
+ unsigned int r_cs;
+ unsigned int r_eflags;
+ unsigned int r_esp;
+ unsigned int r_ss;
+ unsigned int r_gs;
+};
+
+/*
+ * Register set accessible via /proc/$pid/fpregs.
+ */
+struct fpreg32 {
+ unsigned int fpr_env[7];
+ unsigned char fpr_acc[8][10];
+ unsigned int fpr_ex_sw;
+ unsigned char fpr_pad[64];
+};
+
+/*
+ * Register set accessible via /proc/$pid/dbregs.
+ */
+struct dbreg32 {
+ unsigned int dr[8]; /* debug registers */
+};
+
+/* Environment information of floating point unit */
+struct env87 {
+ int en_cw; /* control word (16bits) */
+ int en_sw; /* status word (16bits) */
+ int en_tw; /* tag word (16bits) */
+ int en_fip; /* floating point instruction pointer */
+ u_short en_fcs; /* floating code segment selector */
+ u_short en_opcode; /* opcode last executed (11 bits ) */
+ int en_foo; /* floating operand offset */
+ int en_fos; /* floating operand segment selector */
+};
+
+#ifdef __ia64__
+/* Layout of an x87 fpu register (amd64 gets this elsewhere) */
+struct fpacc87 {
+ u_char fp_bytes[10];
+};
+#endif
+
+/* Floating point context */
+struct save87 {
+ struct env87 sv_env; /* floating point control/status */
+ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
+ u_char sv_pad0[4]; /* padding for (now unused) saved status word */
+ u_char sv_pad[64]; /* padding; used by emulators */
+};
+
+
+/*
+ * Alternative layouts for <sys/procfs.h>
+ * Used in core dumps, the reason for this file existing.
+ */
+struct prstatus32 {
+ int pr_version;
+ u_int pr_statussz;
+ u_int pr_gregsetsz;
+ u_int pr_fpregsetsz;
+ int pr_osreldate;
+ int pr_cursig;
+ pid_t pr_pid;
+ struct reg32 pr_reg;
+};
+
+struct prpsinfo32 {
+ int pr_version;
+ u_int pr_psinfosz;
+ char pr_fname[PRFNAMESZ+1];
+ char pr_psargs[PRARGSZ+1];
+};
+
+/*
+ * Wrappers and converters.
+ */
+int fill_regs32(struct thread *, struct reg32 *);
+int set_regs32(struct thread *, struct reg32 *);
+int fill_fpregs32(struct thread *, struct fpreg32 *);
+int set_fpregs32(struct thread *, struct fpreg32 *);
+int fill_dbregs32(struct thread *, struct dbreg32 *);
+int set_dbregs32(struct thread *, struct dbreg32 *);
+
+#endif /* !_COMPAT_IA32_IA32_REG_H_ */
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index a2b594c..a1b201f 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -188,6 +188,7 @@ pci/agp_intel.c optional agp
# IA32 binary support
#
#amd64/ia32/ia32_exception.S optional compat_ia32
+amd64/ia32/ia32_reg.c optional compat_ia32
amd64/ia32/ia32_signal.c optional compat_ia32
amd64/ia32/ia32_sigtramp.S optional compat_ia32
amd64/ia32/ia32_syscall.c optional compat_ia32
diff --git a/sys/conf/files.ia64 b/sys/conf/files.ia64
index 40be450..856e5c5 100644
--- a/sys/conf/files.ia64
+++ b/sys/conf/files.ia64
@@ -89,6 +89,7 @@ ia64/acpica/madt.c optional acpi
ia64/disasm/disasm_decode.c standard
ia64/disasm/disasm_extract.c standard
ia64/disasm/disasm_format.c standard
+ia64/ia32/ia32_reg.c optional compat_ia32
ia64/ia32/ia32_signal.c optional compat_ia32
ia64/ia32/ia32_sigtramp.c optional compat_ia32
ia64/ia32/ia32_trap.c optional compat_ia32
diff --git a/sys/fs/procfs/procfs_dbregs.c b/sys/fs/procfs/procfs_dbregs.c
index 0e129bb..c30f231 100644
--- a/sys/fs/procfs/procfs_dbregs.c
+++ b/sys/fs/procfs/procfs_dbregs.c
@@ -43,6 +43,8 @@
* $FreeBSD$
*/
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
@@ -56,11 +58,42 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/procfs/procfs.h>
+#ifdef COMPAT_IA32
+#include <sys/procfs.h>
+#include <machine/fpu.h>
+#include <compat/ia32/ia32_reg.h>
+
+extern struct sysentvec ia32_freebsd_sysvec;
+/*
+ * PROC(write, dbregs, td2, &r) becomes
+ * proc_write_dbregs(td2, &r) or
+ * proc_write_dbregs32(td2, &r32)
+ *
+ * UIOMOVE_FROMBUF(r, uio) becomes
+ * uiomove_frombuf(&r, sizeof(r), uio) or
+ * uiomove_frombuf(&r32, sizeof(r32), uio)
+ */
+#define PROC(d, w, t, r) wrap32 ? \
+ proc_ ## d ## _ ## w ## 32(t, r ## 32) : \
+ proc_ ## d ## _ ## w(t, r)
+#define UIOMOVE_FROMBUF(k, u) wrap32 ? \
+ uiomove_frombuf(& k ## 32, sizeof(k ## 32), u) : \
+ uiomove_frombuf(& k, sizeof(k), u)
+#else
+#define PROC(d, w, t, r) proc_ ## d ## _ ## w(t, r)
+#define UIOMOVE_FROMBUF(k, u) uiomove_frombuf(& k, sizeof(k), u)
+#endif
+
int
procfs_doprocdbregs(PFS_FILL_ARGS)
{
int error;
struct dbreg r;
+ struct thread *td2;
+#ifdef COMPAT_IA32
+ struct dbreg32 r32;
+ int wrap32 = 0;
+#endif
PROC_LOCK(p);
KASSERT(p->p_lock > 0, ("proc not held"));
@@ -70,10 +103,20 @@ procfs_doprocdbregs(PFS_FILL_ARGS)
}
/* XXXKSE: */
- error = proc_read_dbregs(FIRST_THREAD_IN_PROC(p), &r);
+ td2 = FIRST_THREAD_IN_PROC(p);
+#ifdef COMPAT_IA32
+ if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) {
+ if (td2->td_proc->p_sysent != &ia32_freebsd_sysvec) {
+ PROC_UNLOCK(p);
+ return (EINVAL);
+ }
+ wrap32 = 1;
+ }
+#endif
+ error = PROC(read, dbregs, td2, &r);
if (error == 0) {
PROC_UNLOCK(p);
- error = uiomove_frombuf(&r, sizeof(r), uio);
+ error = UIOMOVE_FROMBUF(r, uio);
PROC_LOCK(p);
}
if (error == 0 && uio->uio_rw == UIO_WRITE) {
@@ -81,7 +124,7 @@ procfs_doprocdbregs(PFS_FILL_ARGS)
error = EBUSY;
else
/* XXXKSE: */
- error = proc_write_dbregs(FIRST_THREAD_IN_PROC(p), &r);
+ error = PROC(write, dbregs, td2, &r);
}
PROC_UNLOCK(p);
diff --git a/sys/fs/procfs/procfs_fpregs.c b/sys/fs/procfs/procfs_fpregs.c
index 93356ce..cb9797b 100644
--- a/sys/fs/procfs/procfs_fpregs.c
+++ b/sys/fs/procfs/procfs_fpregs.c
@@ -37,6 +37,8 @@
* $FreeBSD$
*/
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
@@ -50,11 +52,42 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/procfs/procfs.h>
+#ifdef COMPAT_IA32
+#include <sys/procfs.h>
+#include <machine/fpu.h>
+#include <compat/ia32/ia32_reg.h>
+
+extern struct sysentvec ia32_freebsd_sysvec;
+/*
+ * PROC(write, fpregs, td2, &r) becomes
+ * proc_write_fpregs(td2, &r) or
+ * proc_write_fpregs32(td2, &r32)
+ *
+ * UIOMOVE_FROMBUF(r, uio) becomes
+ * uiomove_frombuf(&r, sizeof(r), uio) or
+ * uiomove_frombuf(&r32, sizeof(r32), uio)
+ */
+#define PROC(d, w, t, r) wrap32 ? \
+ proc_ ## d ## _ ## w ## 32(t, r ## 32) : \
+ proc_ ## d ## _ ## w(t, r)
+#define UIOMOVE_FROMBUF(k, u) wrap32 ? \
+ uiomove_frombuf(& k ## 32, sizeof(k ## 32), u) : \
+ uiomove_frombuf(& k, sizeof(k), u)
+#else
+#define PROC(d, w, t, r) proc_ ## d ## _ ## w(t, r)
+#define UIOMOVE_FROMBUF(k, u) uiomove_frombuf(& k, sizeof(k), u)
+#endif
+
int
procfs_doprocfpregs(PFS_FILL_ARGS)
{
int error;
struct fpreg r;
+ struct thread *td2;
+#ifdef COMPAT_IA32
+ struct fpreg32 r32;
+ int wrap32 = 0;
+#endif
PROC_LOCK(p);
KASSERT(p->p_lock > 0, ("proc not held"));
@@ -64,10 +97,20 @@ procfs_doprocfpregs(PFS_FILL_ARGS)
}
/* XXXKSE: */
- error = proc_read_fpregs(FIRST_THREAD_IN_PROC(p), &r);
+ td2 = FIRST_THREAD_IN_PROC(p);
+#ifdef COMPAT_IA32
+ if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) {
+ if (td2->td_proc->p_sysent != &ia32_freebsd_sysvec) {
+ PROC_UNLOCK(p);
+ return (EINVAL);
+ }
+ wrap32 = 1;
+ }
+#endif
+ error = PROC(read, fpregs, td2, &r);
if (error == 0) {
PROC_UNLOCK(p);
- error = uiomove_frombuf(&r, sizeof(r), uio);
+ error = UIOMOVE_FROMBUF(r, uio);
PROC_LOCK(p);
}
if (error == 0 && uio->uio_rw == UIO_WRITE) {
@@ -75,7 +118,7 @@ procfs_doprocfpregs(PFS_FILL_ARGS)
error = EBUSY;
else
/* XXXKSE: */
- error = proc_write_fpregs(FIRST_THREAD_IN_PROC(p), &r);
+ error = PROC(write, fpregs, td2, &r);
}
PROC_UNLOCK(p);
diff --git a/sys/fs/procfs/procfs_ioctl.c b/sys/fs/procfs/procfs_ioctl.c
index 6ff00e7..7acf7d2 100644
--- a/sys/fs/procfs/procfs_ioctl.c
+++ b/sys/fs/procfs/procfs_ioctl.c
@@ -41,6 +41,19 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/procfs/procfs.h>
+#ifdef COMPAT_IA32
+struct procfs_status32 {
+ int state; /* Running, stopped, something else? */
+ int flags; /* Any flags */
+ unsigned int events; /* Events to stop on */
+ int why; /* What event, if any, proc stopped on */
+ unsigned int val; /* Any extra data */
+};
+
+#define PIOCWAIT32 _IOR('p', 4, struct procfs_status32)
+#define PIOCSTATUS32 _IOR('p', 6, struct procfs_status32)
+#endif
+
/*
* Process ioctls
*/
@@ -48,6 +61,9 @@ int
procfs_ioctl(PFS_IOCTL_ARGS)
{
struct procfs_status *ps;
+#ifdef COMPAT_IA32
+ struct procfs_status32 *ps32;
+#endif
int error, flags, sig;
PROC_LOCK(p);
@@ -94,6 +110,25 @@ procfs_ioctl(PFS_IOCTL_ARGS)
ps->why = p->p_step ? p->p_stype : 0;
ps->val = p->p_step ? p->p_xstat : 0;
break;
+#ifdef COMPAT_IA32
+ case PIOCWAIT32:
+ while (p->p_step == 0) {
+ /* sleep until p stops */
+ error = msleep(&p->p_stype, &p->p_mtx,
+ PWAIT|PCATCH, "pioctl", 0);
+ if (error != 0)
+ break;
+ }
+ /* fall through to PIOCSTATUS32 */
+ case PIOCSTATUS32:
+ ps32 = (struct procfs_status32 *)data;
+ ps32->state = (p->p_step == 0);
+ ps32->flags = 0; /* nope */
+ ps32->events = p->p_stops;
+ ps32->why = p->p_step ? p->p_stype : 0;
+ ps32->val = p->p_step ? p->p_xstat : 0;
+ break;
+#endif
#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
case _IOC(IOC_IN, 'p', 5, 0):
#endif
diff --git a/sys/fs/procfs/procfs_map.c b/sys/fs/procfs/procfs_map.c
index de0a58c..b98d207 100644
--- a/sys/fs/procfs/procfs_map.c
+++ b/sys/fs/procfs/procfs_map.c
@@ -35,6 +35,8 @@
* $FreeBSD$
*/
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
@@ -54,6 +56,14 @@
#include <vm/vm_page.h>
#include <vm/vm_object.h>
+#ifdef COMPAT_IA32
+#include <sys/procfs.h>
+#include <machine/fpu.h>
+#include <compat/ia32/ia32_reg.h>
+
+extern struct sysentvec ia32_freebsd_sysvec;
+#endif
+
#define MEBUFFERSIZE 256
@@ -77,6 +87,9 @@ procfs_doprocmap(PFS_FILL_ARGS)
vm_map_entry_t entry;
char mebuffer[MEBUFFERSIZE];
char *fullpath, *freepath;
+#ifdef COMPAT_IA32
+ int wrap32 = 0;
+#endif
GIANT_REQUIRED;
@@ -92,6 +105,13 @@ procfs_doprocmap(PFS_FILL_ARGS)
if (uio->uio_offset != 0)
return (0);
+#ifdef COMPAT_IA32
+ if (curthread->td_proc->p_sysent == &ia32_freebsd_sysvec) {
+ if (p->p_sysent != &ia32_freebsd_sysvec)
+ return (EOPNOTSUPP);
+ wrap32 = 1;
+ }
+#endif
error = 0;
if (map != &curthread->td_proc->p_vmspace->vm_map)
vm_map_lock_read(map);
@@ -164,7 +184,12 @@ procfs_doprocmap(PFS_FILL_ARGS)
snprintf(mebuffer, sizeof mebuffer,
"0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s %s\n",
(u_long)entry->start, (u_long)entry->end,
- resident, privateresident, obj,
+ resident, privateresident,
+#ifdef COMPAT_IA32
+ wrap32 ? NULL : obj, /* Hide 64 bit value */
+#else
+ obj,
+#endif
(entry->protection & VM_PROT_READ)?"r":"-",
(entry->protection & VM_PROT_WRITE)?"w":"-",
(entry->protection & VM_PROT_EXECUTE)?"x":"-",
diff --git a/sys/fs/procfs/procfs_regs.c b/sys/fs/procfs/procfs_regs.c
index 7da0f8c..cba2b7b 100644
--- a/sys/fs/procfs/procfs_regs.c
+++ b/sys/fs/procfs/procfs_regs.c
@@ -37,6 +37,8 @@
* $FreeBSD$
*/
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
@@ -50,11 +52,42 @@
#include <fs/pseudofs/pseudofs.h>
#include <fs/procfs/procfs.h>
+#ifdef COMPAT_IA32
+#include <sys/procfs.h>
+#include <machine/fpu.h>
+#include <compat/ia32/ia32_reg.h>
+
+extern struct sysentvec ia32_freebsd_sysvec;
+/*
+ * PROC(write, regs, td2, &r) becomes
+ * proc_write_regs(td2, &r) or
+ * proc_write_regs32(td2, &r32)
+ *
+ * UIOMOVE_FROMBUF(r, uio) becomes
+ * uiomove_frombuf(&r, sizeof(r), uio) or
+ * uiomove_frombuf(&r32, sizeof(r32), uio)
+ */
+#define PROC(d, w, t, r) wrap32 ? \
+ proc_ ## d ## _ ## w ## 32(t, r ## 32) : \
+ proc_ ## d ## _ ## w(t, r)
+#define UIOMOVE_FROMBUF(k, u) wrap32 ? \
+ uiomove_frombuf(& k ## 32, sizeof(k ## 32), u) : \
+ uiomove_frombuf(& k, sizeof(k), u)
+#else
+#define PROC(d, w, t, r) proc_ ## d ## _ ## w(t, r)
+#define UIOMOVE_FROMBUF(k, u) uiomove_frombuf(& k, sizeof(k), u)
+#endif
+
int
procfs_doprocregs(PFS_FILL_ARGS)
{
int error;
struct reg r;
+ struct thread *td2;
+#ifdef COMPAT_IA32
+ struct reg32 r32;
+ int wrap32 = 0;
+#endif
PROC_LOCK(p);
KASSERT(p->p_lock > 0, ("proc not held"));
@@ -64,10 +97,20 @@ procfs_doprocregs(PFS_FILL_ARGS)
}
/* XXXKSE: */
- error = proc_read_regs(FIRST_THREAD_IN_PROC(p), &r);
+ td2 = FIRST_THREAD_IN_PROC(p);
+#ifdef COMPAT_IA32
+ if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) {
+ if (td2->td_proc->p_sysent != &ia32_freebsd_sysvec) {
+ PROC_UNLOCK(p);
+ return (EINVAL);
+ }
+ wrap32 = 1;
+ }
+#endif
+ error = PROC(read, regs, td2, &r);
if (error == 0) {
PROC_UNLOCK(p);
- error = uiomove_frombuf(&r, sizeof(r), uio);
+ error = UIOMOVE_FROMBUF(r, uio);
PROC_LOCK(p);
}
if (error == 0 && uio->uio_rw == UIO_WRITE) {
@@ -75,7 +118,7 @@ procfs_doprocregs(PFS_FILL_ARGS)
error = EBUSY;
else
/* XXXKSE: */
- error = proc_write_regs(FIRST_THREAD_IN_PROC(p), &r);
+ error = PROC(write, regs, td2, &r);
}
PROC_UNLOCK(p);
diff --git a/sys/ia64/ia32/ia32_reg.c b/sys/ia64/ia32/ia32_reg.c
new file mode 100644
index 0000000..dde8b89
--- /dev/null
+++ b/sys/ia64/ia32/ia32_reg.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2005 Peter Wemm
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <compat/ia32/ia32_reg.h>
+
+int
+fill_regs32(struct thread *td, struct reg32 *regs)
+{
+
+ bzero(regs, sizeof(*regs));
+ return (EOPNOTSUPP);
+}
+
+int
+set_regs32(struct thread *td, struct reg32 *regs)
+{
+
+ return (EOPNOTSUPP);
+}
+
+int
+fill_fpregs32(struct thread *td, struct fpreg32 *regs)
+{
+
+ bzero(regs, sizeof(*regs));
+ return (EOPNOTSUPP);
+}
+
+int
+set_fpregs32(struct thread *td, struct fpreg32 *regs)
+{
+
+ return (EOPNOTSUPP);
+}
+
+int
+fill_dbregs32(struct thread *td, struct dbreg32 *regs)
+{
+
+ bzero(regs, sizeof(*regs));
+ return (EOPNOTSUPP);
+}
+
+int
+set_dbregs32(struct thread *td, struct dbreg32 *regs)
+{
+
+ return (EOPNOTSUPP);
+}
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 9f46c97..6a88500 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -31,6 +31,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/exec.h>
#include <sys/fcntl.h>
@@ -66,6 +68,11 @@ __FBSDID("$FreeBSD$");
#include <machine/elf.h>
#include <machine/md_var.h>
+#if defined(COMPAT_IA32) && __ELF_WORD_SIZE == 32
+#include <machine/fpu.h>
+#include <compat/ia32/ia32_reg.h>
+#endif
+
#define OLD_EI_BRAND 8
static int __elfN(check_header)(const Elf_Ehdr *hdr);
@@ -1118,17 +1125,31 @@ __elfN(corehdr)(td, vp, cred, numsegs, hdr, hdrsize)
td)); /* XXXKSE */
}
+#if defined(COMPAT_IA32) && __ELF_WORD_SIZE == 32
+typedef struct prstatus32 elf_prstatus_t;
+typedef struct prpsinfo32 elf_prpsinfo_t;
+typedef struct fpreg32 elf_prfpregset_t;
+typedef struct fpreg32 elf_fpregset_t;
+typedef struct reg32 elf_gregset_t;
+#else
+typedef prstatus_t elf_prstatus_t;
+typedef prpsinfo_t elf_prpsinfo_t;
+typedef prfpregset_t elf_prfpregset_t;
+typedef prfpregset_t elf_fpregset_t;
+typedef gregset_t elf_gregset_t;
+#endif
+
static void
__elfN(puthdr)(struct thread *td, void *dst, size_t *off, int numsegs)
{
struct {
- prstatus_t status;
- prfpregset_t fpregset;
- prpsinfo_t psinfo;
+ elf_prstatus_t status;
+ elf_prfpregset_t fpregset;
+ elf_prpsinfo_t psinfo;
} *tempdata;
- prstatus_t *status;
- prfpregset_t *fpregset;
- prpsinfo_t *psinfo;
+ elf_prstatus_t *status;
+ elf_prfpregset_t *fpregset;
+ elf_prpsinfo_t *psinfo;
struct proc *p;
struct thread *thr;
size_t ehoff, noteoff, notesz, phoff;
@@ -1160,7 +1181,7 @@ __elfN(puthdr)(struct thread *td, void *dst, size_t *off, int numsegs)
if (dst != NULL) {
psinfo->pr_version = PRPSINFO_VERSION;
- psinfo->pr_psinfosz = sizeof(prpsinfo_t);
+ psinfo->pr_psinfosz = sizeof(elf_prpsinfo_t);
strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname));
/*
* XXX - We don't fill in the command line arguments properly
@@ -1182,14 +1203,19 @@ __elfN(puthdr)(struct thread *td, void *dst, size_t *off, int numsegs)
while (thr != NULL) {
if (dst != NULL) {
status->pr_version = PRSTATUS_VERSION;
- status->pr_statussz = sizeof(prstatus_t);
- status->pr_gregsetsz = sizeof(gregset_t);
- status->pr_fpregsetsz = sizeof(fpregset_t);
+ status->pr_statussz = sizeof(elf_prstatus_t);
+ status->pr_gregsetsz = sizeof(elf_gregset_t);
+ status->pr_fpregsetsz = sizeof(elf_fpregset_t);
status->pr_osreldate = osreldate;
status->pr_cursig = p->p_sig;
status->pr_pid = thr->td_tid;
+#if defined(COMPAT_IA32) && __ELF_WORD_SIZE == 32
+ fill_regs32(thr, &status->pr_reg);
+ fill_fpregs32(thr, fpregset);
+#else
fill_regs(thr, &status->pr_reg);
fill_fpregs(thr, fpregset);
+#endif
}
__elfN(putnote)(dst, off, "FreeBSD", NT_PRSTATUS, status,
sizeof *status);
@@ -1235,7 +1261,11 @@ __elfN(puthdr)(struct thread *td, void *dst, size_t *off, int numsegs)
ehdr->e_ident[EI_ABIVERSION] = 0;
ehdr->e_ident[EI_PAD] = 0;
ehdr->e_type = ET_CORE;
+#if defined(COMPAT_IA32) && __ELF_WORD_SIZE == 32
+ ehdr->e_machine = EM_386;
+#else
ehdr->e_machine = ELF_ARCH;
+#endif
ehdr->e_version = EV_CURRENT;
ehdr->e_entry = 0;
ehdr->e_phoff = phoff;
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index cfcc574..76e2be6 100644
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -37,6 +37,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_compat.h"
#include "opt_hwpmc_hooks.h"
#include "opt_ntp.h"
#include "opt_watchdog.h"
@@ -84,8 +85,36 @@ SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
/* Some of these don't belong here, but it's easiest to concentrate them. */
long cp_time[CPUSTATES];
-SYSCTL_OPAQUE(_kern, OID_AUTO, cp_time, CTLFLAG_RD, &cp_time, sizeof(cp_time),
- "LU", "CPU time statistics");
+#ifdef COMPAT_IA32
+extern struct sysentvec ia32_freebsd_sysvec;
+#endif
+
+static int
+sysctl_kern_cp_time(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+#ifdef COMPAT_IA32
+ int i;
+ unsigned int cp_time32[CPUSTATES];
+
+ if (req->td->td_proc->p_sysent == &ia32_freebsd_sysvec) {
+ if (!req->oldptr)
+ return SYSCTL_OUT(req, 0, sizeof(cp_time32));
+ for (i = 0; i < CPUSTATES; i++)
+ cp_time32[i] = (unsigned int)cp_time[i];
+ error = SYSCTL_OUT(req, cp_time32, sizeof(cp_time32));
+ } else
+#endif
+ {
+ if (!req->oldptr)
+ return SYSCTL_OUT(req, 0, sizeof(cp_time));
+ error = SYSCTL_OUT(req, cp_time, sizeof(cp_time));
+ }
+ return error;
+}
+
+SYSCTL_PROC(_kern, OID_AUTO, cp_time, CTLTYPE_LONG|CTLFLAG_RD,
+ 0,0, sysctl_kern_cp_time, "LU", "CPU time statistics");
#ifdef SW_WATCHDOG
#include <sys/watchdog.h>
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index b9afb6a..11b66da 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -32,6 +32,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
@@ -55,6 +57,21 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_object.h>
#include <vm/vm_page.h>
+#ifdef COMPAT_IA32
+#include <sys/procfs.h>
+#include <machine/fpu.h>
+#include <compat/ia32/ia32_reg.h>
+
+extern struct sysentvec ia32_freebsd_sysvec;
+
+struct ptrace_io_desc32 {
+ int piod_op;
+ u_int32_t piod_offs;
+ u_int32_t piod_addr;
+ u_int32_t piod_len;
+};
+#endif
+
/*
* Functions implemented using PROC_ACTION():
*
@@ -138,6 +155,51 @@ proc_write_fpregs(struct thread *td, struct fpreg *fpregs)
PROC_ACTION(set_fpregs(td, fpregs));
}
+#ifdef COMPAT_IA32
+/* For 32 bit binaries, we need to expose the 32 bit regs layouts. */
+int
+proc_read_regs32(struct thread *td, struct reg32 *regs32)
+{
+
+ PROC_ACTION(fill_regs32(td, regs32));
+}
+
+int
+proc_write_regs32(struct thread *td, struct reg32 *regs32)
+{
+
+ PROC_ACTION(set_regs32(td, regs32));
+}
+
+int
+proc_read_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
+{
+
+ PROC_ACTION(fill_dbregs32(td, dbregs32));
+}
+
+int
+proc_write_dbregs32(struct thread *td, struct dbreg32 *dbregs32)
+{
+
+ PROC_ACTION(set_dbregs32(td, dbregs32));
+}
+
+int
+proc_read_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
+{
+
+ PROC_ACTION(fill_fpregs32(td, fpregs32));
+}
+
+int
+proc_write_fpregs32(struct thread *td, struct fpreg32 *fpregs32)
+{
+
+ PROC_ACTION(set_fpregs32(td, fpregs32));
+}
+#endif
+
int
proc_sstep(struct thread *td)
{
@@ -290,6 +352,27 @@ struct ptrace_args {
};
#endif
+#ifdef COMPAT_IA32
+/*
+ * This CPP subterfuge is to try and reduce the number of ifdefs in
+ * the body of the code.
+ * COPYIN(uap->addr, &r.reg, sizeof r.reg);
+ * becomes either:
+ * copyin(uap->addr, &r.reg, sizeof r.reg);
+ * or
+ * copyin(uap->addr, &r.reg32, sizeof r.reg32);
+ * .. except this is done at runtime.
+ */
+#define COPYIN(u, k, s) wrap32 ? \
+ copyin(u, k ## 32, s ## 32) : \
+ copyin(u, k, s)
+#define COPYOUT(k, u, s) wrap32 ? \
+ copyout(k ## 32, u, s ## 32) : \
+ copyout(k, u, s)
+#else
+#define COPYIN(u, k, s) copyin(u, k, s)
+#define COPYOUT(k, u, s) copyout(k, u, s)
+#endif
/*
* MPSAFE
*/
@@ -306,10 +389,21 @@ ptrace(struct thread *td, struct ptrace_args *uap)
struct dbreg dbreg;
struct fpreg fpreg;
struct reg reg;
+#ifdef COMPAT_IA32
+ struct dbreg32 dbreg32;
+ struct fpreg32 fpreg32;
+ struct reg32 reg32;
+ struct ptrace_io_desc32 piod32;
+#endif
} r;
void *addr;
int error = 0;
+#ifdef COMPAT_IA32
+ int wrap32 = 0;
+ if (td->td_proc->p_sysent == &ia32_freebsd_sysvec)
+ wrap32 = 1;
+#endif
addr = &r;
switch (uap->req) {
case PT_GETREGS:
@@ -318,16 +412,16 @@ ptrace(struct thread *td, struct ptrace_args *uap)
case PT_LWPINFO:
break;
case PT_SETREGS:
- error = copyin(uap->addr, &r.reg, sizeof r.reg);
+ error = COPYIN(uap->addr, &r.reg, sizeof r.reg);
break;
case PT_SETFPREGS:
- error = copyin(uap->addr, &r.fpreg, sizeof r.fpreg);
+ error = COPYIN(uap->addr, &r.fpreg, sizeof r.fpreg);
break;
case PT_SETDBREGS:
- error = copyin(uap->addr, &r.dbreg, sizeof r.dbreg);
+ error = COPYIN(uap->addr, &r.dbreg, sizeof r.dbreg);
break;
case PT_IO:
- error = copyin(uap->addr, &r.piod, sizeof r.piod);
+ error = COPYIN(uap->addr, &r.piod, sizeof r.piod);
break;
default:
addr = uap->addr;
@@ -342,16 +436,16 @@ ptrace(struct thread *td, struct ptrace_args *uap)
switch (uap->req) {
case PT_IO:
- (void)copyout(&r.piod, uap->addr, sizeof r.piod);
+ error = COPYOUT(&r.piod, uap->addr, sizeof r.piod);
break;
case PT_GETREGS:
- error = copyout(&r.reg, uap->addr, sizeof r.reg);
+ error = COPYOUT(&r.reg, uap->addr, sizeof r.reg);
break;
case PT_GETFPREGS:
- error = copyout(&r.fpreg, uap->addr, sizeof r.fpreg);
+ error = COPYOUT(&r.fpreg, uap->addr, sizeof r.fpreg);
break;
case PT_GETDBREGS:
- error = copyout(&r.dbreg, uap->addr, sizeof r.dbreg);
+ error = COPYOUT(&r.dbreg, uap->addr, sizeof r.dbreg);
break;
case PT_LWPINFO:
error = copyout(&r.pl, uap->addr, uap->data);
@@ -360,6 +454,30 @@ ptrace(struct thread *td, struct ptrace_args *uap)
return (error);
}
+#undef COPYIN
+#undef COPYOUT
+
+#ifdef COMPAT_IA32
+/*
+ * PROC_READ(regs, td2, addr);
+ * becomes either:
+ * proc_read_regs(td2, addr);
+ * or
+ * proc_read_regs32(td2, addr);
+ * .. except this is done at runtime. There is an additional
+ * complication in that PROC_WRITE disallows 32 bit consumers
+ * from writing to 64 bit address space targets.
+ */
+#define PROC_READ(w, t, a) wrap32 ? \
+ proc_read_ ## w ## 32(t, a) : \
+ proc_read_ ## w (t, a)
+#define PROC_WRITE(w, t, a) wrap32 ? \
+ (safe ? proc_write_ ## w ## 32(t, a) : EINVAL ) : \
+ proc_write_ ## w (t, a)
+#else
+#define PROC_READ(w, t, a) proc_read_ ## w (t, a)
+#define PROC_WRITE(w, t, a) proc_write_ ## w (t, a)
+#endif
int
kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
@@ -368,12 +486,16 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
struct uio uio;
struct proc *curp, *p, *pp;
struct thread *td2 = NULL;
- struct ptrace_io_desc *piod;
+ struct ptrace_io_desc *piod = NULL;
struct ptrace_lwpinfo *pl;
int error, write, tmp, num;
int proctree_locked = 0;
lwpid_t tid = 0, *buf;
pid_t saved_pid = pid;
+#ifdef COMPAT_IA32
+ int wrap32 = 0, safe = 0;
+ struct ptrace_io_desc32 *piod32 = NULL;
+#endif
curp = td->td_proc;
@@ -449,6 +571,17 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
tid = td2->td_tid;
}
+#ifdef COMPAT_IA32
+ /*
+ * Test if we're a 32 bit client and what the target is.
+ * Set the wrap controls accordingly.
+ */
+ if (td->td_proc->p_sysent == &ia32_freebsd_sysvec) {
+ if (td2->td_proc->p_sysent == &ia32_freebsd_sysvec)
+ safe = 1;
+ wrap32 = 1;
+ }
+#endif
/*
* Permissions check
*/
@@ -723,16 +856,32 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_IO:
PROC_UNLOCK(p);
- piod = addr;
- iov.iov_base = piod->piod_addr;
- iov.iov_len = piod->piod_len;
+#ifdef COMPAT_IA32
+ if (wrap32) {
+ piod32 = addr;
+ iov.iov_base = (void *)(uintptr_t)piod32->piod_addr;
+ iov.iov_len = piod32->piod_len;
+ uio.uio_offset = (off_t)(uintptr_t)piod32->piod_offs;
+ uio.uio_resid = piod32->piod_len;
+ } else
+#endif
+ {
+ piod = addr;
+ iov.iov_base = piod->piod_addr;
+ iov.iov_len = piod->piod_len;
+ uio.uio_offset = (off_t)(uintptr_t)piod->piod_offs;
+ uio.uio_resid = piod->piod_len;
+ }
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
- 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 (piod->piod_op) {
+#ifdef COMPAT_IA32
+ tmp = wrap32 ? piod32->piod_op : piod->piod_op;
+#else
+ tmp = piod->piod_op;
+#endif
+ switch (tmp) {
case PIOD_READ_D:
case PIOD_READ_I:
uio.uio_rw = UIO_READ;
@@ -745,7 +894,12 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
return (EINVAL);
}
error = proc_rwmem(p, &uio);
- piod->piod_len -= uio.uio_resid;
+#ifdef COMPAT_IA32
+ if (wrap32)
+ piod32->piod_len -= uio.uio_resid;
+ else
+#endif
+ piod->piod_len -= uio.uio_resid;
return (error);
case PT_KILL:
@@ -754,42 +908,42 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
case PT_SETREGS:
_PHOLD(p);
- error = proc_write_regs(td2, addr);
+ error = PROC_WRITE(regs, td2, addr);
_PRELE(p);
PROC_UNLOCK(p);
return (error);
case PT_GETREGS:
_PHOLD(p);
- error = proc_read_regs(td2, addr);
+ error = PROC_READ(regs, td2, addr);
_PRELE(p);
PROC_UNLOCK(p);
return (error);
case PT_SETFPREGS:
_PHOLD(p);
- error = proc_write_fpregs(td2, addr);
+ error = PROC_WRITE(fpregs, td2, addr);
_PRELE(p);
PROC_UNLOCK(p);
return (error);
case PT_GETFPREGS:
_PHOLD(p);
- error = proc_read_fpregs(td2, addr);
+ error = PROC_READ(fpregs, td2, addr);
_PRELE(p);
PROC_UNLOCK(p);
return (error);
case PT_SETDBREGS:
_PHOLD(p);
- error = proc_write_dbregs(td2, addr);
+ error = PROC_WRITE(dbregs, td2, addr);
_PRELE(p);
PROC_UNLOCK(p);
return (error);
case PT_GETDBREGS:
_PHOLD(p);
- error = proc_read_dbregs(td2, addr);
+ error = PROC_READ(dbregs, td2, addr);
_PRELE(p);
PROC_UNLOCK(p);
return (error);
@@ -872,6 +1026,8 @@ fail_noproc:
sx_xunlock(&proctree_lock);
return (error);
}
+#undef PROC_READ
+#undef PROC_WRITE
/*
* Stop a process because of a debugging event;
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 0058683..93b1a7d 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -135,6 +135,17 @@ 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);
+#ifdef COMPAT_IA32
+struct reg32;
+struct fpreg32;
+struct dbreg32;
+int proc_read_regs32(struct thread *_td, struct reg32 *_reg32);
+int proc_write_regs32(struct thread *_td, struct reg32 *_reg32);
+int proc_read_fpregs32(struct thread *_td, struct fpreg32 *_fpreg32);
+int proc_write_fpregs32(struct thread *_td, struct fpreg32 *_fpreg32);
+int proc_read_dbregs32(struct thread *_td, struct dbreg32 *_dbreg32);
+int proc_write_dbregs32(struct thread *_td, struct dbreg32 *_dbreg32);
+#endif
#else /* !_KERNEL */
#include <sys/cdefs.h>
OpenPOWER on IntegriCloud