Ability to tell the difference between normal and syscall traps

Kostik Belousov kostikbel at gmail.com
Fri May 14 12:57:38 UTC 2010


On Fri, May 14, 2010 at 06:51:19AM -0400, John Baldwin wrote:
> Ali Polatel wrote:
> >Kostik Belousov yazm????:
> >>On Mon, May 10, 2010 at 07:48:47PM +0300, Ali Polatel wrote:
> >>>Another question is how hard is it to implement PL_EVENT_EXEC?
> >>>This could be useful for truss as it updates the execution type of the
> >>>process after successful execve() calls afaict.
> >>Is this needed ? The question is not rhetorical, I am trying to
> >>understand what prevents use of PT_TO_SCE and checking the syscall
> >>number ? You would screen for SYS_execve or SYS_fexecve and
> >>reset the debugger state on SIGTRAP that is supplied to the debugger
> >>before first instruction of new image is executed.
> >>
> >
> >Not really needed, just cleaner imo. As system call numbers may be
> >different for different execution types and you need to look it up from
> >a table using a string as argument which is slow.
> 
> I agree that this would be cleaner.  Having worked on the ptrace/procfs 
> stuff in other tools like strace and truss, exec truly is an important 
> event to a debugger aside from just being another system call as it 
> signals that the address space has been changed.

Ok, I would not much object. But I finally tired of adding the same code
to three places (ignoring !x86 arches).

diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index d5ddc59..39eb435 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -170,7 +170,7 @@ 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[];
+extern const char *syscallnames[];
 
 /*
  * Exception, fault, and trap interface to the FreeBSD kernel.
@@ -884,7 +884,7 @@ syscall(struct trapframe *frame)
 	struct proc *p;
 	struct syscall_args sa;
 	register_t orig_tf_rflags;
-	int error;
+	int error, traced;
 	ksiginfo_t ksi;
 
 	PCPU_INC(cnt.v_syscall);
@@ -905,10 +905,13 @@ syscall(struct trapframe *frame)
 		cred_update_thread(td);
 	orig_tf_rflags = frame->tf_rflags;
 	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 = fetch_syscall_args(td, &sa);
 
 	CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
@@ -961,6 +964,11 @@ syscall(struct trapframe *frame)
 #endif
 	}
  retval:
+	if (traced) {
+		PROC_LOCK(p);
+		td->td_dbgflags &= ~TDB_SCE;
+		PROC_UNLOCK(p);
+	}
 	cpu_set_syscall_retval(td, error);
 
 	/*
@@ -975,40 +983,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.code, syscallnames);
 }
diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c
index aa1ae6c..ad82210 100644
--- a/sys/amd64/ia32/ia32_syscall.c
+++ b/sys/amd64/ia32/ia32_syscall.c
@@ -170,7 +170,7 @@ ia32_syscall(struct trapframe *frame)
 	struct proc *p;
 	struct ia32_syscall_args sa;
 	register_t orig_tf_rflags;
-	int error;
+	int error, traced;
 	ksiginfo_t ksi;
 
 	PCPU_INC(cnt.v_syscall);
@@ -184,10 +184,13 @@ ia32_syscall(struct trapframe *frame)
 		cred_update_thread(td);
 	orig_tf_rflags = frame->tf_rflags;
 	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 = fetch_ia32_syscall_args(td, &sa);
 
 	CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
@@ -218,6 +221,11 @@ ia32_syscall(struct trapframe *frame)
 		td->td_errno = error;
 	}
  retval:
+	if (traced) {
+		PROC_LOCK(p);
+		td->td_dbgflags &= ~TDB_SCE;
+		PROC_UNLOCK(p);
+	}
 	cpu_set_syscall_retval(td, error);
 
 	/*
@@ -232,44 +240,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.code, freebsd32_syscallnames);
 }
 
-
 static void
 ia32_syscall_enable(void *dummy)
 {
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index a11daa6..35df54b 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -184,7 +184,7 @@ 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[];
+extern const char *syscallnames[];
 
 /*
  * Exception, fault, and trap interface to the FreeBSD kernel.
@@ -1051,7 +1051,7 @@ syscall(struct trapframe *frame)
 	struct proc *p;
 	struct syscall_args sa;
 	register_t orig_tf_eflags;
-	int error;
+	int error, traced;
 	ksiginfo_t ksi;
 
 	PCPU_INC(cnt.v_syscall);
@@ -1072,10 +1072,13 @@ syscall(struct trapframe *frame)
 		cred_update_thread(td);
 	orig_tf_eflags = frame->tf_eflags;
 	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 = fetch_syscall_args(td, &sa);
 
 	CTR4(KTR_SYSC, "syscall enter thread %p pid %d proc %s code %d", td,
@@ -1128,6 +1131,11 @@ syscall(struct trapframe *frame)
 #endif
 	}
  retval:
+	if (traced) {
+		PROC_LOCK(p);
+		td->td_dbgflags &= ~TDB_SCE;
+		PROC_UNLOCK(p);
+	}
 	cpu_set_syscall_retval(td, error);
 
 	/*
@@ -1142,41 +1150,6 @@ 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.code, syscallnames);
 }
 
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/subr_trap.c b/sys/kern/subr_trap.c
index 4d20ebd..ea6b0ae 100644
--- a/sys/kern/subr_trap.c
+++ b/sys/kern/subr_trap.c
@@ -58,9 +58,12 @@ __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/systm.h>
 #include <sys/vmmeter.h>
 #ifdef KTRACE
@@ -253,3 +256,61 @@ ast(struct trapframe *framep)
 	userret(td, framep);
 	mtx_assert(&Giant, MA_NOTOWNED);
 }
+
+void
+syscallret(struct thread *td, int error, u_int sa_code __unused,
+    const char *scnames[] __unused)
+{
+	struct proc *p;
+	int traced;
+
+	p = td->td_proc;
+
+	/*
+	 * Check for misbehavior.
+	 */
+	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
+	    (sa_code >= 0 && sa_code < SYS_MAXSYSCALL) ?
+	     scnames[sa_code] : "???");
+	KASSERT(td->td_critnest == 0,
+	    ("System call %s returning in a critical section",
+	    (sa_code >= 0 && sa_code < SYS_MAXSYSCALL) ?
+	     scnames[sa_code] : "???"));
+	KASSERT(td->td_locks == 0,
+	    ("System call %s returning with %d locks held",
+	    (sa_code >= 0 && sa_code < SYS_MAXSYSCALL) ?
+	     scnames[sa_code] : "???", td->td_locks));
+
+	/*
+	 * Handle reschedule and other end-of-syscall issues
+	 */
+	userret(td, td->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
+
+	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);
+	}
+}
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/sys/proc.h b/sys/sys/proc.h
index e32e494..c2b9f4a 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,6 +840,7 @@ 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 *);
+void	syscallret(struct thread *, int, u_int, const char *[]);
 
 void	cpu_exit(struct thread *);
 void	exit1(struct thread *, int) __dead2;
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 */
 };
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20100514/1f1b8c08/attachment.pgp


More information about the freebsd-hackers mailing list