Reorganize syscall entry and leave handling.

Extend struct sysvec with three new elements:
sv_fetch_syscall_args - the method to fetch syscall arguments from
  usermode into struct syscall_args. The structure is machine-depended
  (this might be reconsidered after all architectures are converted).
sv_set_syscall_retval - the method to set a return value for usermode
  from the syscall. It is a generalization of
  cpu_set_syscall_retval(9) to allow ABIs to override the way to set a
  return value.
sv_syscallnames - the table of syscall names.

Use sv_set_syscall_retval in kern_sigsuspend() instead of hardcoding
the call to cpu_set_syscall_retval().

The new functions syscallenter(9) and syscallret(9) are provided that
use sv_*syscall* pointers and contain the common repeated code from
the syscall() implementations for the architecture-specific syscall
trap handlers.

Syscallenter() fetches arguments, calls syscall implementation from
ABI sysent table, and set up return frame. The end of syscall
bookkeeping is done by syscallret().

Take advantage of single place for MI syscall handling code and
implement ptrace_lwpinfo pl_flags PL_FLAG_SCE, PL_FLAG_SCX and
PL_FLAG_EXEC. The SCE and SCX flags notify the debugger that the
thread is stopped at syscall entry or return point respectively.  The
EXEC flag augments SCX and notifies debugger that the process address
space was changed by one of exec(2)-family syscalls.

The i386, amd64, sparc64, sun4v, powerpc and ia64 syscall()s are
changed to use syscallenter()/syscallret(). MIPS and arm are not
converted and use the mostly unchanged syscall() implementation.

Reviewed by:	jhb, marcel, marius, nwhitehorn, stas
Tested by:	marcel (ia64), marius (sparc64), nwhitehorn (powerpc),
	stas (mips)
MFC after:	1 month
This commit is contained in:
Konstantin Belousov 2010-05-23 18:32:02 +00:00
parent fa1ed4bd1a
commit afe1a68827
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=208453
42 changed files with 739 additions and 1044 deletions

View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/syscall.h>
@ -74,7 +75,10 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_LP64
.sv_flags = SV_ABI_FREEBSD | SV_LP64,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
};
static Elf64_Brandinfo freebsd_brand_info = {

View File

@ -76,7 +76,6 @@ __FBSDID("$FreeBSD$");
#ifdef HWPMC_HOOKS
#include <sys/pmckern.h>
#endif
#include <security/audit/audit.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
@ -170,8 +169,6 @@ static int prot_fault_translation = 0;
SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW,
&prot_fault_translation, 0, "Select signal to deliver on protection fault");
extern char *syscallnames[];
/*
* Exception, fault, and trap interface to the FreeBSD kernel.
* This common code is called from assembly language IDT gate entry
@ -805,19 +802,12 @@ dblfault_handler(struct trapframe *frame)
panic("double fault");
}
struct syscall_args {
u_int code;
struct sysent *callp;
register_t args[8];
register_t *argp;
int narg;
};
static int
fetch_syscall_args(struct thread *td, struct syscall_args *sa)
int
cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
struct proc *p;
struct trapframe *frame;
register_t *argp;
caddr_t params;
int reg, regcnt, error;
@ -829,15 +819,10 @@ fetch_syscall_args(struct thread *td, struct syscall_args *sa)
params = (caddr_t)frame->tf_rsp + sizeof(register_t);
sa->code = frame->tf_rax;
if (p->p_sysent->sv_prepsyscall) {
(*p->p_sysent->sv_prepsyscall)(frame, (int *)sa->args,
&sa->code, &params);
} else {
if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
sa->code = frame->tf_rdi;
reg++;
regcnt--;
}
if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
sa->code = frame->tf_rdi;
reg++;
regcnt--;
}
if (p->p_sysent->sv_mask)
sa->code &= p->p_sysent->sv_mask;
@ -851,24 +836,20 @@ fetch_syscall_args(struct thread *td, struct syscall_args *sa)
KASSERT(sa->narg <= sizeof(sa->args) / sizeof(sa->args[0]),
("Too many syscall arguments!"));
error = 0;
sa->argp = &frame->tf_rdi;
sa->argp += reg;
bcopy(sa->argp, sa->args, sizeof(sa->args[0]) * regcnt);
argp = &frame->tf_rdi;
argp += reg;
bcopy(argp, sa->args, sizeof(sa->args[0]) * regcnt);
if (sa->narg > regcnt) {
KASSERT(params != NULL, ("copyin args with no params!"));
error = copyin(params, &sa->args[regcnt],
(sa->narg - regcnt) * sizeof(sa->args[0]));
}
sa->argp = &sa->args[0];
/*
* This may result in two records if debugger modified
* registers or memory during sleep at stop/ptrace point.
*/
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->argp);
#endif
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_rdx;
}
return (error);
}
@ -881,87 +862,22 @@ void
syscall(struct trapframe *frame)
{
struct thread *td;
struct proc *p;
struct syscall_args sa;
register_t orig_tf_rflags;
int error;
ksiginfo_t ksi;
PCPU_INC(cnt.v_syscall);
td = curthread;
p = td->td_proc;
td->td_syscalls++;
#ifdef DIAGNOSTIC
if (ISPL(frame->tf_cs) != SEL_UPL) {
panic("syscall");
/* NOT REACHED */
}
#endif
td->td_pticks = 0;
td->td_frame = frame;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
orig_tf_rflags = frame->tf_rflags;
if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
PROC_UNLOCK(p);
}
error = fetch_syscall_args(td, &sa);
td = curthread;
td->td_frame = frame;
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_name, sa.code);
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_rdx;
STOPEVENT(p, S_SCE, sa.narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
if (td->td_dbgflags & TDB_USERWR) {
/*
* Reread syscall number and arguments if
* debugger modified registers or memory.
*/
error = fetch_syscall_args(td, &sa);
if (error != 0)
goto retval;
td->td_retval[1] = frame->tf_rdx;
}
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'entry', process the probe.
*/
if (systrace_probe_func != NULL && sa.callp->sy_entry != 0)
(*systrace_probe_func)(sa.callp->sy_entry, sa.code,
sa.callp, sa.args);
#endif
AUDIT_SYSCALL_ENTER(sa.code, td);
error = (*sa.callp->sy_call)(td, sa.argp);
AUDIT_SYSCALL_EXIT(error, td);
/* Save the latest error return value. */
td->td_errno = error;
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'return', process the probe.
*/
if (systrace_probe_func != NULL && sa.callp->sy_return != 0)
(*systrace_probe_func)(sa.callp->sy_return, sa.code,
sa.callp, sa.args);
#endif
}
retval:
cpu_set_syscall_retval(td, error);
error = syscallenter(td, &sa);
/*
* Traced syscall.
@ -975,40 +891,5 @@ syscall(struct trapframe *frame)
trapsignal(td, &ksi);
}
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???", td->td_locks));
/*
* Handle reschedule and other end-of-syscall issues
*/
userret(td, frame);
CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_name, sa.code);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(sa.code, error, td->td_retval[0]);
#endif
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa.code);
PTRACESTOP_SC(p, td, S_PT_SCX);
syscallret(td, error, &sa);
}

View File

