Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 May 2010 15:57:31 +0300
From:      Kostik Belousov <kostikbel@gmail.com>
To:        John Baldwin <jhb@freebsd.org>
Cc:        Ali Polatel <alip@exherbo.org>, freebsd-hackers@freebsd.org
Subject:   Re: Ability to tell the difference between normal and syscall traps
Message-ID:  <20100514125731.GP83316@deviant.kiev.zoral.com.ua>
In-Reply-To: <4BED2B27.2020902@FreeBSD.org>
References:  <20100508111509.GB8186@harikalardiyari> <20100508123626.GC83316@deviant.kiev.zoral.com.ua> <20100509053303.GD8186@harikalardiyari> <20100509135807.GH83316@deviant.kiev.zoral.com.ua> <20100509182851.GE8186@harikalardiyari> <20100509214359.GJ83316@deviant.kiev.zoral.com.ua> <20100510164847.GF8186@harikalardiyari> <20100510170947.GP83316@deviant.kiev.zoral.com.ua> <20100511103500.GH8186@harikalardiyari> <4BED2B27.2020902@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--9rkt7tfZQigMla7f
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

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.
>=20
> I agree that this would be cleaner.  Having worked on the ptrace/procfs=
=20
> stuff in other tools like strace and truss, exec truly is an important=20
> event to a debugger aside from just being another system call as it=20
> 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 =3D 0;
 SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW,
 	&prot_fault_translation, 0, "Select signal to deliver on protection fault=
