diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index dc7c8b9..6472d55 100644 --- a/sys/amd64/amd64/elf_machdep.c +++ b/sys/amd64/amd64/elf_machdep.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 = { diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index d5ddc59..2deb931 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -76,7 +76,6 @@ __FBSDID("$FreeBSD$"); #ifdef HWPMC_HOOKS #include #endif -#include #include #include @@ -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, ¶ms); - } 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); - - 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); + td = curthread; + td->td_frame = frame; - /* 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); } diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c index aa1ae6c..6a649ae 100644 --- a/sys/amd64/ia32/ia32_syscall.c +++ b/sys/amd64/ia32/ia32_syscall.c @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -81,62 +82,54 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #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); + orig_tf_rflags = frame->tf_rflags; 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); - - 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) { diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h index acea4c0..2de7a9e 100644 --- a/sys/amd64/include/proc.h +++ b/sys/amd64/include/proc.h @@ -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_ */ diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index 06f1e97..010e1d6 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -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"; diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c index d77e7d4..e77a542 100644 --- a/sys/arm/arm/elf_machdep.c +++ b/sys/arm/arm/elf_machdep.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 = { diff --git a/sys/arm/arm/trap.c b/sys/arm/arm/trap.c index 284e797..c7c84d0 100644 --- a/sys/arm/arm/trap.c +++ b/sys/arm/arm/trap.c @@ -130,7 +130,6 @@ void undefinedinstruction(trapframe_t *); #include extern char fusubailout[]; -extern char *syscallnames[]; #ifdef DEBUG int last_fault_code; /* For the benefit of pmap_fault_fixup() */ diff --git a/sys/cddl/dev/systrace/systrace.c b/sys/cddl/dev/systrace/systrace.c index e54f776..72c25e4 100644 --- a/sys/cddl/dev/systrace/systrace.c +++ b/sys/cddl/dev/systrace/systrace.c @@ -77,7 +77,6 @@ extern struct sysent linux_sysent[]; */ #include #include -extern const char *syscallnames[]; #define DEVNAME "dtrace/systrace" #define PROVNAME "syscall" #define MAXSYSCALL SYS_MAXSYSCALL diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c index 79448a5..d7ac5d0 100644 --- a/sys/compat/ia32/ia32_sysvec.c +++ b/sys/compat/ia32/ia32_sysvec.c @@ -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, }; diff --git a/sys/compat/ia32/ia32_util.h b/sys/compat/ia32/ia32_util.h index a2b88cb..d91bfde 100644 --- a/sys/compat/ia32/ia32_util.h +++ b/sys/compat/ia32/ia32_util.h @@ -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); diff --git a/sys/compat/svr4/svr4_sysvec.c b/sys/compat/svr4/svr4_sysvec.c index 54406f5..e15232b 100644 --- a/sys/compat/svr4/svr4_sysvec.c +++ b/sys/compat/svr4/svr4_sysvec.c @@ -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"; diff --git a/sys/conf/files b/sys/conf/files index aeb68bc..23fab8c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -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 diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c index 408d6ad..df3f48f 100644 --- a/sys/i386/i386/elf_machdep.c +++ b/sys/i386/i386/elf_machdep.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 = { diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index a11daa6..644bb47 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -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, - ¶ms); - } 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); - - 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); + td = curthread; + td->td_frame = frame; - /* 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); } - diff --git a/sys/i386/ibcs2/ibcs2_sysvec.c b/sys/i386/ibcs2/ibcs2_sysvec.c index 9112ed7..71d48a3 100644 --- a/sys/i386/ibcs2/ibcs2_sysvec.c +++ b/sys/i386/ibcs2/ibcs2_sysvec.c @@ -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 diff --git a/sys/i386/include/proc.h b/sys/i386/include/proc.h index 86be8c8..0d92252 100644 --- a/sys/i386/include/proc.h +++ b/sys/i386/include/proc.h @@ -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_ */ diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c index 3f0c6f4..364cc0c 100644 --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -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"; diff --git a/sys/ia64/ia32/ia32_trap.c b/sys/ia64/ia32/ia32_trap.c index ba2bceb..9c7f08d 100644 --- a/sys/ia64/ia32/ia32_trap.c +++ b/sys/ia64/ia32/ia32_trap.c @@ -48,86 +48,15 @@ __FBSDID("$FreeBSD$"); #include -extern char *syscallnames[]; +#include -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; - - 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, ¶ms); - - 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]; + struct trapframe *tf; - 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); } /* diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c index 8360165..87fcd4f 100644 --- a/sys/ia64/ia64/elf_machdep.c +++ b/sys/ia64/ia64/elf_machdep.c @@ -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 = { diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c index f539097..2725b0f 100644 --- a/sys/ia64/ia64/trap.c +++ b/sys/ia64/ia64/trap.c @@ -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,117 +897,68 @@ break_syscall(struct trapframe *tf) do_ast(tf); } -/* - * Process a system call. - * - * See syscall.s for details as to how we get here. In order to support - * the ERESTART case, we return the error to our caller. They deal with - * the hairy details. - */ int -syscall(struct trapframe *tf) +cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) { - struct sysent *callp; struct proc *p; - 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); + struct trapframe *tf; + register_t *args; - td = curthread; - td->td_frame = tf; p = td->td_proc; + tf = td->td_frame; - td->td_pticks = 0; - if (td->td_ucred != p->p_ucred) - cred_update_thread(td); + sa->code = tf->tf_scratch.gr15; + args = &tf->tf_scratch.gr16; - if (p->p_sysent->sv_prepsyscall) { - /* (*p->p_sysent->sv_prepsyscall)(tf, args, &code, ¶ms); */ - panic("prepsyscall"); - } else { + /* + * 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) { /* - * syscall() and __syscall() are handled the same on - * the ia64, as everything is 64-bit aligned, anyway. + * Code is first argument, followed by actual args. */ - if (code == SYS_syscall || code == SYS___syscall) { - /* - * Code is first argument, followed by actual args. - */ - code = args[0]; - args++; - } + sa->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); + 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); td->td_retval[0] = 0; td->td_retval[1] = 0; - 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)); + return (0); +} - /* - * Handle reschedule and other end-of-syscall issues - */ - userret(td, tf); +/* + * Process a system call. + * + * See syscall.s for details as to how we get here. In order to support + * the ERESTART case, we return the error to our caller. They deal with + * the hairy details. + */ +int +syscall(struct trapframe *tf) +{ + struct syscall_args sa; + struct thread *td; + int error; - 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 + td = curthread; + td->td_frame = tf; - /* - * 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); + ia64_set_fpsr(IA64_FPSR_DEFAULT); + tf->tf_scratch.gr10 = EJUSTRETURN; - PTRACESTOP_SC(p, td, S_PT_SCX); + error = syscallenter(td, &sa); + syscallret(td, error, &sa); return (error); } diff --git a/sys/ia64/include/proc.h b/sys/ia64/include/proc.h index e9f337c..574be36 100644 --- a/sys/ia64/include/proc.h +++ b/sys/ia64/include/proc.h @@ -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_ */ diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c index 6c2f627..6710135 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -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 diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index e9090fb..d608e25 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -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, }; /* diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index fc87d63..149e6df 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -871,6 +871,10 @@ exec_fail_dealloc: 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. diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 789bb61..d52cedb 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -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) diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 4d20ebd..4cc56cc 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -58,15 +58,20 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include +#include +#include #include #include #ifdef KTRACE #include #include #endif +#include #include #include @@ -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 */ diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index d8cc4f0..6decc02 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -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; diff --git a/sys/mips/mips/elf64_machdep.c b/sys/mips/mips/elf64_machdep.c index d63fdbc..41b6691 100644 --- a/sys/mips/mips/elf64_machdep.c +++ b/sys/mips/mips/elf64_machdep.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 = { diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c index a7bd755..fc1bc15 100644 --- a/sys/mips/mips/elf_machdep.c +++ b/sys/mips/mips/elf_machdep.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 = { diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 17a6be5..831e018 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -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 */ /* diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c index 35f4147..74e0f26 100644 --- a/sys/powerpc/aim/trap.c +++ b/sys/powerpc/aim/trap.c @@ -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, ¶ms); - } 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]; - else - callp = &p->p_sysent->sv_table[code]; - - 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; + 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(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); - - /* - * 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)); - -#ifdef KTRACE - if (KTRPOINT(td, KTR_SYSRET)) - ktrsysret(code, error, td->td_retval[0]); -#endif +void +syscall(struct trapframe *frame) +{ + struct thread *td; + struct syscall_args sa; + int error; + + td = PCPU_GET(curthread); + td->td_frame = frame; - /* - * 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 diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c index db9be64..93dc597 100644 --- a/sys/powerpc/booke/trap.c +++ b/sys/powerpc/booke/trap.c @@ -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, ¶ms); - } 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]; - - narg = callp->sy_narg; + sa->callp = &p->p_sysent->sv_table[sa->code]; + sa->narg = sa->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); - - /* - * 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)); - -#ifdef KTRACE - if (KTRPOINT(td, KTR_SYSRET)) - ktrsysret(code, error, td->td_retval[0]); -#endif +void +syscall(struct trapframe *frame) +{ + struct thread *td; + struct syscall_args sa; + int error; - /* - * Does the comment in the i386 code about errno apply here? - */ - STOPEVENT(p, S_SCX, code); + td = PCPU_GET(curthread); + td->td_frame = frame; - PTRACESTOP_SC(p, td, S_PT_SCX); + error = syscallenter(td, &sa); + syscallret(td, error, &sa); } static int diff --git a/sys/powerpc/include/proc.h b/sys/powerpc/include/proc.h index d51116b..f3bb8af 100644 --- a/sys/powerpc/include/proc.h +++ b/sys/powerpc/include/proc.h @@ -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_ */ diff --git a/sys/powerpc/powerpc/elf_machdep.c b/sys/powerpc/powerpc/elf_machdep.c index c370309..60fb02f 100644 --- a/sys/powerpc/powerpc/elf_machdep.c +++ b/sys/powerpc/powerpc/elf_machdep.c @@ -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 = { diff --git a/sys/sparc64/include/proc.h b/sys/sparc64/include/proc.h index 3c23663..dceea17 100644 --- a/sys/sparc64/include/proc.h +++ b/sys/sparc64/include/proc.h @@ -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_ */ diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c index 2f9ee39..8ddf476 100644 --- a/sys/sparc64/sparc64/elf_machdep.c +++ b/sys/sparc64/sparc64/elf_machdep.c @@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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 = { diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c index c0772a1..8ce6970 100644 --- a/sys/sparc64/sparc64/trap.c +++ b/sys/sparc64/sparc64/trap.c @@ -94,18 +94,9 @@ __FBSDID("$FreeBSD$"); #include #include -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, - ¶ms); -#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); } diff --git a/sys/sun4v/sun4v/trap.c b/sys/sun4v/sun4v/trap.c index 702fd5c..d099351 100644 --- a/sys/sun4v/sun4v/trap.c +++ b/sys/sun4v/sun4v/trap.c @@ -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,132 +564,79 @@ 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 -/* - * 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 - * in %g1 (and also saved in the trap frame). - */ -void -syscall(struct trapframe *tf) +int +cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa) { - struct sysent *callp; - struct thread *td; - register_t args[8]; - register_t *argp; + struct trapframe *tf; struct proc *p; - u_long code; + register_t *argp; int reg; int regcnt; - int narg; int error; - td = curthread; - 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. - */ - td->td_pcb->pcb_tpc = tf->tf_tpc; - TF_DONE(tf); - + tf = td->td_frame; 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, ¶ms); -#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]; + sa->code = tf->tf_global[1]; - 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])); + if (sa->code == SYS_syscall || sa->code == SYS___syscall) { + sa->code = tf->tf_out[reg++]; + regcnt--; } - 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 (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; + } - 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); + return (error); +} - CTR5(KTR_SYSC, "syscall: p=%p error=%d %s return %#lx %#lx ", p, - error, syscallnames[code], td->td_retval[0], - td->td_retval[1]); - } +/* + * 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 + * in %g1 (and also saved in the trap frame). + */ +void +syscall(struct trapframe *tf) +{ + struct thread *td; + struct syscall_args sa; + int error; - cpu_set_syscall_retval(td, error); + td = curthread; + td->td_frame = tf; - /* - * Handle reschedule and other end-of-syscall issues - */ - userret(td, tf); + KASSERT(td != NULL, ("trap: curthread NULL")); + KASSERT(td->td_proc != NULL, ("trap: curproc NULL")); -#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. + * For syscalls, we don't want to retry the faulting instruction + * (usually), instead we need to advance one instruction. */ - STOPEVENT(p, S_SCX, code); - - PTRACESTOP_SC(p, td, S_PT_SCX); + td->td_pcb->pcb_tpc = tf->tf_tpc; + TF_DONE(tf); - 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); } + diff --git a/sys/sys/proc.h b/sys/sys/proc.h index e32e494..1195019 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -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); diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index b30447c..a6dbe2c 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -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 */ }; diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index c3a19d8..6a8f538 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -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)