@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
@ -81,62 +82,54 @@ __FBSDID("$FreeBSD$");
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <compat/freebsd32/freebsd32_util.h>
#define IDTVEC(name) __CONCAT(X,name)
extern inthand_t IDTVEC(int0x80_syscall), IDTVEC(rsvd);
extern const char *freebsd32_syscallnames[];
void ia32_syscall(struct trapframe *frame); /* Called from asm code */
struct ia32_syscall_args {
u_int code;
caddr_t params;
struct sysent *callp;
u_int64_t args64[8];
int narg;
};
void
ia32_set_syscall_retval(struct thread *td, int error)
{
static int
fetch_ia32_syscall_args(struct thread *td, struct ia32_syscall_args *sa)
cpu_set_syscall_retval(td, error);
}
int
ia32_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
struct proc *p;
struct trapframe *frame;
caddr_t params;
u_int32_t args[8];
int error, i;
p = td->td_proc;
frame = td->td_frame;
sa->params = (caddr_t)frame->tf_rsp + sizeof(u_int32_t);
params = (caddr_t)frame->tf_rsp + sizeof(u_int32_t);
sa->code = frame->tf_rax;
if (p->p_sysent->sv_prepsyscall) {
/*
* Need to check if this is a 32 bit or 64 bit syscall.
*/
if (sa->code == SYS_syscall) {
/*
* The prep code is MP aware.
* Code is first argument, followed by actual args.
*/
(*p->p_sysent->sv_prepsyscall)(frame, args, &sa->code,
&sa->params);
} else {
sa->code = fuword32(params);
params += sizeof(int);
} else if (sa->code == SYS___syscall) {
/*
* Need to check if this is a 32 bit or 64 bit syscall.
* fuword is MP aware.
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments.
* We use a 32-bit fetch in case params is not
* aligned.
*/
if (sa->code == SYS_syscall) {
/*
* Code is first argument, followed by actual args.
*/
sa->code = fuword32(sa->params);
sa->params += sizeof(int);
} else if (sa->code == SYS___syscall) {
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments.
* We use a 32-bit fetch in case params is not
* aligned.
*/
sa->code = fuword32(sa->params);
sa->params += sizeof(quad_t);
}
sa->code = fuword32(params);
params += sizeof(quad_t);
}
if (p->p_sysent->sv_mask)
sa->code &= p->p_sysent->sv_mask;
@ -146,19 +139,19 @@ fetch_ia32_syscall_args(struct thread *td, struct ia32_syscall_args *sa)
sa->callp = &p->p_sysent->sv_table[sa->code];
sa->narg = sa->callp->sy_narg;
if (sa->params != NULL && sa->narg != 0)
error = copyin(sa->params, (caddr_t)args,
if (params != NULL && sa->narg != 0)
error = copyin(params, (caddr_t)args,
(u_int)(sa->narg * sizeof(int)));
else
error = 0;
for (i = 0; i < sa->narg; i++)
sa->args64[i] = args[i];
sa->args[i] = args[i];
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->args64);
#endif
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_rdx;
}
return (error);
}
@ -167,58 +160,16 @@ void
ia32_syscall(struct trapframe *frame)
{
struct thread *td;
struct proc *p;
struct ia32_syscall_args sa;
struct syscall_args sa;
register_t orig_tf_rflags;
int error;
ksiginfo_t ksi;
PCPU_INC(cnt.v_syscall);
td = curthread;
p = td->td_proc;
td->td_syscalls++;
td->td_pticks = 0;
td->td_frame = frame;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
orig_tf_rflags = frame->tf_rflags;
if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
PROC_UNLOCK(p);
}
error = fetch_ia32_syscall_args(td, &sa);
td = curthread;
td->td_frame = frame;
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_name, sa.code);
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_rdx;
STOPEVENT(p, S_SCE, sa.narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
if (td->td_dbgflags & TDB_USERWR) {
/*
* Reread syscall number and arguments if
* debugger modified registers or memory.
*/
error = fetch_ia32_syscall_args(td, &sa);
if (error != 0)
goto retval;
td->td_retval[1] = frame->tf_rdx;
}
AUDIT_SYSCALL_ENTER(sa.code, td);
error = (*sa.callp->sy_call)(td, sa.args64);
AUDIT_SYSCALL_EXIT(error, td);
/* Save the latest error return value. */
td->td_errno = error;
}
retval:
cpu_set_syscall_retval(td, error);
error = syscallenter(td, &sa);
/*
* Traced syscall.
@ -232,44 +183,9 @@ ia32_syscall(struct trapframe *frame)
trapsignal(td, &ksi);
}
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
freebsd32_syscallnames[sa.code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
freebsd32_syscallnames[sa.code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
freebsd32_syscallnames[sa.code] : "???", td->td_locks));
/*
* Handle reschedule and other end-of-syscall issues
*/
userret(td, frame);
CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_proc->p_comm, sa.code);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(sa.code, error, td->td_retval[0]);
#endif
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa.code);
PTRACESTOP_SC(p, td, S_PT_SCX);
syscallret(td, error, &sa);
}
static void
ia32_syscall_enable(void *dummy)
{

View File

@ -79,6 +79,14 @@ int amd64_set_ldt_data(struct thread *td, int start, int num,
extern struct mtx dt_lock;
extern int max_ldt_segment;
struct syscall_args {
u_int code;
struct sysent *callp;
register_t args[8];
int narg;
};
#define HAVE_SYSCALL_ARGS_DEF 1
#endif /* _KERNEL */
#endif /* !_MACHINE_PROC_H_ */

View File

@ -121,8 +121,6 @@ SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
static int elf_linux_fixup(register_t **stack_base,
struct image_params *iparams);
static register_t *linux_copyout_strings(struct image_params *imgp);
static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
caddr_t *params);
static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
static void exec_linux_setregs(struct thread *td,
struct image_params *imgp, u_long stack);
@ -764,19 +762,33 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
return (EJUSTRETURN);
}
/*
* MPSAFE
*/
static void
linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
static int
linux32_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
args[0] = tf->tf_rbx;
args[1] = tf->tf_rcx;
args[2] = tf->tf_rdx;
args[3] = tf->tf_rsi;
args[4] = tf->tf_rdi;
args[5] = tf->tf_rbp; /* Unconfirmed */
*params = NULL; /* no copyin */
struct proc *p;
struct trapframe *frame;
p = td->td_proc;
frame = td->td_frame;
sa->args[0] = frame->tf_rbx;
sa->args[1] = frame->tf_rcx;
sa->args[2] = frame->tf_rdx;
sa->args[3] = frame->tf_rsi;
sa->args[4] = frame->tf_rdi;
sa->args[5] = frame->tf_rbp; /* Unconfirmed */
sa->code = frame->tf_rax;
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
sa->callp = &p->p_sysent->sv_table[sa->code];
sa->narg = sa->callp->sy_narg;
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_rdx;
return (0);
}
/*
@ -1039,7 +1051,7 @@ struct sysentvec elf_linux_sysvec = {
.sv_sendsig = linux_sendsig,
.sv_sigcode = linux_sigcode,
.sv_szsigcode = &linux_szsigcode,
.sv_prepsyscall = linux_prepsyscall,
.sv_prepsyscall = NULL,
.sv_name = "Linux ELF32",
.sv_coredump = elf32_coredump,
.sv_imgact_try = exec_linux_imgact_try,
@ -1054,7 +1066,10 @@ struct sysentvec elf_linux_sysvec = {
.sv_setregs = exec_linux_setregs,
.sv_fixlimit = linux32_fixlimit,
.sv_maxssiz = &linux32_maxssiz,
.sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32
.sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = linux32_fetch_syscall_args,
.sv_syscallnames = NULL,
};
static char GNU_ABI_VENDOR[] = "GNU";

View File

@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/signalvar.h>
#include <sys/vnode.h>
@ -73,7 +74,10 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_ILP32
.sv_flags = SV_ABI_FREEBSD | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = NULL, /* XXXKIB */
.sv_syscallnames = syscallnames,
};
static Elf32_Brandinfo freebsd_brand_info = {

View File

@ -130,7 +130,6 @@ void undefinedinstruction(trapframe_t *);
#include <machine/machdep.h>
extern char fusubailout[];
extern char *syscallnames[];
#ifdef DEBUG
int last_fault_code; /* For the benefit of pmap_fault_fixup() */

View File

@ -77,7 +77,6 @@ extern struct sysent linux_sysent[];
*/
#include <sys/syscall.h>
#include <kern/systrace_args.c>
extern const char *syscallnames[];
#define DEVNAME "dtrace/systrace"
#define PROVNAME "syscall"
#define MAXSYSCALL SYS_MAXSYSCALL

View File

@ -93,6 +93,8 @@ CTASSERT(sizeof(struct ia32_ucontext4) == 324);
CTASSERT(sizeof(struct ia32_sigframe4) == 408);
#endif
extern const char *freebsd32_syscallnames[];
static void ia32_fixlimit(struct rlimit *rl, int which);
SYSCTL_NODE(_compat, OID_AUTO, ia32, CTLFLAG_RW, 0, "ia32 mode");
@ -135,7 +137,10 @@ struct sysentvec ia32_freebsd_sysvec = {
.sv_setregs = ia32_setregs,
.sv_fixlimit = ia32_fixlimit,
.sv_maxssiz = &ia32_maxssiz,
.sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32
.sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32,
.sv_set_syscall_retval = ia32_set_syscall_retval,
.sv_fetch_syscall_args = ia32_fetch_syscall_args,
.sv_syscallnames = freebsd32_syscallnames,
};

View File

@ -47,3 +47,7 @@
#define IA32_MAXDSIZ (512*1024*1024) /* 512MB */
#define IA32_MAXSSIZ (64*1024*1024) /* 64MB */
#define IA32_MAXVMEM 0 /* Unlimited */
struct syscall_args;
int ia32_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
void ia32_set_syscall_retval(struct thread *, int);

View File

@ -191,7 +191,10 @@ struct sysentvec svr4_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_UNDEF | SV_IA32 | SV_ILP32
.sv_flags = SV_ABI_UNDEF | SV_IA32 | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = NULL,
};
const char svr4_emul_path[] = "/compat/svr4";

