From: eugene.loh@oracle.com
To: dtrace@lists.linux.dev, dtrace-devel@oss.oracle.com
Subject: [PATCH v2 35/38] Use uprobes map to call clauses conditionally
Date: Thu, 27 Jun 2024 22:03:14 -0400 [thread overview]
Message-ID: <20240628020316.32544-4-eugene.loh@oracle.com> (raw)
In-Reply-To: <20240628020316.32544-1-eugene.loh@oracle.com>
From: Eugene Loh <eugene.loh@oracle.com>
This version supports only up to 64 clauses for an underlying
probe, but it can be extended to more clauses.
This version also does not work when two overlying probes that
differ in more than just pid map to the same underlying probe.
For example, a pid$pid:::offset probe could map to the same
underlying probe as a usdt$pid::: probe. In the current scheme,
only the "first" overlying probe would fire.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_uprobe.c | 151 +++++++++++++++++++------------------
1 file changed, 77 insertions(+), 74 deletions(-)
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index e99f02c3..38974609 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -517,8 +517,11 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
dt_irlist_t *dlp = &pcb->pcb_ir;
const dt_probe_t *uprp = pcb->pcb_probe;
const dt_uprobe_t *upp = uprp->prv_data;
- const list_probe_t *pop;
uint_t lbl_exit = pcb->pcb_exitlbl;
+ dt_ident_t *uprobes = dt_dlib_get_map(pcb->pcb_hdl, "uprobes");
+ dt_probe_clause_t *pcp;
+
+ assert(uprobes != NULL);
dt_cg_tramp_prologue(pcb);
@@ -527,7 +530,6 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
* // (%r7 = dctx->mst)
* // (%r8 = dctx->ctx)
*/
-
dt_cg_tramp_copy_regs(pcb);
if (upp->flags & PP_IS_RETURN)
dt_cg_tramp_copy_rval_from_regs(pcb);
@@ -542,47 +544,66 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
/*
- * Generate a composite conditional clause:
+ * Look up in the BPF uprobes map. Space for the look-up key will be used
+ * on the BPF stack:
*
- * if (pid == PID1) {
- * dctx->mst->prid = PRID1;
- * < any number of clause calls >
- * goto exit;
- * } else if (pid == PID2) {
- * dctx->mst->prid = PRID2;
- * < any number of clause calls >
- * goto exit;
- * } else if (pid == ...) {
- * < ... >
- * }
+ * offset value
*
- * It is valid and safe to use %r0 to hold the pid value because there
- * are no assignments to %r0 possible in between the conditional
- * statements.
+ * -sizeof(uprobe_map_key_t) pid (in %r0)
+ *
+ * -sizeof(uprobe_map_key_t) + sizeof(pid_t)
+ * ==
+ * -sizeof(dtrace_id_t) underlying-probe prid
*/
- for (pop = dt_list_next(&upp->probes); pop != NULL;
- pop = dt_list_next(pop)) {
- const dt_probe_t *prp = pop->probe;
- uint_t lbl_next = dt_irlist_label(dlp);
- pid_t pid;
- dt_ident_t *idp;
+ emit(dlp, BPF_STORE(BPF_W, BPF_REG_9, (int)(-sizeof(uprobe_map_key_t)), BPF_REG_0));
+ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, (int)(-sizeof(dtrace_id_t)), uprp->desc->id));
+ dt_cg_xsetx(dlp, uprobes, DT_LBL_NONE, BPF_REG_1, uprobes->di_id);
+ emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_9));
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, (int)(-sizeof(uprobe_map_key_t))));
+ emit(dlp, BPF_CALL_HELPER(BPF_FUNC_map_lookup_elem));
+ emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_exit));
- pid = dt_pid_get_pid(prp->desc, pcb->pcb_hdl, pcb, NULL);
- assert(pid != -1);
+ /* Read the PRID from the table lookup and store to mst->prid. */
+ emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_0, 0));
+ emit(dlp, BPF_STORE(BPF_W, BPF_REG_7, DMST_PRID, BPF_REG_1));
+
+ /* Read the bit mask from the table lookup in %r6. */ // FIXME someday, extend this past 64 bits
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_0, offsetof(uprobe_map_val_t, mask)));
+
+ /*
+ * Hold the bit mask in %r6 between clause calls.
+ */
+ for (pcp = dt_list_next(&uprp->clauses); pcp; pcp = dt_list_next(pcp)) {
+ dt_ident_t *idp = pcp->clause;
+ uint_t lbl_next = dt_irlist_label(dlp);
- idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
- assert(idp != NULL);
+ /* If the lowest %r6 bit is 0, skip over this clause. */
+ emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_6));
+ emit(dlp, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 1));
+ emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_1, 0, lbl_next));
/*
- * Check whether this pid-provider probe serves the current
- * process, and emit a sequence of clauses for it when it does.
+ * if (*dctx.act != act) // ldw %r0, [%r9 + DCTX_ACT]
+ * goto exit; // ldw %r0, [%r0 + 0]
+ * // jne %r0, act, lbl_exit
*/
- emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, pid, lbl_next));
- emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_7, DMST_PRID, prp->desc->id), idp);
- dt_cg_tramp_call_clauses(pcb, prp, DT_ACTIVITY_ACTIVE);
- emit(dlp, BPF_JUMP(lbl_exit));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_9, DCTX_ACT));
+ emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_0, 0));
+ emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, DT_ACTIVITY_ACTIVE, lbl_exit));
+
+ /* dctx.mst->scratch_top = 8 */
+ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_7, DMST_SCRATCH_TOP, 8));
+
+ /* Call clause. */
+ emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_9));
+ emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
+
+ /* Finished this clause. */
emitl(dlp, lbl_next,
BPF_NOP());
+
+ /* Right-shift %r6. */
+ emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_6, 1));
}
dt_cg_tramp_return(pcb);
@@ -630,10 +651,9 @@ static int trampoline_is_enabled(dt_pcb_t *pcb, uint_t exitlbl)
{
dt_irlist_t *dlp = &pcb->pcb_ir;
const dt_probe_t *uprp = pcb->pcb_probe;
- const dt_uprobe_t *upp = uprp->prv_data;
- const list_probe_t *pop;
- uint_t lbl_assign = dt_irlist_label(dlp);
- uint_t lbl_exit = pcb->pcb_exitlbl;
+ dt_ident_t *uprobes = dt_dlib_get_map(pcb->pcb_hdl, "uprobes");
+
+ assert(uprobes != NULL);
dt_cg_tramp_prologue(pcb);
@@ -642,7 +662,6 @@ static int trampoline_is_enabled(dt_pcb_t *pcb, uint_t exitlbl)
* // (%r7 = dctx->mst)
* // (%r8 = dctx->ctx)
*/
-
dt_cg_tramp_copy_regs(pcb);
/*
@@ -660,46 +679,30 @@ static int trampoline_is_enabled(dt_pcb_t *pcb, uint_t exitlbl)
emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
/*
- * Generate a composite conditional clause, as above, except that rather
- * than emitting call_clauses, we emit copyouts instead, using
- * copyout_val() above:
+ * Look up in the BPF uprobes map. Space for the look-up key will be used
+ * on the BPF stack:
*
- * if (pid == PID1) {
- * goto assign;
- * } else if (pid == PID2) {
- * goto assign;
- * } else if (pid == ...) {
- * goto assign;
- * }
- * goto exit;
- * assign:
- * *arg0 = 1;
- * goto exit;
+ * offset value
+ *
+ * -sizeof(uprobe_map_key_t) pid (in %r0)
*
- * It is valid and safe to use %r0 to hold the pid value because there
- * are no assignments to %r0 possible in between the conditional
- * statements.
+ * -sizeof(uprobe_map_key_t) + sizeof(pid_t)
+ * ==
+ * -sizeof(dtrace_id_t) underlying-probe prid
*/
- for (pop = dt_list_next(&upp->probes); pop != NULL;
- pop = dt_list_next(pop)) {
- const dt_probe_t *prp = pop->probe;
- pid_t pid;
- dt_ident_t *idp;
-
- pid = dt_pid_get_pid(prp->desc, pcb->pcb_hdl, pcb, NULL);
- assert(pid != -1);
-
- idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
- assert(idp != NULL);
+ emit(dlp, BPF_STORE(BPF_W, BPF_REG_9, (int)(-sizeof(uprobe_map_key_t)), BPF_REG_0));
+ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, (int)(-sizeof(dtrace_id_t)), uprp->desc->id));
+ dt_cg_xsetx(dlp, uprobes, DT_LBL_NONE, BPF_REG_1, uprobes->di_id);
+ emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_9));
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, (int)(-sizeof(uprobe_map_key_t))));
+ emit(dlp, BPF_CALL_HELPER(BPF_FUNC_map_lookup_elem));
+ emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, pcb->pcb_exitlbl));
- /*
- * Check whether this pid-provider probe serves the current
- * process, and copy out a 1 into arg 0 if so.
- */
- emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, pid, lbl_assign));
- }
- emit(dlp, BPF_JUMP(lbl_exit));
- copyout_val(pcb, lbl_assign, 1, 0);
+ /*
+ * If we succeeded, then we use copyout_val() above to assign:
+ * *arg0 = 1;
+ */
+ copyout_val(pcb, DT_LBL_NONE, 1, 0);
dt_cg_tramp_return(pcb);
--
2.43.5
next prev parent reply other threads:[~2024-06-28 2:03 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-28 2:03 some v2 patches eugene.loh
2024-06-28 2:03 ` [PATCH v2 29/38] Set the ERROR PRID in BPF code eugene.loh
2024-06-28 2:03 ` [PATCH v2 32/38] Widen the EPID to include the PRID eugene.loh
2024-07-20 3:58 ` [DTrace-devel] " Kris Van Hees
2024-07-20 23:26 ` Eugene Loh
2024-07-22 21:09 ` Kris Van Hees
2024-06-28 2:03 ` eugene.loh [this message]
2024-06-28 2:03 ` [PATCH v2 36/38] Simplify trampoline_is_enabled() eugene.loh
2024-06-28 2:03 ` [PATCH v2 38/38] Systemwide USDT WIP eugene.loh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240628020316.32544-4-eugene.loh@oracle.com \
--to=eugene.loh@oracle.com \
--cc=dtrace-devel@oss.oracle.com \
--cc=dtrace@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox