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:
parent
fa1ed4bd1a
commit
afe1a68827
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=208453
@ -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 = {
|
||||
|
@ -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, ¶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);
|
||||
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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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_ */
|
||||
|
@ -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";
|
||||
|
@ -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 = {
|
||||
|
@ -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() */
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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";
|
||||
|
@ -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, ¶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];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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 = {
|
||||
|
@ -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, ¶ms); */
|
||||
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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
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
|
||||
|
@ -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];
|
||||
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
|
||||
|
@ -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_ */
|
||||
|
@ -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 = {
|
||||
|
@ -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_ */
|
||||
|
@ -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 = {
|
||||
|
@ -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,
|
||||
¶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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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, ¶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];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user