View File

@ -2166,7 +2166,7 @@ kern/sys_generic.c standard
kern/sys_pipe.c standard
kern/sys_process.c standard
kern/sys_socket.c standard
kern/syscalls.c optional witness | invariants | kdtrace_hooks
kern/syscalls.c standard
kern/sysv_ipc.c standard
kern/sysv_msg.c optional sysvmsg
kern/sysv_sem.c optional sysvsem

View File

@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/syscall.h>
@ -73,7 +74,10 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32
.sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
};
static Elf32_Brandinfo freebsd_brand_info = {

View File

@ -184,8 +184,6 @@ static int prot_fault_translation = 0;
SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW,
&prot_fault_translation, 0, "Select signal to deliver on protection fault");
extern char *syscallnames[];
/*
* Exception, fault, and trap interface to the FreeBSD kernel.
* This common code is called from assembly language IDT gate entry
@ -973,16 +971,8 @@ dblfault_handler()
panic("double fault");
}
struct syscall_args {
u_int code;
struct sysent *callp;
int args[8];
register_t *argp;
int narg;
};
static int
fetch_syscall_args(struct thread *td, struct syscall_args *sa)
int
cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
struct proc *p;
struct trapframe *frame;
@ -995,27 +985,22 @@ fetch_syscall_args(struct thread *td, struct syscall_args *sa)
params = (caddr_t)frame->tf_esp + sizeof(int);
sa->code = frame->tf_eax;
if (p->p_sysent->sv_prepsyscall) {
(*p->p_sysent->sv_prepsyscall)(frame, sa->args, &sa->code,
&params);
} else {
/*
* Need to check if this is a 32 bit or 64 bit syscall.
*/
if (sa->code == SYS_syscall) {
/*
* Need to check if this is a 32 bit or 64 bit syscall.
* Code is first argument, followed by actual args.
*/
if (sa->code == SYS_syscall) {
/*
* Code is first argument, followed by actual args.
*/
sa->code = fuword(params);
params += sizeof(int);
} else if (sa->code == SYS___syscall) {
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments.
*/
sa->code = fuword(params);
params += sizeof(quad_t);
}
sa->code = fuword(params);
params += sizeof(int);
} else if (sa->code == SYS___syscall) {
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments.
*/
sa->code = fuword(params);
params += sizeof(quad_t);
}
if (p->p_sysent->sv_mask)
@ -1031,11 +1016,12 @@ fetch_syscall_args(struct thread *td, struct syscall_args *sa)
(u_int)(sa->narg * sizeof(int)));
else
error = 0;
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_edx;
}
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->args);
#endif
return (error);
}
@ -1048,87 +1034,23 @@ void
syscall(struct trapframe *frame)
{
struct thread *td;
struct proc *p;
struct syscall_args sa;
register_t orig_tf_eflags;
int error;
ksiginfo_t ksi;
PCPU_INC(cnt.v_syscall);
td = curthread;
p = td->td_proc;
td->td_syscalls++;
#ifdef DIAGNOSTIC
if (ISPL(frame->tf_cs) != SEL_UPL) {
panic("syscall");
/* NOT REACHED */
}
#endif
td->td_pticks = 0;
td->td_frame = frame;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
orig_tf_eflags = frame->tf_eflags;
if (p->p_flag & P_TRACED) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
PROC_UNLOCK(p);
}
error = fetch_syscall_args(td, &sa);
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_name, sa.code);
td = curthread;
td->td_frame = frame;
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_edx;
STOPEVENT(p, S_SCE, sa.narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
if (td->td_dbgflags & TDB_USERWR) {
/*
* Reread syscall number and arguments if
* debugger modified registers or memory.
*/
error = fetch_syscall_args(td, &sa);
if (error != 0)
goto retval;
td->td_retval[1] = frame->tf_edx;
}
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'entry', process the probe.
*/
if (systrace_probe_func != NULL && sa.callp->sy_entry != 0)
(*systrace_probe_func)(sa.callp->sy_entry, sa.code,
sa.callp, sa.args);
#endif
AUDIT_SYSCALL_ENTER(sa.code, td);
error = (*sa.callp->sy_call)(td, sa.args);
AUDIT_SYSCALL_EXIT(error, td);
/* Save the latest error return value. */
td->td_errno = error;
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'return', process the probe.
*/
if (systrace_probe_func != NULL && sa.callp->sy_return != 0)
(*systrace_probe_func)(sa.callp->sy_return, sa.code,
sa.callp, sa.args);
#endif
}
retval:
cpu_set_syscall_retval(td, error);
error = syscallenter(td, &sa);
/*
* Traced syscall.
@ -1142,41 +1064,5 @@ syscall(struct trapframe *frame)
trapsignal(td, &ksi);
}
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???", td->td_locks));
/*
* Handle reschedule and other end-of-syscall issues
*/
userret(td, frame);
CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_name, sa.code);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(sa.code, error, td->td_retval[0]);
#endif
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa.code);
PTRACESTOP_SC(p, td, S_PT_SCX);
syscallret(td, error, &sa);
}

View File

@ -86,7 +86,10 @@ struct sysentvec ibcs2_svr3_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_UNDEF | SV_IA32 | SV_ILP32
.sv_flags = SV_ABI_UNDEF | SV_IA32 | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = NULL,
};
static int

View File

@ -77,6 +77,14 @@ void user_ldt_deref(struct proc_ldt *pldt);
extern struct mtx dt_lock;
struct syscall_args {
u_int code;
struct sysent *callp;
register_t args[8];
int narg;
};
#define HAVE_SYSCALL_ARGS_DEF 1
#endif /* _KERNEL */
#endif /* !_MACHINE_PROC_H_ */

View File

