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;
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to