[RFC] DTrace SYSCALL provider (was Re: [RFC] Saving the latest errno from syscalls.)

Jung-uk Kim jkim at FreeBSD.org
Mon Mar 15 18:10:54 UTC 2010


On Friday 12 March 2010 01:32 pm, Jung-uk Kim wrote:
> On Friday 12 March 2010 04:29 am, Kostik Belousov wrote:
> > On Thu, Mar 11, 2010 at 06:15:07PM -0500, Jung-uk Kim wrote:
> > > On Thursday 11 March 2010 04:55 pm, Marcel Moolenaar wrote:
> > > > On Mar 11, 2010, at 1:24 PM, Jung-uk Kim wrote:
> > > > > While I was debugging syscalls, I found a very useful field
> > > > > in struct thread, td_errno.  It seems it was added for
> > > > > dtrace but it is only populated on amd64 and i386.  Is the
> > > > > attached patch acceptable for maintainers of other
> > > > > platforms?
> > > >
> > > > Isn't it better to do it in cpu_set_syscall_retval()?
> > > > That way you catch all cases, plus you can save the
> > > > translated error as well...
> > >
> > > I just took amd64/i386 as an example and I was not sure whether
> > > it was meant to store translated error or not.  Does anyone
> > > with DTrace internal knowledge answer the question?
> >
> > I do not know that much about DTrace, but it seems that setting
> > td_errno in cpu_set_syscall_retval() is too late. Dtrace has a
> > probe after the syscall return, and it is called right before
> > cpu_set_syscall_retval() can be reasonably called. The probe only
> > issued for syscall that goes into sysent.
>
> Ah, I can see that now.  So, if/when we implement DTrace SYSCALL
> provider for other arches, this is the right place. :-)

I went ahead and implemented DTrace SYSCALL providers for non-x86 
arches.  It passes 'make universe' test but I don't know if it works.  
Can maintainers of other arches test or review the attached patch?

Thanks!

Jung-uk Kim
-------------- next part --------------
Index: sys/arm/arm/trap.c
===================================================================
--- sys/arm/arm/trap.c	(revision 205172)
+++ sys/arm/arm/trap.c	(working copy)
@@ -122,7 +122,18 @@ __FBSDID("$FreeBSD$");
 #include <sys/kdb.h>
 #endif
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
 
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+#endif
+
+
 void swi_handler(trapframe_t *);
 void undefinedinstruction(trapframe_t *);
 
@@ -925,9 +936,36 @@ syscall(struct thread *td, trapframe_t *frame, u_i
 		td->td_retval[1] = 0;
 		STOPEVENT(p, S_SCE, callp->sy_narg);
 		PTRACESTOP_SC(p, td, S_PT_SCE);
+
+#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(code, td);
 		error = (*callp->sy_call)(td, 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
+
 		KASSERT(td->td_ar == NULL, 
 		    ("returning from syscall with td_ar set!"));
 	}
Index: sys/powerpc/booke/trap.c
===================================================================
--- sys/powerpc/booke/trap.c	(revision 205172)
+++ sys/powerpc/booke/trap.c	(working copy)
@@ -75,6 +75,17 @@ __FBSDID("$FreeBSD$");
 #include <machine/trap.h>
 #include <machine/spr.h>
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+#endif
+
 #ifdef FPU_EMU
 #include <powerpc/fpu/fpu_extern.h>
 #endif
@@ -409,10 +420,35 @@ syscall(struct trapframe *frame)
 
 		PTRACESTOP_SC(p, td, S_PT_SCE);
 
+#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(code, td);
 		error = (*callp->sy_call)(td, params);
 		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
+
 		CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", p->p_comm,
 		     syscallnames[code], td->td_retval[0]);
 	}