@ -102,8 +102,6 @@ static int linux_fixup(register_t **stack_base,
struct image_params *iparams);
static int elf_linux_fixup(register_t **stack_base,
struct image_params *iparams);
static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
caddr_t *params);
static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
static void exec_linux_setregs(struct thread *td,
struct image_params *imgp, u_long stack);
@ -864,19 +862,33 @@ linux_rt_sigreturn(struct thread *td, struct linux_rt_sigreturn_args *args)
return (EJUSTRETURN);
}
/*
* MPSAFE
*/
static void
linux_prepsyscall(struct trapframe *tf, int *args, u_int *code, caddr_t *params)
static int
linux_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
args[0] = tf->tf_ebx;
args[1] = tf->tf_ecx;
args[2] = tf->tf_edx;
args[3] = tf->tf_esi;
args[4] = tf->tf_edi;
args[5] = tf->tf_ebp; /* Unconfirmed */
*params = NULL; /* no copyin */
struct proc *p;
struct trapframe *frame;
p = td->td_proc;
frame = td->td_frame;
sa->code = frame->tf_eax;
sa->args[0] = frame->tf_ebx;
sa->args[1] = frame->tf_ecx;
sa->args[2] = frame->tf_edx;
sa->args[3] = frame->tf_esi;
sa->args[4] = frame->tf_edi;
sa->args[5] = frame->tf_ebp; /* Unconfirmed */
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
sa->callp = &p->p_sysent->sv_table[sa->code];
sa->narg = sa->callp->sy_narg;
td->td_retval[0] = 0;
td->td_retval[1] = frame->tf_edx;
return (0);
}
/*
@ -972,7 +984,7 @@ struct sysentvec linux_sysvec = {
.sv_sendsig = linux_sendsig,
.sv_sigcode = linux_sigcode,
.sv_szsigcode = &linux_szsigcode,
.sv_prepsyscall = linux_prepsyscall,
.sv_prepsyscall = NULL,
.sv_name = "Linux a.out",
.sv_coredump = NULL,
.sv_imgact_try = exec_linux_imgact_try,
@ -987,7 +999,10 @@ struct sysentvec linux_sysvec = {
.sv_setregs = exec_linux_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32
.sv_flags = SV_ABI_LINUX | SV_AOUT | SV_IA32 | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = linux_fetch_syscall_args,
.sv_syscallnames = NULL,
};
struct sysentvec elf_linux_sysvec = {
@ -1003,7 +1018,7 @@ struct sysentvec elf_linux_sysvec = {
.sv_sendsig = linux_sendsig,
.sv_sigcode = linux_sigcode,
.sv_szsigcode = &linux_szsigcode,
.sv_prepsyscall = linux_prepsyscall,
.sv_prepsyscall = NULL,
.sv_name = "Linux ELF",
.sv_coredump = elf32_coredump,
.sv_imgact_try = exec_linux_imgact_try,
@ -1018,7 +1033,10 @@ struct sysentvec elf_linux_sysvec = {
.sv_setregs = exec_linux_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32
.sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = linux_fetch_syscall_args,
.sv_syscallnames = NULL,
};
static char GNU_ABI_VENDOR[] = "GNU";

View File

@ -48,86 +48,15 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
extern char *syscallnames[];
#include <compat/ia32/ia32_util.h>
static void
ia32_syscall(struct trapframe *tf)
void
ia32_set_syscall_retval(struct thread *td, int error)
{
uint64_t args64[8];
uint32_t args[8];
struct thread *td;
struct proc *p;
struct sysent *callp;
caddr_t params;
register_t eflags;
u_int code;
int error, i, narg;
ksiginfo_t ksi;
struct trapframe *tf;
PCPU_INC(cnt.v_syscall);
td = curthread;
params = (caddr_t)(tf->tf_special.sp & ((1L<<32)-1)) +
sizeof(uint32_t);
code = tf->tf_scratch.gr8; /* eax */
eflags = ia64_get_eflag();
p = td->td_proc;
if (p->p_sysent->sv_prepsyscall == NULL) {
if (code == SYS_syscall) {
/* Code is first argument, followed by actual args. */
code = fuword32(params);
params += sizeof(int);
} else if (code == SYS___syscall) {
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments. We
* use a 32-bit fetch in case params is not aligned.
*/
code = fuword32(params);
params += sizeof(quad_t);
}
} else
(*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params);
if (p->p_sysent->sv_mask)
code &= p->p_sysent->sv_mask;
if (code >= p->p_sysent->sv_size)
callp = &p->p_sysent->sv_table[0];
else
callp = &p->p_sysent->sv_table[code];
narg = callp->sy_narg;
/* copyin and the ktrsyscall()/ktrsysret() code is MP-aware */
if (params != NULL && narg != 0)
error = copyin(params, (caddr_t)args, narg * sizeof(int));
else
error = 0;
for (i = 0; i < narg; i++)
args64[i] = args[i];
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(code, narg, args64);
#endif
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_proc->p_comm, code);
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = tf->tf_scratch.gr10; /* edx */
STOPEVENT(p, S_SCE, narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
AUDIT_SYSCALL_ENTER(code, td);
error = (*callp->sy_call)(td, args64);
AUDIT_SYSCALL_EXIT(error, td);
}
tf = td->td_frame;
switch (error) {
case 0:
@ -148,6 +77,7 @@ ia32_syscall(struct trapframe *tf)
break;
default:
p = td->td_proc;
if (p->p_sysent->sv_errsize) {
if (error >= p->p_sysent->sv_errsize)
error = -1; /* XXX */
@ -158,6 +88,74 @@ ia32_syscall(struct trapframe *tf)
ia64_set_eflag(ia64_get_eflag() | PSL_C);
break;
}
}
int
ia32_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
struct trapframe *tf;
struct proc *p;
uint32_t args[8];
caddr_t params;
int error, i;
tf = td->td_frame;
p = td->td_proc;
params = (caddr_t)(tf->tf_special.sp & ((1L<<32)-1)) +
sizeof(uint32_t);
sa->code = tf->tf_scratch.gr8; /* eax */
if (sa->code == SYS_syscall) {
/* Code is first argument, followed by actual args. */
sa->code = fuword32(params);
params += sizeof(int);
} else if (sa->code == SYS___syscall) {
/*
* Like syscall, but code is a quad, so as to maintain
* quad alignment for the rest of the arguments. We
* use a 32-bit fetch in case params is not aligned.
*/
sa->code = fuword32(params);
params += sizeof(quad_t);
}
if (p->p_sysent->sv_mask)
sa->code &= p->p_sysent->sv_mask;
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
sa->callp = &p->p_sysent->sv_table[sa->code];
sa->narg = sa->callp->sy_narg;
if (params != NULL && sa->narg != 0)
error = copyin(params, (caddr_t)args, sa->narg * sizeof(int));
else
error = 0;
if (error == 0) {
for (i = 0; i < sa->narg; i++)
sa->args[i] = args[i];
td->td_retval[0] = 0;
td->td_retval[1] = tf->tf_scratch.gr10; /* edx */
}
return (error);
}
static void
ia32_syscall(struct trapframe *tf)
{
struct thread *td;
struct syscall_args sa;
register_t eflags;
int error;
ksiginfo_t ksi;
td = curthread;
eflags = ia64_get_eflag();
error = syscallenter(td, &sa);
/*
* Traced syscall.
@ -171,37 +169,7 @@ ia32_syscall(struct trapframe *tf)
trapsignal(td, &ksi);
}
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
td->td_locks));
/*
* End of syscall tracing.
*/
CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_proc->p_comm, code);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(code, error, td->td_retval[0]);
#endif
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, code);
PTRACESTOP_SC(p, td, S_PT_SCX);
syscallret(td, error, &sa);
}
/*

View File

@ -81,7 +81,10 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_LP64
.sv_flags = SV_ABI_FREEBSD | SV_LP64,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
};
static Elf64_Brandinfo freebsd_brand_info = {

View File

@ -87,8 +87,6 @@ static void break_syscall(struct trapframe *tf);
*/
extern struct fpswa_iface *fpswa_iface;
extern char *syscallnames[];
static const char *ia64_vector_names[] = {
"VHPT Translation", /* 0 */
"Instruction TLB", /* 1 */
@ -899,6 +897,46 @@ break_syscall(struct trapframe *tf)
do_ast(tf);
}
int
cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
struct proc *p;
struct trapframe *tf;
register_t *args;
p = td->td_proc;
tf = td->td_frame;
sa->code = tf->tf_scratch.gr15;
args = &tf->tf_scratch.gr16;
/*
* syscall() and __syscall() are handled the same on
* the ia64, as everything is 64-bit aligned, anyway.
*/
if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
/*
* Code is first argument, followed by actual args.
*/
sa->code = args[0];
args++;
}
if (p->p_sysent->sv_mask)
sa->code &= p->p_sysent->sv_mask;
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
sa->callp = &p->p_sysent->sv_table[sa->code];
sa->narg = sa->callp->sy_narg;
bcopy(args, sa->args, sa->narg * sizeof(sa->args[0]));
td->td_retval[0] = 0;
td->td_retval[1] = 0;
return (0);
}
/*
* Process a system call.
*
@ -909,107 +947,18 @@ break_syscall(struct trapframe *tf)
int
syscall(struct trapframe *tf)
{
struct sysent *callp;
struct proc *p;
struct syscall_args sa;
struct thread *td;
uint64_t *args;
int code, error;
ia64_set_fpsr(IA64_FPSR_DEFAULT);
code = tf->tf_scratch.gr15;
args = &tf->tf_scratch.gr16;
PCPU_INC(cnt.v_syscall);
int error;
td = curthread;
td->td_frame = tf;
p = td->td_proc;
td->td_pticks = 0;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
if (p->p_sysent->sv_prepsyscall) {
/* (*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params); */
panic("prepsyscall");
} else {
/*
* syscall() and __syscall() are handled the same on
* the ia64, as everything is 64-bit aligned, anyway.
*/
if (code == SYS_syscall || code == SYS___syscall) {
/*
* Code is first argument, followed by actual args.
*/
code = args[0];
args++;
}
}
if (p->p_sysent->sv_mask)
code &= p->p_sysent->sv_mask;
if (code >= p->p_sysent->sv_size)
callp = &p->p_sysent->sv_table[0];
else
callp = &p->p_sysent->sv_table[code];
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(code, callp->sy_narg, args);
#endif
CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_name, code);
td->td_retval[0] = 0;
td->td_retval[1] = 0;
ia64_set_fpsr(IA64_FPSR_DEFAULT);
tf->tf_scratch.gr10 = EJUSTRETURN;
STOPEVENT(p, S_SCE, callp->sy_narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
AUDIT_SYSCALL_ENTER(code, td);
error = (*callp->sy_call)(td, args);
AUDIT_SYSCALL_EXIT(error, td);
cpu_set_syscall_retval(td, error);
td->td_syscalls++;
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
td->td_locks));
/*
* Handle reschedule and other end-of-syscall issues
*/
userret(td, tf);
CTR4(KTR_SYSC, "syscall exit thread %p pid %d proc %s code %d", td,
td->td_proc->p_pid, td->td_name, code);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(code, error, td->td_retval[0]);
#endif
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, code);
PTRACESTOP_SC(p, td, S_PT_SCX);
error = syscallenter(td, &sa);
syscallret(td, error, &sa);
return (error);
}

