Skip to content

Commit

Permalink
cg: Implement dependent probes
Browse files Browse the repository at this point in the history
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@oracle.com>
Reviewed-by: Nick Alcock <nick.alcock@oracle.com>
  • Loading branch information
kvanhees committed Feb 27, 2023
1 parent c82c1bf commit 4d361cd
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 6 deletions.
2 changes: 2 additions & 0 deletions libdtrace/dt_cc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
46 changes: 46 additions & 0 deletions libdtrace/dt_cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,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)
{
Expand All @@ -593,6 +623,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 optimization:
* 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);
}

Expand Down
60 changes: 54 additions & 6 deletions libdtrace/dt_probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -1321,9 +1326,9 @@ dt_probe_error_clause(dtrace_hdl_t *dtp, dt_ident_t *idp)
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);

Expand All @@ -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);
Expand All @@ -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)
{
Expand Down
7 changes: 7 additions & 0 deletions libdtrace/dt_probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 4d361cd

Please sign in to comment.