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
This commit is contained in:
parent
f17f88d3e0
commit
8ff6d9dd22
@ -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
|
||||
|
@ -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)(dtrace_id_t, uintptr_t, uintptr_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) {
|
||||
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);
|
||||
/*
|
||||
* Convert the syscall parameters using the registered
|
||||
* function.
|
||||
* Save probe arguments now so that we can retrieve them if
|
||||
* the getargval method is called from further down the stack.
|
||||
*/
|
||||
(*sysent->sy_systrace_args_func)(sysnum, params, uargs,
|
||||
&n_args);
|
||||
} else if (params != NULL) {
|
||||
/*
|
||||
* 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, 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_t id, void *parg,
|
||||
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)
|
||||
{
|
||||
|
@ -126,14 +126,9 @@ syscallenter(struct thread *td, struct syscall_args *sa)
|
||||
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 syscall_args *sa)
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user