Index: sys/powerpc/aim/trap.c
===================================================================
--- sys/powerpc/aim/trap.c	(revision 205172)
+++ sys/powerpc/aim/trap.c	(working copy)
@@ -77,6 +77,17 @@ __FBSDID("$FreeBSD$");
 #include <machine/spr.h>
 #include <machine/sr.h>
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+#endif
+
 static void	trap_fatal(struct trapframe *frame);
 static void	printtrap(u_int vector, struct trapframe *frame, int isfatal,
 		    int user);
@@ -405,10 +416,35 @@ syscall(struct trapframe *frame)
 
 		PTRACESTOP_SC(p, td, S_PT_SCE);
 
+#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(code, td);
 		error = (*callp->sy_call)(td, params);
 		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
+
 		CTR3(KTR_SYSC, "syscall: p=%s %s ret=%x", td->td_name,
 		     syscallnames[code], td->td_retval[0]);
 	}
Index: sys/sparc64/sparc64/trap.c
===================================================================
--- sys/sparc64/sparc64/trap.c	(revision 205172)
+++ sys/sparc64/sparc64/trap.c	(working copy)
@@ -94,6 +94,17 @@ __FBSDID("$FreeBSD$");
 #include <machine/tsb.h>
 #include <machine/watch.h>
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+#endif
+
 struct syscall_args {
 	u_long code;
 	struct sysent *callp;
@@ -648,10 +659,35 @@ syscall(struct trapframe *tf)
 			td->td_retval[1] = 0;
 		}
 
+#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
+
 		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]);
Index: sys/ia64/ia64/trap.c
===================================================================
--- sys/ia64/ia64/trap.c	(revision 205172)
+++ sys/ia64/ia64/trap.c	(working copy)
@@ -76,6 +76,17 @@ __FBSDID("$FreeBSD$");
 
 #include <ia64/disasm/disasm.h>
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+#endif
+
 static int print_usertrap = 0;
 SYSCTL_INT(_machdep, OID_AUTO, print_usertrap,
     CTLFLAG_RW, &print_usertrap, 0, "");
@@ -970,10 +981,35 @@ syscall(struct trapframe *tf)
 
 	PTRACESTOP_SC(p, td, S_PT_SCE);
 
+#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(code, td);
 	error = (*callp->sy_call)(td, 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
+
 	cpu_set_syscall_retval(td, error);
 	td->td_syscalls++;
 
Index: sys/ia64/ia32/ia32_trap.c
===================================================================
--- sys/ia64/ia32/ia32_trap.c	(revision 205172)
+++ sys/ia64/ia32/ia32_trap.c	(working copy)
@@ -48,6 +48,17 @@ __FBSDID("$FreeBSD$");
 
 #include <security/audit/audit.h>
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+#endif
+
 extern char *syscallnames[];
 
 static void
@@ -124,9 +135,34 @@ ia32_syscall(struct trapframe *tf)
 
 		PTRACESTOP_SC(p, td, S_PT_SCE);
 
+#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(code, td);
 		error = (*callp->sy_call)(td, args64);
 		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
 	}
 
 	switch (error) {
Index: sys/sun4v/sun4v/trap.c
===================================================================
--- sys/sun4v/sun4v/trap.c	(revision 205172)
+++ sys/sun4v/sun4v/trap.c	(working copy)
@@ -96,6 +96,17 @@
 
 #include <security/audit/audit.h>
 
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * This is a hook which is initialised by the systrace module
+ * when it is loaded. This keeps the DTrace syscall provider
+ * implementation opaque. 
+ */
+systrace_probe_func_t	systrace_probe_func;
+#endif
+
 void trap(struct trapframe *tf, int64_t type, uint64_t data);
 void syscall(struct trapframe *tf);
 
@@ -662,10 +673,35 @@ syscall(struct trapframe *tf)
 
 		PTRACESTOP_SC(p, td, S_PT_SCE);
 
+#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(code, td);
 		error = (*callp->sy_call)(td, 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
+
 		CTR5(KTR_SYSC, "syscall: p=%p error=%d %s return %#lx %#lx ", p,
 		    error, syscallnames[code], td->td_retval[0],
 		    td->td_retval[1]);


More information about the freebsd-hackers mailing list