From bdd101c4d4aeab6c9e76250c310c16f5704b8b8c Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 4 Oct 2022 12:54:36 -0400 Subject: [PATCH] dtrace: Add a "regs" variable This allows invop-based providers (i.e., fbt and kinst) to expose the register file of the CPU at the point where the probe fired. It does not work for SDT providers because their probes are implemented as plain function calls and so don't save registers. It's not clear what semantics "regs" should have for them anyway. This is akin to "uregs", which nominally provides access to the userspace registers. In fact, DIF already had a DIF_VAR_REGS variable defined, it was simply unimplemented. Usage example: print the contents of %rdi upon each call to amd64_syscall(): fbt::amd64_syscall:entry {printf("%x", regs[R_RDI]);} Note that the R_* constants are defined in /usr/lib/dtrace/regs_x86.d. Currently there are no similar definitions for non-x86 platforms. Reviewed by: christos MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D36799 --- .../lib/libdtrace/common/dt_open.c | 2 ++ .../opensolaris/uts/common/dtrace/dtrace.c | 26 +++++-------------- sys/cddl/dev/dtrace/aarch64/dtrace_subr.c | 17 ++++++------ sys/cddl/dev/dtrace/amd64/dtrace_subr.c | 12 ++++++--- sys/cddl/dev/dtrace/arm/dtrace_subr.c | 16 +++++++----- sys/cddl/dev/dtrace/dtrace_cddl.h | 2 ++ sys/cddl/dev/dtrace/i386/dtrace_subr.c | 13 +++++++--- sys/cddl/dev/dtrace/powerpc/dtrace_subr.c | 16 +++++++----- sys/cddl/dev/dtrace/riscv/dtrace_subr.c | 16 +++++++----- 9 files changed, 65 insertions(+), 55 deletions(-) diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index f55d488f4d91..9621a0fcb391 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -416,6 +416,8 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_func, "void(int)" }, { "rand", DT_IDENT_FUNC, 0, DIF_SUBR_RAND, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int()" }, +{ "regs", DT_IDENT_ARRAY, 0, DIF_VAR_REGS, DT_ATTR_STABCMN, DT_VERS_1_13, + &dt_idops_regs, NULL }, { "rindex", DT_IDENT_FUNC, 0, DIF_SUBR_RINDEX, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "int(const char *, const char *, [int])" }, #ifdef illumos diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 0ef05717b904..44a85db65117 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -3360,30 +3360,19 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, return (mstate->dtms_arg[ndx]); -#ifdef illumos - case DIF_VAR_UREGS: { - klwp_t *lwp; - - if (!dtrace_priv_proc(state)) - return (0); - - if ((lwp = curthread->t_lwp) == NULL) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); - cpu_core[curcpu].cpuc_dtrace_illval = NULL; - return (0); - } - - return (dtrace_getreg(lwp->lwp_regs, ndx)); - return (0); - } -#else + case DIF_VAR_REGS: case DIF_VAR_UREGS: { struct trapframe *tframe; if (!dtrace_priv_proc(state)) return (0); - if ((tframe = curthread->td_frame) == NULL) { + if (v == DIF_VAR_REGS) + tframe = curthread->t_dtrace_trapframe; + else + tframe = curthread->td_frame; + + if (tframe == NULL) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = 0; return (0); @@ -3391,7 +3380,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, return (dtrace_getreg(tframe, ndx)); } -#endif case DIF_VAR_CURTHREAD: if (!dtrace_priv_proc(state)) diff --git a/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c index 74b3bf7ed7d1..694e3c70ae2d 100644 --- a/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/aarch64/dtrace_subr.c @@ -27,18 +27,16 @@ * Use is subject to license terms. */ -#include -__FBSDID("$FreeBSD$"); - #include #include -#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -65,17 +63,20 @@ dtrace_invop_hdlr_t *dtrace_invop_hdlr; int dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax) { + struct thread *td; dtrace_invop_hdlr_t *hdlr; int rval; + rval = 0; + td = curthread; + td->t_dtrace_trapframe = frame; for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0) - return (rval); - - return (0); + break; + td->t_dtrace_trapframe = NULL; + return (rval); } - void dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) { diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c index f4fb70f80a6b..2521afc7b443 100644 --- a/sys/cddl/dev/dtrace/amd64/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/amd64/dtrace_subr.c @@ -33,12 +33,13 @@ #include #include -#include #include #include +#include #include #include #include +#include #include #include #include @@ -65,15 +66,20 @@ dtrace_invop_hdlr_t *dtrace_invop_hdlr; int dtrace_invop(uintptr_t addr, struct trapframe *frame, void **scratch) { + struct thread *td; dtrace_invop_hdlr_t *hdlr; int rval; + td = curthread; + td->t_dtrace_trapframe = frame; + rval = 0; for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) { rval = hdlr->dtih_func(addr, frame, (uintptr_t)scratch); if (rval != 0) - return (rval); + break; } - return (0); + td->t_dtrace_trapframe = NULL; + return (rval); } void diff --git a/sys/cddl/dev/dtrace/arm/dtrace_subr.c b/sys/cddl/dev/dtrace/arm/dtrace_subr.c index 367d8d75eea4..d39bc8a54288 100644 --- a/sys/cddl/dev/dtrace/arm/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/arm/dtrace_subr.c @@ -27,18 +27,16 @@ * Use is subject to license terms. */ -#include -__FBSDID("$FreeBSD$"); - #include #include -#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -70,14 +68,18 @@ dtrace_invop_hdlr_t *dtrace_invop_hdlr; int dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax) { + struct thread *td; dtrace_invop_hdlr_t *hdlr; int rval; + rval = 0; + td = curthread; + td->t_dtrace_trapframe = frame; for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0) - return (rval); - - return (0); + break; + td->t_dtrace_trapframe = NULL; + return (rval); } diff --git a/sys/cddl/dev/dtrace/dtrace_cddl.h b/sys/cddl/dev/dtrace/dtrace_cddl.h index dd62af632e79..08b6f80d4bae 100644 --- a/sys/cddl/dev/dtrace/dtrace_cddl.h +++ b/sys/cddl/dev/dtrace/dtrace_cddl.h @@ -87,6 +87,7 @@ typedef struct kdtrace_thread { void *td_dtrace_sscr; /* Saved scratch space location. */ void *td_systrace_args; /* syscall probe arguments. */ uint64_t td_fasttrap_tp_gen; /* Tracepoint hash table gen. */ + struct trapframe *td_dtrace_trapframe; /* Trap frame from invop. */ } kdtrace_thread_t; /* @@ -115,6 +116,7 @@ typedef struct kdtrace_thread { #define t_dtrace_sscr td_dtrace->td_dtrace_sscr #define t_dtrace_systrace_args td_dtrace->td_systrace_args #define t_fasttrap_tp_gen td_dtrace->td_fasttrap_tp_gen +#define t_dtrace_trapframe td_dtrace->td_dtrace_trapframe #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 diff --git a/sys/cddl/dev/dtrace/i386/dtrace_subr.c b/sys/cddl/dev/dtrace/i386/dtrace_subr.c index 37cc7601bef5..69a07e8ee968 100644 --- a/sys/cddl/dev/dtrace/i386/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/i386/dtrace_subr.c @@ -33,14 +33,15 @@ #include #include -#include #include #include #include #include +#include #include #include #include +#include #include #include #include @@ -68,14 +69,18 @@ dtrace_invop_hdlr_t *dtrace_invop_hdlr; int dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t eax) { + struct thread *td; dtrace_invop_hdlr_t *hdlr; int rval; + rval = 0; + td = curthread; + td->t_dtrace_trapframe = frame; for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) if ((rval = hdlr->dtih_func(addr, frame, eax)) != 0) - return (rval); - - return (0); + break; + td->t_dtrace_trapframe = NULL; + return (rval); } void diff --git a/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c b/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c index 0707a40aa22e..7a19a0b6caec 100644 --- a/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/powerpc/dtrace_subr.c @@ -27,18 +27,16 @@ * Use is subject to license terms. */ -#include -__FBSDID("$FreeBSD$"); - #include #include -#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -65,14 +63,18 @@ dtrace_invop_hdlr_t *dtrace_invop_hdlr; int dtrace_invop(uintptr_t addr, struct trapframe *frame, uintptr_t arg0) { + struct thread *td; dtrace_invop_hdlr_t *hdlr; int rval; + rval = 0; + td = curthread; + td->t_dtrace_trapframe = frame; for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) if ((rval = hdlr->dtih_func(addr, frame, arg0)) != 0) - return (rval); - - return (0); + break; + td->t_dtrace_trapframe = NULL; + return (rval); } void diff --git a/sys/cddl/dev/dtrace/riscv/dtrace_subr.c b/sys/cddl/dev/dtrace/riscv/dtrace_subr.c index 964be9571098..1e24a88f6c75 100644 --- a/sys/cddl/dev/dtrace/riscv/dtrace_subr.c +++ b/sys/cddl/dev/dtrace/riscv/dtrace_subr.c @@ -29,18 +29,16 @@ * Use is subject to license terms. */ -#include -__FBSDID("$FreeBSD$"); - #include #include -#include #include #include #include +#include #include #include #include +#include #include #include #include @@ -68,14 +66,18 @@ dtrace_invop_hdlr_t *dtrace_invop_hdlr; int dtrace_invop(uintptr_t addr, struct trapframe *frame) { + struct thread *td; dtrace_invop_hdlr_t *hdlr; int rval; + rval = 0; + td = curthread; + td->t_dtrace_trapframe = frame; for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) if ((rval = hdlr->dtih_func(addr, frame, 0)) != 0) - return (rval); - - return (0); + break; + td->t_dtrace_trapframe = NULL; + return (rval); } void