View File

@ -41,4 +41,14 @@ struct mdproc {
#define KINFO_PROC_SIZE 1088
#define KINFO_PROC32_SIZE 768
#ifdef _KERNEL
struct syscall_args {
u_int code;
struct sysent *callp;
register_t args[8];
int narg;
};
#define HAVE_SYSCALL_ARGS_DEF 1
#endif
#endif /* !_MACHINE_PROC_H_ */

View File

@ -89,6 +89,10 @@ struct sysentvec aout_sysvec = {
#else
#error Choose SV_XXX flags for the platform
#endif
,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
};
static int

View File

@ -334,6 +334,21 @@ set_boot_verbose(void *data __unused)
}
SYSINIT(boot_verbose, SI_SUB_TUNABLES, SI_ORDER_ANY, set_boot_verbose, NULL);
static int
null_fetch_syscall_args(struct thread *td __unused,
struct syscall_args *sa __unused)
{
panic("null_fetch_syscall_args");
}
static void
null_set_syscall_retval(struct thread *td __unused, int error __unused)
{
panic("null_set_syscall_retval");
}
struct sysentvec null_sysvec = {
.sv_size = 0,
.sv_table = NULL,
@ -361,7 +376,11 @@ struct sysentvec null_sysvec = {
.sv_copyout_strings = NULL,
.sv_setregs = NULL,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL
.sv_maxssiz = NULL,
.sv_flags = 0,
.sv_set_syscall_retval = null_set_syscall_retval,
.sv_fetch_syscall_args = null_fetch_syscall_args,
.sv_syscallnames = NULL,
};
/*

View File

@ -871,6 +871,10 @@ do_execve(td, args, mac_p)
free(imgp->freepath, M_TEMP);
if (error == 0) {
PROC_LOCK(p);
td->td_dbgflags |= TDB_EXEC;
PROC_UNLOCK(p);
/*
* Stop the process here if its stop event mask has
* the S_EXEC bit set.

View File

@ -1483,7 +1483,7 @@ kern_sigsuspend(struct thread *td, sigset_t mask)
* thread. But sigsuspend should return only on signal
* delivery.
*/
cpu_set_syscall_retval(td, EINTR);
(p->p_sysent->sv_set_syscall_retval)(td, EINTR);
for (has_sig = 0; !has_sig;) {
while (msleep(&p->p_sigacts, &p->p_mtx, PPAUSE|PCATCH, "pause",
0) == 0)

View File

@ -58,15 +58,20 @@ __FBSDID("$FreeBSD$");
#include <sys/pmckern.h>
#include <sys/proc.h>
#include <sys/ktr.h>
#include <sys/pioctl.h>
#include <sys/ptrace.h>
#include <sys/resourcevar.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
#include <sys/systm.h>
#include <sys/vmmeter.h>
#ifdef KTRACE
#include <sys/uio.h>
#include <sys/ktrace.h>
#endif
#include <security/audit/audit.h>
#include <machine/cpu.h>
#include <machine/pcb.h>
@ -253,3 +258,160 @@ ast(struct trapframe *framep)
userret(td, framep);
mtx_assert(&Giant, MA_NOTOWNED);
}
#ifdef HAVE_SYSCALL_ARGS_DEF
static const char *syscallname(struct proc *p, u_int code) __unused;
static const char *
syscallname(struct proc *p, u_int code)
{
static const char unknown[] = "unknown";
if (p->p_sysent->sv_syscallnames == NULL)
return (unknown);
return (p->p_sysent->sv_syscallnames[code]);
}
int
syscallenter(struct thread *td, struct syscall_args *sa)
{
struct proc *p;
int error, traced;
PCPU_INC(cnt.v_syscall);
p = td->td_proc;
td->td_syscalls++;
td->td_pticks = 0;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
if (p->p_flag & P_TRACED) {
traced = 1;
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
td->td_dbgflags |= TDB_SCE;
PROC_UNLOCK(p);
} else
traced = 0;
error = (p->p_sysent->sv_fetch_syscall_args)(td, sa);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->args);
#endif
CTR6(KTR_SYSC,
"syscall: td=%p pid %d %s (%#lx, %#lx, %#lx)",
td, td->td_proc->p_pid, syscallname(p, sa->code),
sa->args[0], sa->args[1], sa->args[2]);
if (error == 0) {
STOPEVENT(p, S_SCE, sa->narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
if (td->td_dbgflags & TDB_USERWR) {
/*
* Reread syscall number and arguments if
* debugger modified registers or memory.
*/
error = (p->p_sysent->sv_fetch_syscall_args)(td, sa);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->args);
#endif
if (error != 0)
goto retval;
}
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'entry', process the probe.
*/
if (systrace_probe_func != NULL && sa->callp->sy_entry != 0)
(*systrace_probe_func)(sa->callp->sy_entry, sa->code,
sa->callp, sa->args);
#endif
AUDIT_SYSCALL_ENTER(sa->code, td);
error = (sa->callp->sy_call)(td, sa->args);
AUDIT_SYSCALL_EXIT(error, td);
/* Save the latest error return value. */
td->td_errno = error;
#ifdef KDTRACE_HOOKS
/*
* If the systrace module has registered it's probe
* callback and if there is a probe active for the
* syscall 'return', process the probe.
*/
if (systrace_probe_func != NULL && sa->callp->sy_return != 0)
(*systrace_probe_func)(sa->callp->sy_return, sa->code,
sa->callp, sa->args);
#endif
CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx",
p, error, td->td_retval[0], td->td_retval[1]);
}
retval:
if (traced) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_SCE;
PROC_UNLOCK(p);
}
(p->p_sysent->sv_set_syscall_retval)(td, error);
return (error);
}
void
syscallret(struct thread *td, int error, struct syscall_args *sa __unused)
{
struct proc *p;
int traced;
p = td->td_proc;
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
syscallname(p, sa->code));
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
syscallname(p, sa->code)));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
syscallname(p, sa->code), td->td_locks));
/*
* Handle reschedule and other end-of-syscall issues
*/
userret(td, td->td_frame);
CTR4(KTR_SYSC, "syscall %s exit thread %p pid %d proc %s",
syscallname(p, sa->code), td, td->td_proc->p_pid, td->td_name);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(sa->code, error, td->td_retval[0]);
#endif
if (p->p_flag & P_TRACED) {
traced = 1;
PROC_LOCK(p);
td->td_dbgflags |= TDB_SCX;
PROC_UNLOCK(p);
} else
traced = 0;
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa->code);
PTRACESTOP_SC(p, td, S_PT_SCX);
if (traced || (td->td_dbgflags & TDB_EXEC) != 0) {
PROC_LOCK(p);
td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC);
PROC_UNLOCK(p);
}
}
#endif /* HAVE_SYSCALL_ARGS_DEF */

View File

