[DTrace-devel] [PATCH 14/15] cg: Implement dependent probes

Kris Van Hees kris.van.hees at oracle.com
Thu Feb 23 07:24:19 UTC 2023


Some providers may wish to implement probes on top of other probes.
This patch provides the concept of dependent probes: probes that use
other probes as their firing mechanism.  This is accomplished by
generating a custom trampoline that converts the DTrace context of
the underlying probe into a DTrace context for the dependent probe
and then adding the clauses for the dependent probe to the underlying
probe.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_cc.c    |  2 ++
 libdtrace/dt_cg.c    | 46 +++++++++++++++++++++++++++++++++
 libdtrace/dt_probe.c | 60 +++++++++++++++++++++++++++++++++++++++-----
 libdtrace/dt_probe.h |  7 ++++++
 4 files changed, 109 insertions(+), 6 deletions(-)

diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index bbc203c3..88d7f1fe 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -2119,6 +2119,8 @@ dt_construct(dtrace_hdl_t *dtp, dt_probe_t *prp, uint_t cflags, dt_ident_t *idp)
 	pcb.pcb_probe = prp;
 	pcb.pcb_pdesc = prp->desc;
 
+	yybegin(YYS_DONE);
+
 	if ((err = setjmp(yypcb->pcb_jmpbuf)) != 0)
 		goto out;
 
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 4b619cc7..5837119d 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -499,6 +499,36 @@ dt_cg_tramp_call_clauses(dt_pcb_t *pcb, const dt_probe_t *prp,
 			     (dt_clause_f *)dt_cg_call_clause, &arg);
 }
 
