Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 17 Dec 2015 00:00:27 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r292388 - in head/sys: cddl/dev/dtrace cddl/dev/systrace kern sys
Message-ID:  <201512170000.tBH00RRT026326@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Thu Dec 17 00:00:27 2015
New Revision: 292388
URL: https://svnweb.freebsd.org/changeset/base/292388

Log:
  Support an arbitrary number of arguments to DTrace syscall probes.
  
  Rather than pushing all eight possible arguments into dtrace_probe()'s
  stack frame, make the syscall_args struct for the current syscall available
  via the current thread. Using a custom getargval method for the systrace
  provider, this allows any syscall argument to be fetched, even in kernels
  that have modified the maximum number of system call arguments.
  
  Sponsored by:	EMC / Isilon Storage Division

Modified:
  head/sys/cddl/dev/dtrace/dtrace_cddl.h
  head/sys/cddl/dev/systrace/systrace.c
  head/sys/kern/subr_syscall.c
  head/sys/sys/sysent.h

Modified: head/sys/cddl/dev/dtrace/dtrace_cddl.h
==============================================================================
--- head/sys/cddl/dev/dtrace/dtrace_cddl.h	Wed Dec 16 23:53:16 2015	(r292387)
+++ head/sys/cddl/dev/dtrace/dtrace_cddl.h	Thu Dec 17 00:00:27 2015	(r292388)
@@ -83,8 +83,8 @@ typedef struct kdtrace_thread {
 	uintptr_t	td_dtrace_regv;
 #endif
 	u_int64_t	td_hrtime;	/* Last time on cpu. */
-	int		td_errno;	/* Syscall return value. */
 	void		*td_dtrace_sscr; /* Saved scratch space location. */
+	void		*td_systrace_args; /* syscall probe arguments. */
 } kdtrace_thread_t;
 
 /*
@@ -110,6 +110,7 @@ typedef struct kdtrace_thread {
 #define	t_dtrace_astpc	td_dtrace->td_dtrace_astpc
 #define	t_dtrace_regv	td_dtrace->td_dtrace_regv
 #define	t_dtrace_sscr	td_dtrace->td_dtrace_sscr
+#define	t_dtrace_systrace_args	td_dtrace->td_systrace_args
 #define	p_dtrace_helpers	p_dtrace->p_dtrace_helpers
 #define	p_dtrace_count	p_dtrace->p_dtrace_count
 #define	p_dtrace_probes	p_dtrace->p_dtrace_probes

Modified: head/sys/cddl/dev/systrace/systrace.c
==============================================================================
--- head/sys/cddl/dev/systrace/systrace.c	Wed Dec 16 23:53:16 2015	(r292387)
+++ head/sys/cddl/dev/systrace/systrace.c	Thu Dec 17 00:00:27 2015	(r292388)
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/conf.h>
 #include <sys/cpuvar.h>
+#include <sys/dtrace.h>
 #include <sys/fcntl.h>
 #include <sys/filio.h>
 #include <sys/kdb.h>
@@ -53,9 +54,10 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysproto.h>
 #include <sys/uio.h>
 #include <sys/unistd.h>
-#include <machine/stdarg.h>
 
-#include <sys/dtrace.h>
+#include <cddl/dev/dtrace/dtrace_cddl.h>
+
+#include <machine/stdarg.h>
 
 #ifdef LINUX_SYSTRACE
 #if defined(__amd64__)
@@ -138,6 +140,7 @@ static void	systrace_unload(void *);
 
 static void	systrace_getargdesc(void *, dtrace_id_t, void *,
 		    dtrace_argdesc_t *);
+static uint64_t	systrace_getargval(void *, dtrace_id_t, void *, int, int);
 static void	systrace_provide(void *, dtrace_probedesc_t *);
 static void	systrace_destroy(void *, dtrace_id_t, void *);
 static void	systrace_enable(void *, dtrace_id_t, void *);
@@ -164,16 +167,13 @@ static dtrace_pops_t systrace_pops = {
 	NULL,
 	NULL,
 	systrace_getargdesc,
-	NULL,
+	systrace_getargval,
 	NULL,
 	systrace_destroy
 };
 
 static dtrace_provider_id_t	systrace_id;
 
-typedef void (*systrace_dtrace_probe_t)(dtrace_id_t, uintptr_t, uintptr_t,
-    uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
-
 #ifdef NATIVE_ABI
 /*
  * Probe callback function.
@@ -183,48 +183,48 @@ typedef void (*systrace_dtrace_probe_t)(
  *       compat syscall from something like Linux.
  */
 static void