@ -1105,9 +1105,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
pl->pl_lwpid = td2->td_tid;
if (td2->td_dbgflags & TDB_XSIG)
pl->pl_event = PL_EVENT_SIGNAL;
else
pl->pl_event = 0;
pl->pl_flags = 0;
if (td2->td_dbgflags & TDB_SCE)
pl->pl_flags |= PL_FLAG_SCE;
else if (td2->td_dbgflags & TDB_SCX)
pl->pl_flags |= PL_FLAG_SCX;
if (td2->td_dbgflags & TDB_EXEC)
pl->pl_flags |= PL_FLAG_EXEC;
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
break;

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/signalvar.h>
#include <sys/vnode.h>
@ -77,7 +78,10 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_LP64
.sv_flags = SV_ABI_FREEBSD | SV_LP64,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = NULL, /* XXXKIB */
.sv_syscallnames = NULL,
};
static Elf64_Brandinfo freebsd_brand_gnutools_info64 = {

View File

@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/linker.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/signalvar.h>
#include <sys/vnode.h>
@ -77,7 +78,10 @@ struct sysentvec elf64_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_LP64
.sv_flags = SV_ABI_FREEBSD | SV_LP64,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = NULL, /* XXXKIB */
.sv_syscallnames = syscallnames,
};
static Elf64_Brandinfo freebsd_brand_info = {
@ -129,7 +133,10 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_ILP32
.sv_flags = SV_ABI_FREEBSD | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = NULL, /* XXXKIB */
.sv_syscallnames = syscallnames,
};
static Elf32_Brandinfo freebsd_brand_info = {

View File

@ -261,7 +261,6 @@ SYSCTL_INT(_vm, OID_AUTO, allow_unaligned_acc, CTLFLAG_RW,
static int emulate_unaligned_access(struct trapframe *frame);
extern char *syscallnames[];
extern void fswintrberr(void); /* XXX */
/*

View File

@ -92,8 +92,6 @@ int setfault(faultbuf); /* defined in locore.S */
int badaddr(void *, size_t);
int badaddr_read(void *, size_t, int *);
extern char *syscallnames[];
struct powerpc_exception {
u_int vector;
char *name;
@ -320,125 +318,76 @@ handle_onfault(struct trapframe *frame)
return (0);
}
void
syscall(struct trapframe *frame)
int
cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
caddr_t params;
struct sysent *callp;
struct thread *td;
struct proc *p;
int error, n;
size_t narg;
register_t args[10];
u_int code;
struct proc *p;
struct trapframe *frame;
caddr_t params;
int error, n;
td = PCPU_GET(curthread);
p = td->td_proc;
frame = td->td_frame;
PCPU_INC(cnt.v_syscall);
code = frame->fixreg[0];
sa->code = frame->fixreg[0];
params = (caddr_t)(frame->fixreg + FIRSTARG);
n = NARGREG;
if (p->p_sysent->sv_prepsyscall) {
/*
* The prep code is MP aware.
*/
(*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
} else if (code == SYS_syscall) {
if (sa->code == SYS_syscall) {
/*
* code is first argument,
* followed by actual args.
*/
code = *(u_int *) params;
sa->code = *(u_int *) params;
params += sizeof(register_t);
n -= 1;
} else if (code == SYS___syscall) {
} else if (sa->code == SYS___syscall) {
/*
* Like syscall, but code is a quad,
* so as to maintain quad alignment
* for the rest of the args.
*/
params += sizeof(register_t);
code = *(u_int *) params;
sa->code = *(u_int *) params;
params += sizeof(register_t);
n -= 2;
}
if (p->p_sysent->sv_mask)
code &= p->p_sysent->sv_mask;
sa->code &= p->p_sysent->sv_mask;
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
sa->callp = &p->p_sysent->sv_table[sa->code];
if (code >= p->p_sysent->sv_size)
callp = &p->p_sysent->sv_table[0];
else
callp = &p->p_sysent->sv_table[code];
sa->narg = sa->callp->sy_narg;
narg = callp->sy_narg;
if (narg > n) {
bcopy(params, args, n * sizeof(register_t));
error = copyin(MOREARGS(frame->fixreg[1]), args + n,
(narg - n) * sizeof(register_t));
params = (caddr_t)args;
bcopy(params, sa->args, n * sizeof(register_t));
if (sa->narg > n) {
error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
(sa->narg - n) * sizeof(register_t));
} else
error = 0;
CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", td->td_name,
syscallnames[code],
frame->fixreg[FIRSTARG],
frame->fixreg[FIRSTARG+1],
frame->fixreg[FIRSTARG+2]);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(code, narg, (register_t *)params);
#endif
td->td_syscalls++;
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
STOPEVENT(p, S_SCE, narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
AUDIT_SYSCALL_ENTER(code, td);
error = (*callp->sy_call)(td, params);
AUDIT_SYSCALL_EXIT(error, td);
CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", td->td_name,
syscallnames[code], td->td_retval[0]);
}
return (error);
}
cpu_set_syscall_retval(td, error);
void
syscall(struct trapframe *frame)
{
struct thread *td;
struct syscall_args sa;
int error;
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
td->td_locks));
td = PCPU_GET(curthread);
td->td_frame = frame;
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(code, error, td->td_retval[0]);
#endif
/*
* Does the comment in the i386 code about errno apply here?
*/
STOPEVENT(p, S_SCX, code);
PTRACESTOP_SC(p, td, S_PT_SCX);
error = syscallenter(td, &sa);
syscallret(td, error, &sa);
}
static int

View File

@ -101,8 +101,6 @@ int setfault(faultbuf); /* defined in locore.S */
int badaddr(void *, size_t);
int badaddr_read(void *, size_t, int *);
extern char *syscallnames[];
struct powerpc_exception {
u_int vector;
char *name;
@ -324,125 +322,75 @@ handle_onfault(struct trapframe *frame)
return (0);
}
void
syscall(struct trapframe *frame)
int
cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
caddr_t params;
struct sysent *callp;
struct thread *td;
struct proc *p;
int error, n;
size_t narg;
register_t args[10];
u_int code;
struct proc *p;
struct trapframe *frame;
caddr_t params;
int error, n;
td = PCPU_GET(curthread);
p = td->td_proc;
frame = td->td_frame;
PCPU_INC(cnt.v_syscall);
code = frame->fixreg[0];
sa->code = frame->fixreg[0];
params = (caddr_t)(frame->fixreg + FIRSTARG);
n = NARGREG;
if (p->p_sysent->sv_prepsyscall) {
/*
* The prep code is MP aware.
*/
(*p->p_sysent->sv_prepsyscall)(frame, args, &code, &params);
} else if (code == SYS_syscall) {
if (sa->code == SYS_syscall) {
/*
* code is first argument,
* followed by actual args.
*/
code = *(u_int *) params;
sa->code = *(u_int *) params;
params += sizeof(register_t);
n -= 1;
} else if (code == SYS___syscall) {
} else if (sa->code == SYS___syscall) {
/*
* Like syscall, but code is a quad,
* so as to maintain quad alignment
* for the rest of the args.
*/
params += sizeof(register_t);
code = *(u_int *) params;
sa->code = *(u_int *) params;
params += sizeof(register_t);
n -= 2;
}
if (p->p_sysent->sv_mask)
code &= p->p_sysent->sv_mask;
if (code >= p->p_sysent->sv_size)
callp = &p->p_sysent->sv_table[0];
sa->code &= p->p_sysent->sv_mask;
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
callp = &p->p_sysent->sv_table[code];
sa->callp = &p->p_sysent->sv_table[sa->code];
sa->narg = sa->callp->sy_narg;
narg = callp->sy_narg;
if (narg > n) {
bcopy(params, args, n * sizeof(register_t));
error = copyin(MOREARGS(frame->fixreg[1]), args + n,
(narg - n) * sizeof(register_t));
params = (caddr_t)args;
bcopy(params, sa->args, n * sizeof(register_t));
if (sa->narg > n) {
error = copyin(MOREARGS(frame->fixreg[1]), sa->args + n,
(sa->narg - n) * sizeof(register_t));
} else
error = 0;
CTR5(KTR_SYSC, "syscall: p=%s %s(%x %x %x)", p->p_comm,
syscallnames[code],
frame->fixreg[FIRSTARG],
frame->fixreg[FIRSTARG+1],
frame->fixreg[FIRSTARG+2]);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(code, narg, (register_t *)params);
#endif
td->td_syscalls++;
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = frame->fixreg[FIRSTARG + 1];
STOPEVENT(p, S_SCE, narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
AUDIT_SYSCALL_ENTER(code, td);
error = (*callp->sy_call)(td, params);
AUDIT_SYSCALL_EXIT(error, td);
CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", p->p_comm,
syscallnames[code], td->td_retval[0]);
}
return (error);
}
cpu_set_syscall_retval(td, error);
void
syscall(struct trapframe *frame)
{
struct thread *td;
struct syscall_args sa;
int error;
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???",
td->td_locks));
td = PCPU_GET(curthread);
td->td_frame = frame;
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(code, error, td->td_retval[0]);
#endif
/*
* Does the comment in the i386 code about errno apply here?
*/
STOPEVENT(p, S_SCX, code);
PTRACESTOP_SC(p, td, S_PT_SCX);
error = syscallenter(td, &sa);
syscallret(td, error, &sa);
}
static int