+static int
+dt_cg_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg)
+{
+	dt_pcb_t	*pcb = dtp->dt_pcb;
+	dt_irlist_t	*dlp = &pcb->pcb_ir;
+	dt_ident_t	*idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
+	dt_probe_t	*saved_prp = pcb->pcb_probe;
+	uint_t		exitlbl = dt_irlist_label(dlp);
+
+	dt_cg_tramp_save_args(pcb);
+	pcb->pcb_probe = prp;
+	emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_7, DMST_PRID, prp->desc->id), idp);
+	if (prp->prov->impl->trampoline != NULL)
+		prp->prov->impl->trampoline(pcb, exitlbl);
+	dt_cg_tramp_call_clauses(pcb, prp, DT_ACTIVITY_ACTIVE);
+
+	pcb->pcb_probe = saved_prp;
+	dt_cg_tramp_restore_args(pcb);
+	emitl(dlp, exitlbl,
+		   BPF_NOP());
+
+	return 0;
+}
+
+static void
+dt_cg_tramp_add_dependents(dt_pcb_t *pcb, const dt_probe_t *prp)
+{
+	dt_probe_dependent_iter(pcb->pcb_hdl, prp, dt_cg_add_dependent, NULL);
+}
+
 void
 dt_cg_tramp_return(dt_pcb_t *pcb)
 {
@@ -519,6 +549,22 @@ void
 dt_cg_tramp_epilogue(dt_pcb_t *pcb)
 {
 	dt_cg_tramp_call_clauses(pcb, pcb->pcb_probe, DT_ACTIVITY_ACTIVE);
+	/*
+	 * For each dependent probe (if any):
+	 *	1.1 Call dt_cg_tramp_save_args()
+	 *	1.2 Set PRID to the probe ID of the dependent probe
+	 *	1.3 Call prp->prov->impl->trampoline()
+	 *		[ This will generate the pseudo-trampoline that sets
+	 *		  up the arguments for the dependent probe, possibly
+	 *		  based on the arguments of the underllying probe. ]
+	 *	1.4 Call dt_cg_tramp_call_clauses() for the dependent probe
+	 *	1.1 Call dt_cg_tramp_restore_args()
+	 *
+	 * Possible iptimization:
+	 *	Do not call dt_cg_tramp_restore_args() after the last dependent
+	 *	probe.
+	 */
+	dt_cg_tramp_add_dependents(pcb, pcb->pcb_probe);
 	dt_cg_tramp_return(pcb);
 }
 
diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
index e50fc7ba..a5952c57 100644
--- a/libdtrace/dt_probe.c
+++ b/libdtrace/dt_probe.c
@@ -24,10 +24,15 @@
 #include <dt_list.h>
 #include <dt_bpf.h>
 
-typedef struct dt_probeclause {
+typedef struct dt_probe_clause {
 	dt_list_t	list;
 	dt_ident_t	*clause;
-} dt_probeclause_t;
+} dt_probe_clause_t;
+
+typedef struct dt_probe_dependent {
+	dt_list_t	list;
+	dt_probe_t	*probe;
+} dt_probe_dependent_t;
 
 #define DEFINE_HE_FUNCS(id) \
 	static uint32_t id##_hval(const dt_probe_t *probe) \
@@ -462,7 +467,7 @@ dt_probe_enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
 void
 dt_probe_destroy(dt_probe_t *prp)
 {
-	dt_probeclause_t	*pcp, *pcp_next;
+	dt_probe_clause_t	*pcp, *pcp_next;
 	dt_probe_instance_t	*pip, *pip_next;
 	dtrace_hdl_t		*dtp;
 
@@ -1321,9 +1326,9 @@ no_mem:
 int
 dt_probe_add_clause(dtrace_hdl_t *dtp, dt_probe_t *prp, dt_ident_t *idp)
 {
-	dt_probeclause_t	*pcp;
+	dt_probe_clause_t	*pcp;
 
-	pcp = dt_zalloc(dtp, sizeof(dt_probeclause_t));;
+	pcp = dt_zalloc(dtp, sizeof(dt_probe_clause_t));;
 	if (pcp == NULL)
 		return dt_set_errno(dtp, EDT_NOMEM);
 
@@ -1345,7 +1350,7 @@ int
 dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
 		     dt_clause_f *func, void *arg)
 {
-	dt_probeclause_t	*pcp;
+	dt_probe_clause_t	*pcp;
 	int			rc;
 
 	assert(func != NULL);
@@ -1361,6 +1366,49 @@ dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
 	return 0;
 }
 
+int
+dt_probe_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp, dt_probe_t *dprp)
+{
+	dt_probe_dependent_t	*pdp;
+
+	/* Ignore dependent probes already in the list. */
+	for (pdp = dt_list_next(&prp->dependents); pdp != NULL;
+	     pdp = dt_list_next(pdp)) {
+		if (pdp->probe == dprp)
+			return 0;
+	}
+
+	pdp = dt_zalloc(dtp, sizeof(dt_probe_dependent_t));;
+	if (pdp == NULL)
+		return dt_set_errno(dtp, EDT_NOMEM);
+
+	pdp->probe = dprp;
+
+	dt_list_append(&prp->dependents, pdp);
+
+	return 0;
+}
+
+int
+dt_probe_dependent_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+			dt_dependent_f *func, void *arg)
+{
+	dt_probe_dependent_t	*pdp;
+	int			rc;
+
+	assert(func != NULL);
+
+	for (pdp = dt_list_next(&prp->dependents); pdp != NULL;
+	     pdp = dt_list_next(pdp)) {
+		rc = func(dtp, pdp->probe, arg);
+
+		if (rc != 0)
+			return rc;
+	}
+
+	return 0;
+}
+
 void
 dt_probe_init(dtrace_hdl_t *dtp)
 {
diff --git a/libdtrace/dt_probe.h b/libdtrace/dt_probe.h
index 6464af55..4b9396a7 100644
--- a/libdtrace/dt_probe.h
+++ b/libdtrace/dt_probe.h
@@ -33,6 +33,7 @@ typedef struct dt_probe_instance {
 typedef struct dt_probe {
 	dt_list_t list;			/* prev/next in enablings chain */
 	dt_list_t clauses;		/* clauses to attach */
+	dt_list_t dependents;		/* dependenct probes to attach */
 	const dtrace_probedesc_t *desc;	/* probe description (id, name) */
 	dt_provider_t *prov;		/* pointer to containing provider */
 	struct dt_hentry he_prv;	/* provider name htab links */
@@ -90,6 +91,12 @@ typedef int dt_clause_f(dtrace_hdl_t *dtp, dt_ident_t *idp, void *arg);
 extern int dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
 				dt_clause_f *func, void *arg);
 
+extern int dt_probe_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp,
+				  dt_probe_t *idprp);
+typedef int dt_dependent_f(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg);
+extern int dt_probe_dependent_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+				   dt_dependent_f *func, void *arg);
+
 
 extern void dt_probe_init(dtrace_hdl_t *dtp);
 extern void dt_probe_detach(dtrace_hdl_t *dtp);
-- 
2.39.1




More information about the DTrace-devel mailing list