Jumbo-commit to enhance 32 bit application support on 64 bit kernels.
This is good enough to be able to run a RELENG_4 gdb binary against a RELENG_4 application, along with various other tools (eg: 4.x gcore). We use this at work. ia32_reg.[ch]: handle the 32 bit register file format, used by ptrace, procfs and core dumps. procfs_*regs.c: vary the format of proc/XXX/*regs depending on the client and target application. procfs_map.c: Don't print a 64 bit value to 32 bit consumers, or their sscanf fails. They expect an unsigned long. imgact_elf.c: produce a valid 32 bit coredump for 32 bit apps. sys_process.c: handle 32 bit consumers debugging 32 bit targets. Note that 64 bit consumers can still debug 32 bit targets. IA64 has got stubs for ia32_reg.c. Known limitations: a 5.x/6.x gdb uses get/setcontext(), which isn't implemented in the 32/64 wrapper yet. We also make a tiny patch to gdb pacify it over conflicting formats of ld-elf.so.1. Approved by: re
This commit is contained in:
parent
14ff9254d8
commit
921b3c5ee4
224
sys/amd64/ia32/ia32_reg.c
Normal file
224
sys/amd64/ia32/ia32_reg.c
Normal file
@ -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));
|
||||
}
|
141
sys/compat/ia32/ia32_reg.h
Normal file
141
sys/compat/ia32/ia32_reg.h
Normal file
@ -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_ */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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":"-",
|
||||
|
@ -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);
|
||||
|
||||
|
82
sys/ia64/ia32/ia32_reg.c
Normal file
82
sys/ia64/ia32/ia32_reg.c
Normal file
@ -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);
|
||||
}
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user