View File

@ -48,4 +48,14 @@ struct mdproc {
#define KINFO_PROC_SIZE 768
#ifdef _KERNEL
struct syscall_args {
u_int code;
struct sysent *callp;
register_t args[10];
int narg;
};
#define HAVE_SYSCALL_ARGS_DEF 1
#endif
#endif /* !_MACHINE_PROC_H_ */

View File

@ -76,7 +76,10 @@ struct sysentvec elf32_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_ILP32
.sv_flags = SV_ABI_FREEBSD | SV_ILP32,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
};
static Elf32_Brandinfo freebsd_brand_info = {

View File

@ -53,4 +53,16 @@ struct mdproc {
#define KINFO_PROC_SIZE 1088
#ifdef _KERNEL
struct syscall_args {
u_int code;
struct sysent *callp;
register_t args[8];
int narg;
};
#define HAVE_SYSCALL_ARGS_DEF 1
#endif
#endif /* !_MACHINE_PROC_H_ */

View File

@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/linker.h>
#include <sys/proc.h>
#include <sys/sysent.h>
#include <sys/imgact_elf.h>
#include <sys/syscall.h>
@ -88,7 +89,10 @@ static struct sysentvec elf64_freebsd_sysvec = {
.sv_setregs = exec_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
.sv_flags = SV_ABI_FREEBSD | SV_LP64
.sv_flags = SV_ABI_FREEBSD | SV_LP64,
.sv_set_syscall_retval = cpu_set_syscall_retval,
.sv_fetch_syscall_args = cpu_fetch_syscall_args,
.sv_syscallnames = syscallnames,
};
static Elf64_Brandinfo freebsd_brand_info = {

View File

@ -94,18 +94,9 @@ __FBSDID("$FreeBSD$");
#include <machine/tsb.h>
#include <machine/watch.h>
struct syscall_args {
u_long code;
struct sysent *callp;
register_t args[8];
register_t *argp;
int narg;
};
void trap(struct trapframe *tf);
void syscall(struct trapframe *tf);
static int fetch_syscall_args(struct thread *td, struct syscall_args *sa);
static int trap_cecc(void);
static int trap_pfault(struct thread *td, struct trapframe *tf);
@ -123,8 +114,6 @@ extern char fas_fault[];
extern char fas_nofault_begin[];
extern char fas_nofault_end[];
extern char *syscallnames[];
const char *const trap_msg[] = {
"reserved",
"instruction access exception",
@ -579,11 +568,12 @@ trap_pfault(struct thread *td, struct trapframe *tf)
/* Maximum number of arguments that can be passed via the out registers. */
#define REG_MAXARGS 6
static int
fetch_syscall_args(struct thread *td, struct syscall_args *sa)
int
cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
struct trapframe *tf;
struct proc *p;
register_t *argp;
int reg;
int regcnt;
int error;
@ -595,19 +585,13 @@ fetch_syscall_args(struct thread *td, struct syscall_args *sa)
sa->code = tf->tf_global[1];
if (p->p_sysent->sv_prepsyscall) {
#if 0
(*p->p_sysent->sv_prepsyscall)(tf, sa->args, &sa->code,
&params);
#endif
} else if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
sa->code = tf->tf_out[reg++];
regcnt--;
}
if (p->p_sysent->sv_mask)
sa->code &= p->p_sysent->sv_mask;
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
@ -617,21 +601,17 @@ fetch_syscall_args(struct thread *td, struct syscall_args *sa)
KASSERT(sa->narg <= sizeof(sa->args) / sizeof(sa->args[0]),
("Too many syscall arguments!"));
error = 0;
sa->argp = sa->args;
argp = sa->args;
bcopy(&tf->tf_out[reg], sa->args, sizeof(sa->args[0]) * regcnt);
if (sa->narg > regcnt)
error = copyin((void *)(tf->tf_out[6] + SPOFF +
offsetof(struct frame, fr_pad[6])), &sa->args[regcnt],
(sa->narg - regcnt) * sizeof(sa->args[0]));
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = 0;
}
/*
* This may result in two records if debugger modified
* registers or memory during sleep at stop/ptrace point.
*/
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(sa->code, sa->narg, sa->argp);
#endif
return (error);
}
@ -644,29 +624,16 @@ fetch_syscall_args(struct thread *td, struct syscall_args *sa)
void
syscall(struct trapframe *tf)
{
struct syscall_args sa;
struct thread *td;
struct proc *p;
struct syscall_args sa;
int error;
td = curthread;
td->td_frame = tf;
KASSERT(td != NULL, ("trap: curthread NULL"));
KASSERT(td->td_proc != NULL, ("trap: curproc NULL"));
PCPU_INC(cnt.v_syscall);
p = td->td_proc;
td->td_syscalls++;
td->td_pticks = 0;
td->td_frame = tf;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
if ((p->p_flag & P_TRACED) != 0) {
PROC_LOCK(p);
td->td_dbgflags &= ~TDB_USERWR;
PROC_UNLOCK(p);
}
/*
* For syscalls, we don't want to retry the faulting instruction
* (usually), instead we need to advance one instruction.
@ -674,68 +641,6 @@ syscall(struct trapframe *tf)
td->td_pcb->pcb_tpc = tf->tf_tpc;
TF_DONE(tf);
error = fetch_syscall_args(td, &sa);
CTR5(KTR_SYSC, "syscall: td=%p %s(%#lx, %#lx, %#lx)", td,
syscallnames[sa.code], sa.argp[0], sa.argp[1], sa.argp[2]);
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = 0;
STOPEVENT(p, S_SCE, sa.narg);
PTRACESTOP_SC(p, td, S_PT_SCE);
if ((td->td_dbgflags & TDB_USERWR) != 0) {
/*
* Reread syscall number and arguments if
* debugger modified registers or memory.
*/
error = fetch_syscall_args(td, &sa);
if (error != 0)
goto retval;
td->td_retval[1] = 0;
}
AUDIT_SYSCALL_ENTER(sa.code, td);
error = (*sa.callp->sy_call)(td, sa.argp);
AUDIT_SYSCALL_EXIT(error, td);
CTR5(KTR_SYSC, "syscall: p=%p error=%d %s return %#lx %#lx",
p, error, syscallnames[sa.code], td->td_retval[0],
td->td_retval[1]);
}
retval:
cpu_set_syscall_retval(td, error);
/*
* Check for misbehavior.
*/
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???");
KASSERT(td->td_critnest == 0,
("System call %s returning in a critical section",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???"));
KASSERT(td->td_locks == 0,
("System call %s returning with %d locks held",
(sa.code >= 0 && sa.code < SYS_MAXSYSCALL) ?
syscallnames[sa.code] : "???", td->td_locks));
/*
* Handle reschedule and other end-of-syscall issues.
*/
userret(td, tf);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(sa.code, error, td->td_retval[0]);
#endif
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, sa.code);
PTRACESTOP_SC(p, td, S_PT_SCX);
error = syscallenter(td, &sa);
syscallret(td, error, &sa);
}

View File