");
=20
-extern char *syscallnames[];
+extern const char *syscallnames[];
=20
 /*
  * 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;
=20
 	PCPU_INC(cnt.v_syscall);
@@ -905,10 +905,13 @@ syscall(struct trapframe *frame)
 		cred_update_thread(td);
 	orig_tf_rflags =3D frame->tf_rflags;
 	if (p->p_flag & P_TRACED) {
+		traced =3D 1;
 		PROC_LOCK(p);
 		td->td_dbgflags &=3D ~TDB_USERWR;
+		td->td_dbgflags |=3D TDB_SCE;
 		PROC_UNLOCK(p);
-	}
+	} else
+		traced =3D 0;
 	error =3D fetch_syscall_args(td, &sa);
=20
 	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 &=3D ~TDB_SCE;
+		PROC_UNLOCK(p);
+	}
 	cpu_set_syscall_retval(td, error);
=20
 	/*
@@ -975,40 +983,5 @@ syscall(struct trapframe *frame)
 		trapsignal(td, &ksi);
 	}
=20
-	/*
-	 * Check for misbehavior.
-	 */
-	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
-	    (sa.code >=3D 0 && sa.code < SYS_MAXSYSCALL) ?
-	     syscallnames[sa.code] : "???");
-	KASSERT(td->td_critnest =3D=3D 0,
-	    ("System call %s returning in a critical section",
-	    (sa.code >=3D 0 && sa.code < SYS_MAXSYSCALL) ?
-	     syscallnames[sa.code] : "???"));
-	KASSERT(td->td_locks =3D=3D 0,
-	    ("System call %s returning with %d locks held",
-	    (sa.code >=3D 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;
=20
 	PCPU_INC(cnt.v_syscall);
@@ -184,10 +184,13 @@ ia32_syscall(struct trapframe *frame)
 		cred_update_thread(td);
 	orig_tf_rflags =3D frame->tf_rflags;
 	if (p->p_flag & P_TRACED) {
+		traced =3D 1;
 		PROC_LOCK(p);
 		td->td_dbgflags &=3D ~TDB_USERWR;
+		td->td_dbgflags |=3D TDB_SCE;
 		PROC_UNLOCK(p);
-	}
+	} else
+		traced =3D 0;
 	error =3D fetch_ia32_syscall_args(td, &sa);
=20
 	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 =3D error;
 	}
  retval:
+	if (traced) {
+		PROC_LOCK(p);
+		td->td_dbgflags &=3D ~TDB_SCE;
+		PROC_UNLOCK(p);
+	}
 	cpu_set_syscall_retval(td, error);
=20
 	/*
@@ -232,44 +240,9 @@ ia32_syscall(struct trapframe *frame)
 		trapsignal(td, &ksi);
 	}
=20
-	/*
-	 * Check for misbehavior.
-	 */
-	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
-	    (sa.code >=3D 0 && sa.code < SYS_MAXSYSCALL) ?
-	     freebsd32_syscallnames[sa.code] : "???");
-	KASSERT(td->td_critnest =3D=3D 0,
-	    ("System call %s returning in a critical section",
-	    (sa.code >=3D 0 && sa.code < SYS_MAXSYSCALL) ?
-	     freebsd32_syscallnames[sa.code] : "???"));
-	KASSERT(td->td_locks =3D=3D 0,
-	    ("System call %s returning with %d locks held",
-	    (sa.code >=3D 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);
-=20
-	PTRACESTOP_SC(p, td, S_PT_SCX);
+	syscallret(td, error, sa.code, freebsd32_syscallnames);
 }
=20
-
 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 =3D 0;
 SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW,
 	&prot_fault_translation, 0, "Select signal to deliver on protection fault=
");
=20
-extern char *syscallnames[];
+extern const char *syscallnames[];
=20
 /*
  * 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;
=20
 	PCPU_INC(cnt.v_syscall);
@@ -1072,10 +1072,13 @@ syscall(struct trapframe *frame)
 		cred_update_thread(td);
 	orig_tf_eflags =3D frame->tf_eflags;
 	if (p->p_flag & P_TRACED) {
+		traced =3D 1;
 		PROC_LOCK(p);
 		td->td_dbgflags &=3D ~TDB_USERWR;
+		td->td_dbgflags |=3D TDB_SCE;
 		PROC_UNLOCK(p);
-	}
+	} else
+		traced =3D 0;
 	error =3D fetch_syscall_args(td, &sa);
=20
 	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 &=3D ~TDB_SCE;
+		PROC_UNLOCK(p);
+	}
 	cpu_set_syscall_retval(td, error);
=20
 	/*
@@ -1142,41 +1150,6 @@ syscall(struct trapframe *frame)
 		trapsignal(td, &ksi);
 	}
=20
-	/*
-	 * Check for misbehavior.
-	 */
-	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
-	    (sa.code >=3D 0 && sa.code < SYS_MAXSYSCALL) ?
-	     syscallnames[sa.code] : "???");
-	KASSERT(td->td_critnest =3D=3D 0,
-	    ("System call %s returning in a critical section",
-	    (sa.code >=3D 0 && sa.code < SYS_MAXSYSCALL) ?
-	     syscallnames[sa.code] : "???"));
-	KASSERT(td->td_locks =3D=3D 0,
-	    ("System call %s returning with %d locks held",
-	    (sa.code >=3D 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);
 }
=20
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);
=20
 	if (error =3D=3D 0) {
+		PROC_LOCK(p);
+		td->td_dbgflags |=3D 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 =3D td->td_proc;
+
+	/*
+	 * Check for misbehavior.
+	 */
+	WITNESS_WARN(WARN_PANIC, NULL, "System call %s returning",
+	    (sa_code >=3D 0 && sa_code < SYS_MAXSYSCALL) ?
+	     scnames[sa_code] : "???");
+	KASSERT(td->td_critnest =3D=3D 0,
+	    ("System call %s returning in a critical section",
+	    (sa_code >=3D 0 && sa_code < SYS_MAXSYSCALL) ?
+	     scnames[sa_code] : "???"));
+	KASSERT(td->td_locks =3D=3D 0,
+	    ("System call %s returning with %d locks held",
+	    (sa_code >=3D 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 =3D 1;
+		PROC_LOCK(p);
+		td->td_dbgflags |=3D TDB_SCX;
+		PROC_UNLOCK(p);
+	} else
+		traced =3D 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) !=3D 0) {
+		PROC_LOCK(p);
+		td->td_dbgflags &=3D ~(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, v=
oid *addr, int data)
 		pl->pl_lwpid =3D td2->td_tid;
 		if (td2->td_dbgflags & TDB_XSIG)
 			pl->pl_event =3D PL_EVENT_SIGNAL;
-		else
-			pl->pl_event =3D 0;
 		pl->pl_flags =3D 0;
+		if (td2->td_dbgflags & TDB_SCE)
+			pl->pl_flags |=3D PL_FLAG_SCE;
+		else if (td2->td_dbgflags & TDB_SCX)
+			pl->pl_flags |=3D PL_FLAG_SCX;
+		if (td2->td_dbgflags & TDB_EXEC)
+			pl->pl_flags |=3D PL_FLAG_EXEC;
 		pl->pl_sigmask =3D td2->td_sigmask;
 		pl->pl_siglist =3D 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 */
=20
 /*
  * "Private" flags kept in td_pflags:
@@ -837,6 +840,7 @@ void	cpu_switch(struct thread *, struct thread *, struc=
t 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 *[]);
=20
 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 */
 };

--9rkt7tfZQigMla7f
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (FreeBSD)

iEYEARECAAYFAkvtSLoACgkQC3+MBN1Mb4iVmgCgzRauK+Y3x7gaHKyV262osh3Z
3D4AoMtpanSlq/21vCDALp0zc+zWABGv
=EuVN
-----END PGP SIGNATURE-----

--9rkt7tfZQigMla7f--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100514125731.GP83316>