Author: kib
Date: Sat Jan 23 11:45:35 2010
New Revision: 202882
URL: http://svn.freebsd.org/changeset/base/202882
Log:
For PT_TO_SCE stop that stops the ptraced process upon syscall entry,
syscall arguments are collected before ptracestop() is called. As a
consequence, debugger cannot modify syscall or its arguments.
For i386, amd64 and ia32 on amd64 MD syscall(), reread syscall number
and arguments after ptracestop(), if debugger modified anything in the
process environment. Since procfs stopeven requires number of syscall
arguments in p_xstat, this cannot be solved by moving stop/trace point
before argument fetching.
Move the code to read arguments into separate function
fetch_syscall_args() to avoid code duplication. Note that ktrace point
for modified syscall is intentionally recorded twice, once with original
arguments, and second time with the arguments set by debugger.
PT_TO_SCX stop is executed after cpu_syscall_set_retval() already.
Reported by: Ali Polatel
Briefly discussed with: jhb
MFC after:3 weeks
Modified:
head/sys/amd64/amd64/trap.c
head/sys/amd64/ia32/ia32_syscall.c
head/sys/i386/i386/trap.c
head/sys/kern/sys_process.c
head/sys/sys/proc.h
Modified: head/sys/amd64/amd64/trap.c
==
--- head/sys/amd64/amd64/trap.c Sat Jan 23 11:43:30 2010(r202881)
+++ head/sys/amd64/amd64/trap.c Sat Jan 23 11:45:35 2010(r202882)
@@ -885,95 +885,131 @@ dblfault_handler(struct trapframe *frame
panic("double fault");
}
-/*
- * syscall - system call request C handler
- *
- * A system call is essentially treated as a trap.
- */
-void
-syscall(struct trapframe *frame)
-{
- caddr_t params;
+struct syscall_args {
+ u_int code;
struct sysent *callp;
- struct thread *td = curthread;
- struct proc *p = td->td_proc;
- register_t orig_tf_rflags;
- int error;
- int narg;
register_t args[8];
register_t *argp;
- u_int code;
- int reg, regcnt;
- ksiginfo_t ksi;
-
- PCPU_INC(cnt.v_syscall);
+ int narg;
+};
-#ifdef DIAGNOSTIC
- if (ISPL(frame->tf_cs) != SEL_UPL) {
- panic("syscall");
- /* NOT REACHED */
- }
-#endif
+static int
+fetch_syscall_args(struct thread *td, struct syscall_args *sa)
+{
+ struct proc *p;
+ struct trapframe *frame;
+ caddr_t params;
+ int reg, regcnt, error;
+ p = td->td_proc;
+ frame = td->td_frame;
reg = 0;
regcnt = 6;
- td->td_pticks = 0;
- td->td_frame = frame;
- if (td->td_ucred != p->p_ucred)
- cred_update_thread(td);
+
params = (caddr_t)frame->tf_rsp + sizeof(register_t);
- code = frame->tf_rax;
- orig_tf_rflags = frame->tf_rflags;
+ sa->code = frame->tf_rax;
if (p->p_sysent->sv_prepsyscall) {
- (*p->p_sysent->sv_prepsyscall)(frame, (int *)args, &code,
¶ms);
+ (*p->p_sysent->sv_prepsyscall)(frame, (int *)sa->args,
+ &sa->code, ¶ms);
} else {
- if (code == SYS_syscall || code == SYS___syscall) {
- code = frame->tf_rdi;
+ if (sa->code == SYS_syscall || sa->code == SYS___syscall) {
+ sa->code = frame->tf_rdi;
reg++;
regcnt--;
}
}
-
if (p->p_sysent->sv_mask)
- code &= p->p_sysent->sv_mask;
+ sa->code &= p->p_sysent->sv_mask;
- if (code >= p->p_sysent->sv_size)
- callp = &p->p_sysent->sv_table[0];
+ 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];
- narg = callp->sy_narg;
- KASSERT(narg <= sizeof(args) / sizeof(args[0]),
+ sa->narg = sa->callp->sy_narg;
+ KASSERT(sa->narg <= sizeof(sa->args) / sizeof(sa->args[0]),
("Too many syscall arguments!"));
error = 0;
- argp = &frame->tf_rdi;
- argp += reg;
- bcopy(argp, args, sizeof(args[0]) * regcnt);
- if (narg > regcnt) {
+ sa->argp = &frame->tf_rdi;
+ sa->argp += reg;
+ bcopy(sa->argp, sa->args, sizeof(sa->args[0]) * regcnt);
+ if (sa->narg > regcnt) {
KASSERT(params != NULL, ("copyin args with no params!"));
- error = copyin(params, &args[regcnt],
- (narg - regcnt) * sizeof(args[0]));
+ error = copyin(params, &sa->args[regcnt],
+ (sa->narg - regcnt) * sizeof(sa->args[0]));
}
- argp = &args[0];
+ sa->argp = &sa->args[0];
+ /*
+* This may result in two records if debugger modified
+