@ -53,4 +53,16 @@ struct mdproc {
#define KINFO_PROC_SIZE 1088
#ifdef _KERNEL
struct syscall_args {
u_int code;
struct sysent *callp;
register_t args[8];
int narg;
};
#define HAVE_SYSCALL_ARGS_DEF 1
#endif
#endif /* !_MACHINE_PROC_H_ */

View File

@ -117,8 +117,6 @@ extern char fas_fault[];
extern char fas_nofault_begin[];
extern char fas_nofault_end[];
extern char *syscallnames[];
const char *const trap_msg[] = {
"reserved",
"instruction access exception",
@ -566,6 +564,53 @@ trap_pfault(struct thread *td, struct trapframe *tf, int64_t type, uint64_t data
/* Maximum number of arguments that can be passed via the out registers. */
#define REG_MAXARGS 6
int
cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa)
{
struct trapframe *tf;
struct proc *p;
register_t *argp;
int reg;
int regcnt;
int error;
p = td->td_proc;
tf = td->td_frame;
reg = 0;
regcnt = REG_MAXARGS;
sa->code = tf->tf_global[1];
if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
sa->code = tf->tf_out[reg++];
regcnt--;
}
if (p->p_sysent->sv_mask)
sa->code &= p->p_sysent->sv_mask;
if (sa->code >= p->p_sysent->sv_size)
sa->callp = &p->p_sysent->sv_table[0];
else
sa->callp = &p->p_sysent->sv_table[sa->code];
sa->narg = sa->callp->sy_narg;
KASSERT(sa->narg <= sizeof(sa->args) / sizeof(sa->args[0]),
("Too many syscall arguments!"));
error = 0;
argp = sa->args;
bcopy(&tf->tf_out[reg], sa->args, sizeof(sa->args[0]) * regcnt);
if (sa->narg > regcnt)
error = copyin((void *)(tf->tf_out[6] + SPOFF +
offsetof(struct frame, fr_pad[6])), &sa->args[regcnt],
(sa->narg - regcnt) * sizeof(sa->args[0]));
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = 0;
}
return (error);
}
/*
* Syscall handler. The arguments to the syscall are passed in the o registers
* by the caller, and are saved in the trap frame. The syscall number is passed
@ -574,31 +619,16 @@ trap_pfault(struct thread *td, struct trapframe *tf, int64_t type, uint64_t data
void
syscall(struct trapframe *tf)
{
struct sysent *callp;
struct thread *td;
register_t args[8];
register_t *argp;
struct proc *p;
u_long code;
int reg;
int regcnt;
int narg;
struct syscall_args sa;
int error;
td = curthread;
td->td_frame = tf;
KASSERT(td != NULL, ("trap: curthread NULL"));
KASSERT(td->td_proc != NULL, ("trap: curproc NULL"));
p = td->td_proc;
PCPU_INC(cnt.v_syscall);
td->td_pticks = 0;
td->td_frame = tf;
if (td->td_ucred != p->p_ucred)
cred_update_thread(td);
code = tf->tf_global[1];
/*
* For syscalls, we don't want to retry the faulting instruction
* (usually), instead we need to advance one instruction.
@ -606,92 +636,7 @@ syscall(struct trapframe *tf)
td->td_pcb->pcb_tpc = tf->tf_tpc;
TF_DONE(tf);
reg = 0;
regcnt = REG_MAXARGS;
if (p->p_sysent->sv_prepsyscall) {
/*
* The prep code is MP aware.
*/
#if 0
(*p->p_sysent->sv_prepsyscall)(tf, args, &code, &params);
#endif
} else if (code == SYS_syscall || code == SYS___syscall) {
code = tf->tf_out[reg++];
regcnt--;
}
if (p->p_sysent->sv_mask)
code &= p->p_sysent->sv_mask;
if (code >= p->p_sysent->sv_size)
callp = &p->p_sysent->sv_table[0];
else
callp = &p->p_sysent->sv_table[code];
narg = callp->sy_narg;
if (narg <= regcnt) {
argp = &tf->tf_out[reg];
error = 0;
} else {
KASSERT(narg <= sizeof(args) / sizeof(args[0]),
("Too many syscall arguments!"));
argp = args;
bcopy(&tf->tf_out[reg], args, sizeof(args[0]) * regcnt);
error = copyin((void *)(tf->tf_out[6] + SPOFF +
offsetof(struct frame, fr_pad[6])),
&args[regcnt], (narg - regcnt) * sizeof(args[0]));
}
CTR5(KTR_SYSC, "syscall: td=%p %s(%#lx, %#lx, %#lx)", td,
syscallnames[code], argp[0], argp[1], argp[2]);
/*
* Try to run the syscall without the MP lock if the syscall
* is MP safe.
*/
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSCALL))
ktrsyscall(code, narg, argp);
#endif
if (error == 0) {
td->td_retval[0] = 0;
td->td_retval[1] = 0;
STOPEVENT(p, S_SCE, narg); /* MP aware */
PTRACESTOP_SC(p, td, S_PT_SCE);
AUDIT_SYSCALL_ENTER(code, td);
error = (*callp->sy_call)(td, argp);
AUDIT_SYSCALL_EXIT(error, td);
CTR5(KTR_SYSC, "syscall: p=%p error=%d %s return %#lx %#lx ", p,
error, syscallnames[code], td->td_retval[0],
td->td_retval[1]);
}
cpu_set_syscall_retval(td, error);
/*
* Handle reschedule and other end-of-syscall issues
*/
userret(td, tf);
#ifdef KTRACE
if (KTRPOINT(td, KTR_SYSRET))
ktrsysret(code, error, td->td_retval[0]);
#endif
/*
* This works because errno is findable through the
* register set. If we ever support an emulation where this
* is not the case, this code will need to be revisited.
*/
STOPEVENT(p, S_SCX, code);
PTRACESTOP_SC(p, td, S_PT_SCX);
WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
(code >= 0 && code < SYS_MAXSYSCALL) ? syscallnames[code] : "???");
mtx_assert(&Giant, MA_NOTOWNED);
error = syscallenter(td, &sa);
syscallret(td, error, &sa);
}

View File

@ -364,6 +364,9 @@ do { \
#define TDB_SUSPEND 0x00000001 /* Thread is suspended by debugger */
#define TDB_XSIG 0x00000002 /* Thread is exchanging signal under trace */
#define TDB_USERWR 0x00000004 /* Debugger modified memory or registers */
#define TDB_SCE 0x00000008 /* Thread performs syscall enter */
#define TDB_SCX 0x00000010 /* Thread performs syscall exit */
#define TDB_EXEC 0x00000020 /* TDB_SCX from exec(2) family */
/*
* "Private" flags kept in td_pflags:
@ -837,9 +840,14 @@ void cpu_switch(struct thread *, struct thread *, struct mtx *);
void cpu_throw(struct thread *, struct thread *) __dead2;
void unsleep(struct thread *);
void userret(struct thread *, struct trapframe *);
struct syscall_args;
int syscallenter(struct thread *, struct syscall_args *);
void syscallret(struct thread *, int, struct syscall_args *);
void cpu_exit(struct thread *);
void exit1(struct thread *, int) __dead2;
struct syscall_args;
int cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa);
void cpu_fork(struct thread *, struct proc *, struct thread *, int);
void cpu_set_fork_handler(struct thread *, void (*)(void *), void *);
void cpu_set_syscall_retval(struct thread *, int);

View File

@ -99,6 +99,9 @@ struct ptrace_lwpinfo {
int pl_flags; /* LWP flags. */
#define PL_FLAG_SA 0x01 /* M:N thread */
#define PL_FLAG_BOUND 0x02 /* M:N bound thread */
#define PL_FLAG_SCE 0x04 /* syscall enter point */
#define PL_FLAG_SCX 0x08 /* syscall leave point */
#define PL_FLAG_EXEC 0x10 /* exec(2) succeeded */
sigset_t pl_sigmask; /* LWP signal mask */
sigset_t pl_siglist; /* LWP pending signal */
};

View File

@ -65,6 +65,7 @@ struct sysent { /* system call table */
struct image_params;
struct __sigset;
struct syscall_args;
struct trapframe;
struct vnode;
@ -103,6 +104,10 @@ struct sysentvec {
void (*sv_fixlimit)(struct rlimit *, int);
u_long *sv_maxssiz;
u_int sv_flags;
void (*sv_set_syscall_retval)(struct thread *, int);
int (*sv_fetch_syscall_args)(struct thread *, struct
syscall_args *);
const char **sv_syscallnames;
};
#define SV_ILP32 0x000100
@ -123,6 +128,7 @@ extern struct sysentvec aout_sysvec;
extern struct sysentvec elf_freebsd_sysvec;
extern struct sysentvec null_sysvec;
extern struct sysent sysent[];
extern const char *syscallnames[];
#define NO_SYSCALL (-1)