-systrace_probe(uint32_t id, int sysnum, struct sysent *sysent, void *params,
-    int ret)
+systrace_probe(struct syscall_args *sa, enum systrace_probe_t type, int retval)
 {
-	uint64_t uargs[8];
-	systrace_dtrace_probe_t probe;
-	int n_args = 0;
+	uint64_t uargs[nitems(sa->args)];
+	dtrace_id_t id;
+	int n_args, sysnum;
 
+	sysnum = sa->code;
 	memset(uargs, 0, sizeof(uargs));
 
-	/*
-	 * Check if this syscall has an argument conversion function
-	 * registered.
-	 */
-	if (params != NULL && sysent->sy_systrace_args_func != NULL) {
-		/*
-		 * Convert the syscall parameters using the registered
-		 * function.
-		 */
-		(*sysent->sy_systrace_args_func)(sysnum, params, uargs,
-		    &n_args);
-	} else if (params != NULL) {
+	if (type == SYSTRACE_ENTRY) {
+		id = sa->callp->sy_entry;
+
+		if (sa->callp->sy_systrace_args_func != NULL)
+			/*
+			 * Convert the syscall parameters using the registered
+			 * function.
+			 */
+			(*sa->callp->sy_systrace_args_func)(sysnum, sa->args,
+			    uargs, &n_args);
+		else
+			/*
+			 * Use the built-in system call argument conversion
+			 * function to translate the syscall structure fields
+			 * into the array of 64-bit values that DTrace expects.
+			 */
+			systrace_args(sysnum, sa->args, uargs, &n_args);
 		/*
-		 * Use the built-in system call argument conversion
-		 * function to translate the syscall structure fields
-		 * into the array of 64-bit values that DTrace
-		 * expects.
+		 * Save probe arguments now so that we can retrieve them if
+		 * the getargval method is called from further down the stack.
 		 */
-		systrace_args(sysnum, params, uargs, &n_args);
+		curthread->t_dtrace_systrace_args = uargs;
 	} else {
-		/*
-		 * Since params is NULL, this is a 'return' probe.
-		 * Set arg0 and arg1 as the return value of this syscall.
-		 */
-		uargs[0] = uargs[1] = ret;
+		id = sa->callp->sy_return;
+
+		curthread->t_dtrace_systrace_args = NULL;
+		/* Set arg0 and arg1 as the return value of this syscall. */
+		uargs[0] = uargs[1] = retval;
 	}
 
 	/* Process the probe using the converted argments. */
-	probe = (systrace_dtrace_probe_t)dtrace_probe;
-	probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4], uargs[5],
-	    uargs[6], uargs[7]);
+	dtrace_probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]);
 }
-
 #endif
 
 static void
@@ -244,6 +244,21 @@ systrace_getargdesc(void *arg, dtrace_id
 		desc->dtargd_ndx = DTRACE_ARGNONE;
 }
 
+static uint64_t
+systrace_getargval(void *arg __unused, dtrace_id_t id __unused,
+    void *parg __unused, int argno, int aframes __unused)
+{
+	uint64_t *uargs;
+
+	uargs = curthread->t_dtrace_systrace_args;
+	if (uargs == NULL)
+		/* This is a return probe. */
+		return (0);
+	if (argno >= nitems(((struct syscall_args *)NULL)->args))
+		return (0);
+	return (uargs[argno]);
+}
+
 static void
 systrace_provide(void *arg, dtrace_probedesc_t *desc)
 {

Modified: head/sys/kern/subr_syscall.c
==============================================================================
--- head/sys/kern/subr_syscall.c	Wed Dec 16 23:53:16 2015	(r292387)
+++ head/sys/kern/subr_syscall.c	Thu Dec 17 00:00:27 2015	(r292388)
@@ -126,14 +126,9 @@ syscallenter(struct thread *td, struct s
 			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.
-		 */
+		/* Give the syscall:::entry DTrace probe a chance to fire. */
 		if (systrace_probe_func != NULL && sa->callp->sy_entry != 0)
-			(*systrace_probe_func)(sa->callp->sy_entry, sa->code,
-			    sa->callp, sa->args, 0);
+			(*systrace_probe_func)(sa, SYSTRACE_ENTRY, 0);
 #endif
 
 		AUDIT_SYSCALL_ENTER(sa->code, td);
@@ -145,14 +140,10 @@ syscallenter(struct thread *td, struct s
 			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.
-		 */
+		/* Give the syscall:::return DTrace probe a chance to fire. */
 		if (systrace_probe_func != NULL && sa->callp->sy_return != 0)
-			(*systrace_probe_func)(sa->callp->sy_return, sa->code,
-			    sa->callp, NULL, (error) ? -1 : td->td_retval[0]);
+			(*systrace_probe_func)(sa, SYSTRACE_RETURN,
+			    error ? -1 : td->td_retval[0]);
 #endif
 		syscall_thread_exit(td, sa->callp);
 	}

Modified: head/sys/sys/sysent.h
==============================================================================
--- head/sys/sys/sysent.h	Wed Dec 16 23:53:16 2015	(r292387)
+++ head/sys/sys/sysent.h	Thu Dec 17 00:00:27 2015	(r292388)
@@ -38,18 +38,18 @@ struct rlimit;
 struct sysent;
 struct thread;
 struct ksiginfo;
+struct syscall_args;
+
+enum systrace_probe_t {
+	SYSTRACE_ENTRY,
+	SYSTRACE_RETURN,
+};
 
 typedef	int	sy_call_t(struct thread *, void *);
 
-/* Used by the machine dependent syscall() code. */
-typedef	void (*systrace_probe_func_t)(u_int32_t, int, struct sysent *, void *,
-    int);
-
-/*
- * Used by loaded syscalls to convert arguments to a DTrace array
- * of 64-bit arguments.
- */
-typedef	void (*systrace_args_func_t)(int, void *, u_int64_t *, int *);
+typedef	void	(*systrace_probe_func_t)(struct syscall_args *,
+		    enum systrace_probe_t, int);
+typedef	void	(*systrace_args_func_t)(int, void *, uint64_t *, int *);
 
 extern systrace_probe_func_t	systrace_probe_func;
 
@@ -84,7 +84,6 @@ struct sysent {			/* system call table *
 
 struct image_params;
 struct __sigset;
-struct syscall_args;
 struct trapframe;
 struct vnode;
 



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