* [PATCH 01/19] Change probes from having lists of clauses to lists of stmts
@ 2024-08-29 5:25 eugene.loh
2024-08-29 5:25 ` [PATCH 02/19] Add a hook for a provider-specific "update" function eugene.loh
` (18 more replies)
0 siblings, 19 replies; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
Each stmt has a clause and a probe description. Traditionally,
we have added clauses to probes. Further, we have generated an
enabled probe ID for each probe/clause combination, and the
consumer has use the EPID to determine the PRID as well as the
data descriptor for the clause.
In an up-coming patch, we will move to a new scheme, in which a
widened EPID will have the PRID in its upper 32 bits and a stmt
ID in the lower 32 bits. The stmt ID will be used to identify
clauses to call as well as the data descriptor for the clause.
In this patch, change from probes having clauses associated
with them to having stmts.
We move the definition of dt_probe_clause_t in dt_probe.c to
be a definition of dt_probe_stmt_t in dt_impl.h so that the
type will become available for providers that will need it.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_cg.c | 17 +++++----
libdtrace/dt_impl.h | 5 +++
libdtrace/dt_probe.c | 79 +++++++++++++++++++++++-------------------
libdtrace/dt_probe.h | 12 +++----
libdtrace/dt_program.c | 8 ++---
5 files changed, 66 insertions(+), 55 deletions(-)
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index 4fab8eed..a7861829 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -844,9 +844,10 @@ typedef struct {
} dt_clause_arg_t;
static int
-dt_cg_call_clause(dtrace_hdl_t *dtp, dt_ident_t *idp, dt_clause_arg_t *arg)
+dt_cg_call_clause(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp, dt_clause_arg_t *arg)
{
dt_irlist_t *dlp = arg->dlp;
+ dt_ident_t *idp = sdp->dtsd_clause;
/*
* if (*dctx.act != act) // ldw %r0, [%r9 + DCTX_ACT]
@@ -874,14 +875,12 @@ dt_cg_call_clause(dtrace_hdl_t *dtp, dt_ident_t *idp, dt_clause_arg_t *arg)
}
void
-dt_cg_tramp_call_clauses(dt_pcb_t *pcb, const dt_probe_t *prp,
- dt_activity_t act)
+dt_cg_tramp_call_clauses(dt_pcb_t *pcb, const dt_probe_t *prp, dt_activity_t act)
{
dt_irlist_t *dlp = &pcb->pcb_ir;
dt_clause_arg_t arg = { dlp, act, pcb->pcb_exitlbl };
- dt_probe_clause_iter(pcb->pcb_hdl, prp,
- (dt_clause_f *)dt_cg_call_clause, &arg);
+ dt_probe_stmt_iter(pcb->pcb_hdl, prp, (dt_stmt_f *)dt_cg_call_clause, &arg);
}
static int
@@ -990,9 +989,10 @@ dt_cg_tramp_epilogue_advance(dt_pcb_t *pcb, dt_activity_t act)
}
static int
-dt_cg_tramp_error_call_clause(dtrace_hdl_t *dtp, dt_ident_t *idp,
- dt_irlist_t *dlp)
+dt_cg_tramp_error_call_clause(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp, dt_irlist_t *dlp)
{
+ dt_ident_t *idp = sdp->dtsd_clause;
+
/*
* dt_error_#(dctx); // mov %r1, %r9
* // call dt_error_#
@@ -1029,8 +1029,7 @@ dt_cg_tramp_error(dt_pcb_t *pcb)
TRACE_REGSET("Trampoline: Begin");
emit(dlp, BPF_MOV_REG(BPF_REG_9, BPF_REG_1));
- dt_probe_clause_iter(dtp, dtp->dt_error,
- (dt_clause_f *)dt_cg_tramp_error_call_clause, dlp);
+ dt_probe_stmt_iter(dtp, dtp->dt_error, (dt_stmt_f *)dt_cg_tramp_error_call_clause, dlp);
emit(dlp, BPF_MOV_IMM(BPF_REG_0, 0));
emit(dlp, BPF_RETURN());
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 44dd1415..98fddc23 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -258,6 +258,11 @@ typedef struct dt_percpu_drops {
typedef uint32_t dt_version_t; /* encoded version (see below) */
+typedef struct dt_probe_stmt {
+ dt_list_t list;
+ dtrace_stmtdesc_t *stmt;
+} dt_probe_stmt_t;
+
struct dtrace_hdl {
const dtrace_vector_t *dt_vector; /* library vector, if vectored open */
void *dt_varg; /* vector argument, if vectored open */
diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
index ab90d2ed..bb28bbed 100644
--- a/libdtrace/dt_probe.c
+++ b/libdtrace/dt_probe.c
@@ -24,11 +24,6 @@
#include <dt_list.h>
#include <dt_bpf.h>
-typedef struct dt_probe_clause {
- dt_list_t list;
- dt_ident_t *clause;
-} dt_probe_clause_t;
-
typedef struct dt_probe_dependent {
dt_list_t list;
dt_probe_t *probe;
@@ -467,7 +462,7 @@ dt_probe_enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
void
dt_probe_destroy(dt_probe_t *prp)
{
- dt_probe_clause_t *pcp, *pcp_next;
+ dt_probe_stmt_t *psp, *psp_next;
dt_probe_instance_t *pip, *pip_next;
dt_probe_dependent_t *dep, *dep_next;
dtrace_hdl_t *dtp;
@@ -499,9 +494,18 @@ dt_probe_destroy(dt_probe_t *prp)
dt_free(dtp, prp->nargv);
dt_free(dtp, prp->xargv);
- for (pcp = dt_list_next(&prp->clauses); pcp != NULL; pcp = pcp_next) {
- pcp_next = dt_list_next(pcp);
- dt_free(dtp, pcp);
+ for (psp = dt_list_next(&prp->stmts); psp != NULL; psp = psp_next) {
+ psp_next = dt_list_next(psp);
+
+ /*
+ * FIXME? Is there nothing inside we also need to free?
+ *
+ * If psp->stmt was created with dt_probe_error_stmt(), maybe:
+ * dt_ident_t *idp = psp->stmt->dtsd_clause;
+ * dt_iddtor_difo(idp);
+ * dt_ident_destroy(idp);
+ */
+ dt_free(dtp, psp);
}
for (dep = dt_list_next(&prp->dependents); dep != NULL; dep = dep_next) {
@@ -1283,24 +1287,24 @@ dtrace_probe_iter(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
}
/*
- * Create an ERROR-probe specific copy of a given clause.
+ * Create an ERROR-probe specific copy of a given stmt.
*
- * A modified copy of the clause is necessary because the ERROR probe may share
- * some clauses with other probes, and yet it needs to be handled differently.
+ * A modified copy of the stmt is necessary because the ERROR probe may share
+ * some stmts with other probes, and yet it needs to be handled differently.
*
- * The following modifications are made in the copy of the clause:
- *
- * - it is named dt_error_N where N is taken from the original clause
- * dt_clause_N (which also guarantees uniqueness)
+ * In the copy of the stmt, the clause is named dt_error_N, where N is taken
+ * from the original stmt's dt_clause_N (which also guarantees uniqueness).
*/
-dt_ident_t *
-dt_probe_error_clause(dtrace_hdl_t *dtp, dt_ident_t *idp)
+static dtrace_stmtdesc_t *
+dt_probe_error_stmt(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
{
char *name;
int len;
+ dt_ident_t *idp = sdp->dtsd_clause;
dtrace_difo_t *dp = dt_dlib_get_func_difo(dtp, idp);
dt_ident_t *nidp = NULL;
dtrace_difo_t *ndp;
+ dtrace_stmtdesc_t *nsdp = NULL;
/*
* Copy the DIFO.
@@ -1316,7 +1320,6 @@ dt_probe_error_clause(dtrace_hdl_t *dtp, dt_ident_t *idp)
name = dt_alloc(dtp, len);
if (name == NULL)
goto no_mem;
-
snprintf(name, len, "dt_error_%s", idp->di_name + strlen("dt_clause_"));
/*
@@ -1330,7 +1333,12 @@ dt_probe_error_clause(dtrace_hdl_t *dtp, dt_ident_t *idp)
dt_ident_set_data(nidp, ndp);
- return nidp;
+ nsdp = dt_alloc(dtp, sizeof(dtrace_stmtdesc_t));
+ if (nsdp == NULL)
+ goto no_mem;
+ nsdp->dtsd_clause = nidp;
+
+ return nsdp;
no_mem:
if (ndp != NULL)
@@ -1343,40 +1351,39 @@ no_mem:
}
int
-dt_probe_add_clause(dtrace_hdl_t *dtp, dt_probe_t *prp, dt_ident_t *idp)
+dt_probe_add_stmt(dtrace_hdl_t *dtp, dt_probe_t *prp, dtrace_stmtdesc_t *sdp)
{
- dt_probe_clause_t *pcp;
+ dt_probe_stmt_t *psp;
- pcp = dt_zalloc(dtp, sizeof(dt_probe_clause_t));
- if (pcp == NULL)
+ psp = dt_zalloc(dtp, sizeof(dt_probe_stmt_t));
+ if (psp == NULL)
return dt_set_errno(dtp, EDT_NOMEM);
if (prp == dtp->dt_error) {
- pcp->clause = dt_probe_error_clause(dtp, idp);
- if (pcp->clause == NULL) {
- dt_free(dtp, pcp);
+ psp->stmt = dt_probe_error_stmt(dtp, sdp);
+ if (psp->stmt == NULL) {
+ dt_free(dtp, psp);
return 0;
}
} else
- pcp->clause = idp;
+ psp->stmt = sdp;
- dt_list_append(&prp->clauses, pcp);
+ dt_list_append(&prp->stmts, psp);
return 0;
}
int
-dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
- dt_clause_f *func, void *arg)
+dt_probe_stmt_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp, dt_stmt_f *func, void *arg)
{
- dt_probe_clause_t *pcp;
- int rc;
+ dt_probe_stmt_t *psp;
+ int rc;
assert(func != NULL);
- for (pcp = dt_list_next(&prp->clauses); pcp != NULL;
- pcp = dt_list_next(pcp)) {
- rc = func(dtp, pcp->clause, arg);
+ for (psp = dt_list_next(&prp->stmts); psp != NULL;
+ psp = dt_list_next(psp)) {
+ rc = func(dtp, psp->stmt, arg);
if (rc != 0)
return rc;
diff --git a/libdtrace/dt_probe.h b/libdtrace/dt_probe.h
index b4c1a3e4..2a78cb9c 100644
--- a/libdtrace/dt_probe.h
+++ b/libdtrace/dt_probe.h
@@ -32,7 +32,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 stmts; /* stmts */
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 */
@@ -86,11 +86,11 @@ typedef int dt_probe_f(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg);
extern int dt_probe_iter(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
dt_probe_f *pfunc, dtrace_probe_f *dfunc, void *arg);
-extern int dt_probe_add_clause(dtrace_hdl_t *dtp, dt_probe_t *prp,
- dt_ident_t *idp);
-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_stmt(dtrace_hdl_t *dtp, dt_probe_t *prp,
+ dtrace_stmtdesc_t *sdp);
+typedef int dt_stmt_f(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp, void *arg);
+extern int dt_probe_stmt_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
+ dt_stmt_f *func, void *arg);
extern int dt_probe_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp,
dt_probe_t *idprp);
diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
index bdb434e0..afbf7265 100644
--- a/libdtrace/dt_program.c
+++ b/libdtrace/dt_program.c
@@ -139,8 +139,8 @@ dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
}
typedef struct pi_state {
- int *cnt;
- dt_ident_t *idp;
+ int *cnt;
+ dtrace_stmtdesc_t *sdp;
} pi_state_t;
static int
@@ -151,7 +151,7 @@ dt_stmt_probe(dtrace_hdl_t *dtp, dt_probe_t *prp, pi_state_t *st)
dt_probe_info(dtp, prp->desc, &p);
dt_probe_enable(dtp, prp);
- dt_probe_add_clause(dtp, prp, st->idp);
+ dt_probe_add_stmt(dtp, prp, st->sdp);
(*st->cnt)++;
return 0;
@@ -166,7 +166,7 @@ dt_prog_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
int rc;
st.cnt = cnt;
- st.idp = sdp->dtsd_clause;
+ st.sdp = sdp;
rc = dt_probe_iter(dtp, pdp, (dt_probe_f *)dt_stmt_probe, NULL, &st);
/*
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 02/19] Add a hook for a provider-specific "update" function
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 5:25 ` [PATCH 03/19] Widen the EPID to include the PRID eugene.loh
` (17 subsequent siblings)
18 siblings, 0 replies; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
For up-coming USDT-probe support, we need to update a BPF map
-- at least when the dtrace session starts but possibly also later
to support systemwide USDT tracing for processes that may start up
later.
One way to do this is with a USDT-specific update function.
For now, let's add a hook for providers to have provider-specific
update functions. User space can either call
for (i = 0; i < ARRAY_SIZE(dt_providers); i++) {
if (dt_providers[i]->update)
dt_providers[i]->update(...);
}
any time it likes. Or it can call dt_usdt.update(...).
This is for WIP. A different approach can be adopted later instead.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_provider.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h
index 17b1844c..21ff15ad 100644
--- a/libdtrace/dt_provider.h
+++ b/libdtrace/dt_provider.h
@@ -68,6 +68,8 @@ typedef struct dt_provimpl {
void *datap);
void (*destroy)(dtrace_hdl_t *dtp, /* free provider data */
void *datap);
+ void (*update)(dtrace_hdl_t *dtp, /* update provider-specific info */
+ void *datap);
} dt_provimpl_t;
/* list dt_dtrace first */
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 03/19] Widen the EPID to include the PRID
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
2024-08-29 5:25 ` [PATCH 02/19] Add a hook for a provider-specific "update" function eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 20:28 ` [DTrace-devel] " Sam James
2024-08-29 5:25 ` [PATCH 04/19] Eliminate dt_pdesc eugene.loh
` (16 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
Each output record has an EPID associated with it. When the consumer
reads a record, it uses the EPID to look up both a PRID (so it can
report PRID and probe function and name) and a data description.
During code generation, the PRID and data description are known,
and so the EPID is set during relocation.
However, we want to support underlying probes that trigger for PRIDs
that will be discovered at run time. So, expand the EPID to 64 bits:
*) the lower half, known at code generation, will index into an
array dtp->dt_stmts[] of statements, which have information
about probe descriptions, data descriptions, and clauses to call
*) the upper half will have the PRID, which will be discovered
at run time
Statement descriptions include a new member dtsd_index, which is
the index to dtp->dt_stmts[].
The consumer gets information about the firing probe from the PRID,
an index to dtp->dt_probes[].
The lower half "EPID" depends only on the statement and no longer
on the specific probe that is firing. Its value is known at code
generation for a compiled clause. It no longer needs to be set in
relocation; that relocation will be removed in a future patch.
The buffer memory pointed to by dctx->buf is rearranged so that EPID
will (still) fall on an 8-byte boundary but now take up 8 bytes.
We do not need to expand:
- the mstate (since it already had the PRID)
Rename mstate's epid to be a statement ID, stid. When
the producer needs the epid, it can construct it from
mst->prid and mst->stid.
- the output buffer (since it already had unused padding)
The new, wider EPID is seen for the built-in variable epid as well
as the epid that the consumer reads.
The probe descriptions dt_pdesc become superfluous and will be
eliminated in a future patch.
Update test files:
- Where the upper 32 bits of the EPID are known (since the PRID
corresponds to a dtrace::: probe), update the expected EPID in
the .r files.
- Where the upper 32 bits of the EPID are not known, add .r.p
processing to filter those bits out before comparing to known
results in .r files.
- Increase expected EPID width.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
bpf/get_bvar.c | 6 ++-
bpf/probe_error.c | 2 +-
include/dtrace/universal.h | 2 +-
libdtrace/dt_bpf.c | 2 -
libdtrace/dt_cc.c | 13 ++---
libdtrace/dt_cg.c | 49 +++++++++++--------
libdtrace/dt_consume.c | 28 +++++++----
libdtrace/dt_dctx.h | 16 +++---
libdtrace/dt_handle.c | 9 ++--
libdtrace/dt_impl.h | 1 +
libdtrace/dt_map.c | 11 +++--
libdtrace/dt_open.c | 2 +-
libdtrace/dt_program.c | 7 +++
libdtrace/dtrace.h | 1 +
test/demo/dtrace/error.r | 2 +-
test/stress/buffering/tst.resize3-manual.r | 2 +-
test/stress/buffering/tst.resize3.r | 2 +-
test/unittest/actions/setopt/tst.badopt.r | 14 +++---
.../arrays/tst.declared-bounds.runtime_out.r | 2 +-
test/unittest/codegen/err.deref_0.r | 2 +-
test/unittest/codegen/err.deref_1.r | 2 +-
test/unittest/codegen/err.deref_i0.r | 2 +-
test/unittest/codegen/err.deref_i1.r | 2 +-
.../unittest/codegen/err.deref_string-assoc.r | 2 +-
test/unittest/codegen/err.deref_string-gvar.r | 2 +-
test/unittest/codegen/err.deref_string-lvar.r | 2 +-
test/unittest/codegen/err.deref_string-tvar.r | 2 +-
.../codegen/err.str_NULL_plus_offset-assoc.r | 2 +-
.../codegen/err.str_NULL_plus_offset-lvar.r | 2 +-
.../codegen/err.str_NULL_plus_offset-tvar.r | 2 +-
.../codegen/err.str_NULL_plus_offset.r | 2 +-
test/unittest/disasm/tst.vartab-bvar.r | 2 +-
test/unittest/drops/drp.DTRACEDROP_DBLERROR.r | 2 +-
.../tst.DTRACEFLT_BADADDR.null_ptr_field.r | 2 +-
test/unittest/error/tst.DTRACEFLT_BADADDR.r | 4 +-
test/unittest/error/tst.DTRACEFLT_BADADDR2.r | 4 +-
.../error/tst.DTRACEFLT_DIVZERO.div.r | 2 +-
.../error/tst.DTRACEFLT_DIVZERO.mod.r | 2 +-
test/unittest/error/tst.DTRACEFLT_UNKNOWN.r | 4 +-
.../error/tst.clause_scope-begin-ended.r | 2 +-
test/unittest/error/tst.clause_scope-begin.r | 2 +-
.../unittest/error/tst.clause_scope-regular.r | 2 +-
.../error/tst.clause_scope-regular.r.p | 12 ++++-
test/unittest/error/tst.error.r | 2 +-
test/unittest/error/tst.errorend.r | 2 +-
.../alloca/err.alloca-bcopy-before-beyond.r | 2 +-
.../alloca/err.alloca-bcopy-before-bottom.r | 2 +-
.../alloca/err.alloca-bcopy-beyond-top.r | 2 +-
.../alloca/err.alloca-bcopy-crossing-bottom.r | 2 +-
.../alloca/err.alloca-bcopy-crossing-top.r | 2 +-
.../alloca/err.alloca-crossing-clauses.r | 2 +-
.../alloca/err.alloca-load-before-bottom.r | 2 +-
.../funcs/alloca/err.alloca-load-beyond-top.r | 2 +-
.../alloca/err.alloca-load-crossing-bottom.r | 2 +-
.../alloca/err.alloca-null-deref-lvalue.r | 2 +-
.../funcs/alloca/err.alloca-null-deref.r | 2 +-
.../err.alloca-scratch-exceeding-bcopy.r | 2 +-
.../alloca/err.alloca-store-before-bottom.r | 2 +-
.../alloca/err.alloca-store-beyond-top.r | 2 +-
.../alloca/err.alloca-store-crossing-bottom.r | 2 +-
test/unittest/funcs/bcopy/err.badbcopy1.r | 2 +-
test/unittest/funcs/bcopy/err.badbcopy4.r | 2 +-
test/unittest/funcs/bcopy/err.badbcopy5.r | 2 +-
test/unittest/funcs/bcopy/err.badbcopy6.r | 2 +-
test/unittest/funcs/bcopy/err.badbcopy7.r | 2 +-
test/unittest/funcs/bcopy/err.badbcopy8.r | 2 +-
test/unittest/funcs/copyin/err.badaddr.r | 2 +-
test/unittest/funcs/copyin/err.null_arg1.r | 2 +-
test/unittest/funcs/copyinstr/err.badaddr.r | 2 +-
test/unittest/funcs/copyinstr/err.null_arg1.r | 2 +-
test/unittest/funcs/copyinto/err.badaddr.r | 2 +-
test/unittest/funcs/copyinto/err.badsize.r | 2 +-
test/unittest/funcs/copyinto/err.null_arg1.r | 2 +-
test/unittest/funcs/err.badalloca.r | 2 +-
test/unittest/funcs/err.badalloca.r.p | 12 ++++-
test/unittest/funcs/err.link_ntopbadaddr.r | 2 +-
test/unittest/funcs/err.link_ntopbadarg.r | 2 +-
.../inet_ntoa6/err.inet_ntoa6.arg1_null.r | 2 +-
.../err.inet_ntoa6.arg1_null_const.r | 2 +-
test/unittest/funcs/strlen/tst.null.r | 2 +-
test/unittest/funcs/strtok/tst.strtok_null.r | 2 +-
.../funcs/strtok/tst.strtok_nulldel.r | 2 +-
.../funcs/strtok/tst.strtok_nullstr.r | 2 +-
.../funcs/strtok/tst.strtok_nullstr2.r | 2 +-
.../funcs/substr/err.substr_null_arg1.r | 2 +-
test/unittest/pointers/err.AllocaOverrun.r | 2 +-
test/unittest/pointers/err.BadAlign.r | 2 +-
test/unittest/pointers/err.InvalidAddress2.r | 2 +-
test/unittest/pointers/err.InvalidAddress4.r | 2 +-
.../speculation/err.CommitWithInvalid.r | 2 +-
.../speculation/err.DiscardWithInvalid.r | 2 +-
test/unittest/speculation/tst.negcommit.r | 2 +-
92 files changed, 197 insertions(+), 146 deletions(-)
diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
index a0c04f3a..e9733bb1 100644
--- a/bpf/get_bvar.c
+++ b/bpf/get_bvar.c
@@ -48,8 +48,10 @@ noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx)
mst->tstamp = bpf_ktime_get_ns();
return mst->tstamp;
- case DIF_VAR_EPID:
- return mst->epid;
+ case DIF_VAR_EPID: {
+ uint64_t val = mst->prid;
+ return (val << 32) | mst->stid;
+ }
case DIF_VAR_ID:
return mst->prid;
case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2:
diff --git a/bpf/probe_error.c b/bpf/probe_error.c
index ee1a1793..fba779a8 100644
--- a/bpf/probe_error.c
+++ b/bpf/probe_error.c
@@ -29,7 +29,7 @@ noinline void dt_probe_error(const dt_dctx_t *dctx, uint64_t pc, uint64_t fault,
int oldprid = mst->prid;
mst->argv[0] = 0;
- mst->argv[1] = mst->epid;
+ mst->argv[1] = (((uint64_t)mst->prid) << 32) | mst->stid;
mst->argv[2] = mst->clid;
mst->argv[3] = pc;
mst->argv[4] = fault;
diff --git a/include/dtrace/universal.h b/include/dtrace/universal.h
index d6562489..655ea772 100644
--- a/include/dtrace/universal.h
+++ b/include/dtrace/universal.h
@@ -37,7 +37,7 @@ typedef uint16_t dtrace_actkind_t; /* action kind */
typedef uint32_t dtrace_aggid_t; /* aggregation identifier */
typedef uint32_t dtrace_cacheid_t; /* predicate cache identifier */
-typedef uint32_t dtrace_epid_t; /* enabled probe identifier */
+typedef uint64_t dtrace_epid_t; /* enabled probe identifier */
typedef uint32_t dtrace_optid_t; /* option identifier */
typedef uint32_t dtrace_specid_t; /* speculation identifier */
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 70597d65..3f9c42ea 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -774,7 +774,6 @@ gmap_create_cpuinfo(dtrace_hdl_t *dtp)
* The size of the memory region is the sum of:
* - size of the DTrace machine state, rounded up to the nearest
* multiple of 8
- * - 8 bytes padding for trace buffer alignment purposes
* - maximum trace buffer record size, rounded up to the nearest
* multiple of 8
* - size of dctx->mem (see dt_dctx.h)
@@ -783,7 +782,6 @@ static int
gmap_create_mem(dtrace_hdl_t *dtp)
{
size_t sz = roundup(sizeof(dt_mstate_t), 8) +
- 8 +
roundup(dtp->dt_maxreclen, 8) +
DMEM_SIZE(dtp);
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index d1ee3843..cf3c5504 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -123,6 +123,7 @@ dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
if (sdp == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+ sdp->dtsd_index = dtp->dt_clause_nextid++;
assert(yypcb->pcb_stmt == NULL);
yypcb->pcb_stmt = sdp;
yypcb->pcb_maxrecs = 0;
@@ -133,8 +134,8 @@ dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
return sdp;
}
-static dt_ident_t *
-dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
+static void
+dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp, dtrace_stmtdesc_t *sdp)
{
char *name;
int len;
@@ -156,12 +157,12 @@ dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
/*
* Generate a symbol name.
*/
- len = snprintf(NULL, 0, "dt_clause_%d", dtp->dt_clause_nextid) + 1;
+ len = snprintf(NULL, 0, "dt_clause_%d", sdp->dtsd_index) + 1;
name = dt_alloc(dtp, len);
if (name == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
- snprintf(name, len, "dt_clause_%d", dtp->dt_clause_nextid++);
+ snprintf(name, len, "dt_clause_%d", sdp->dtsd_index);
/*
* Add the symbol to the BPF identifier table and associate the DIFO
@@ -174,7 +175,7 @@ dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
dt_ident_set_data(idp, dp);
- return idp;
+ sdp->dtsd_clause = idp;
}
static void
@@ -214,7 +215,7 @@ dt_compile_one_clause(dtrace_hdl_t *dtp, dt_node_t *cnp, dt_node_t *pnp)
* Compile the clause (predicate and action).
*/
dt_cg(yypcb, cnp);
- sdp->dtsd_clause = dt_clause_create(dtp, dt_as(yypcb));
+ dt_clause_create(dtp, dt_as(yypcb), sdp);
assert(yypcb->pcb_stmt == sdp);
if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0)
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index a7861829..2c559868 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -277,15 +277,9 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
* buf = rc + roundup(sizeof(dt_mstate_t), 8);
* // add %r0, roundup(
* sizeof(dt_mstate_t), 8)
- * *((uint64_t *)&buf[0]) = 0;
- * // stdw [%r0 + 0], 0
- * buf += 8; // add %r0, 8
- * // (%r0 = pointer to buffer space)
* dctx.buf = buf; // stdw [%r9 + DCTX_BUF], %r0
*/
emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, roundup(sizeof(dt_mstate_t), 8)));
- emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, 0, 0));
- emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8));
emit(dlp, BPF_STORE(BPF_DW, BPF_REG_9, DCTX_BUF, BPF_REG_0));
/*
@@ -1057,10 +1051,8 @@ static void
dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
{
dt_irlist_t *dlp = &pcb->pcb_ir;
- dt_ident_t *epid = dt_dlib_get_var(pcb->pcb_hdl, "EPID");
dt_ident_t *clid = dt_dlib_get_var(pcb->pcb_hdl, "CLID");
- assert(epid != NULL);
assert(clid != NULL);
/*
@@ -1093,18 +1085,22 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
* // stdw [%r0 + DMST_FAULT], 0
* dctx->mst->tstamp = 0; // stdw [%r0 + DMST_TSTAMP], 0
* dctx->mst->specsize = 0;// stdw [%r0 + DMST_SPECSIZE], 0
- * dctx->mst->epid = EPID; // stw [%r0 + DMST_EPID], EPID
+ * dctx->mst->stid = STID; // stw [%r0 + DMST_STID], STID
* dctx->mst->clid = CLID; // stw [%r0 + DMST_CLID], CLID
- * *((uint32_t *)&buf[DBUF_EPID]) = EPID;
- * // stw [%r9 + DBUF_EPID], EPID
*/
emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_0, DCTX_MST));
emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_FAULT, 0));
emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_TSTAMP, 0));
emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_SPECSIZE, 0));
- emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_EPID, -1), epid);
+ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_STID, pcb->pcb_stmt->dtsd_index));
emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_CLID, -1), clid);
- emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_EPID, -1), epid);
+
+ /*
+ * Zero out the leading 4 bytes of the buffer.
+ * *((uint32_t *)&buf[DBUF_PAD]) = 0;
+ * // stw [%r9 + DBUF_PAD], 0
+ */
+ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_PAD, 0));
/*
* Set the speculation ID field to zero to indicate no active
@@ -1114,6 +1110,18 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
*/
emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_SPECID, 0));
+ /*
+ * *((uint64_t *)&buf[DBUF_EPID]) = (dctx->mst->prid << 32) | stid;
+ * // ld %r1, [%r0 + DMST_PRID]
+ * // lsh %r1, 32
+ * // or %r1, stid
+ * // stdw [%r9 + DBUF_EPID], %r1
+ */
+ emit (dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_0, DMST_PRID));
+ emit (dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 32));
+ emit (dlp, BPF_ALU64_IMM(BPF_OR, BPF_REG_1, pcb->pcb_stmt->dtsd_index));
+ emit (dlp, BPF_STORE(BPF_DW, BPF_REG_9, DBUF_EPID, BPF_REG_1));
+
/*
* If there is a predicate:
*
@@ -1132,10 +1140,9 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
TRACE_REGSET("Prologue: End ");
/*
- * Account for 32-bit EPID (at offset 0) and 32-bit speculation ID (at
- * offset 4).
+ * Set the offset for the beginning of trace data.
*/
- pcb->pcb_bufoff += 2 * sizeof(uint32_t);
+ pcb->pcb_bufoff = DBUF_DATA;
}
/*
@@ -1170,15 +1177,15 @@ dt_cg_epilogue(dt_pcb_t *pcb)
/*
* rc = bpf_perf_event_output(dctx->ctx, &buffers,
* BPF_F_CURRENT_CPU,
- * buf - 4, bufoff + 4);
+ * buf + 4, bufoff - 4);
* // lddw %r1, [%fp + DT_STK_DCTX]
* // lddw %r1, [%r1 + DCTX_CTX]
* // lddw %r2, &buffers
* // lddw %r3, BPF_F_CURRENT_CPU
* // mov %r4, %r9
- * // add %r4, -4
+ * // add %r4, 4
* // mov %r5, pcb->pcb_bufoff
- * // add %r5, 4
+ * // add %r5, -4
* // call bpf_perf_event_output
*/
emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_DCTX));
@@ -1186,9 +1193,9 @@ dt_cg_epilogue(dt_pcb_t *pcb)
dt_cg_xsetx(dlp, buffers, DT_LBL_NONE, BPF_REG_2, buffers->di_id);
dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, BPF_REG_3, BPF_F_CURRENT_CPU);
emit(dlp, BPF_MOV_REG(BPF_REG_4, BPF_REG_9));
- emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -4));
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4));
emit(dlp, BPF_MOV_IMM(BPF_REG_5, pcb->pcb_bufoff));
- emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4));
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -4));
emit(dlp, BPF_CALL_HELPER(BPF_FUNC_perf_event_output));
/*
diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
index 51eb6c80..e3ce2d3b 100644
--- a/libdtrace/dt_consume.c
+++ b/libdtrace/dt_consume.c
@@ -15,9 +15,11 @@
#include <alloca.h>
#include <dt_impl.h>
#include <dt_aggregate.h>
+#include <dt_dctx.h>
#include <dt_module.h>
#include <dt_pcap.h>
#include <dt_peb.h>
+#include <dt_probe.h>
#include <dt_state.h>
#include <dt_string.h>
#include <libproc.h>
@@ -479,7 +481,7 @@ dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last)
*/
if (flow == DTRACEFLOW_ENTRY) {
if (last != DTRACE_EPIDNONE && id != last &&
- pd->id == dtp->dt_pdesc[last]->id)
+ pd->id == dtp->dt_probes[last >> 32]->desc->id)
flow = DTRACEFLOW_NONE;
}
@@ -2184,19 +2186,23 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
int peekflags, dtrace_epid_t *last, int committing,
void *arg)
{
+ int specid;
dtrace_epid_t epid;
+ uint32_t prid;
dtrace_datadesc_t *epd;
dt_spec_buf_t tmpl;
dt_spec_buf_t *dtsb;
- int specid;
int i;
int rval;
dtrace_workstatus_t ret;
int commit_discard_seen, only_commit_discards;
int data_recording = 1;
- epid = ((uint32_t *)data)[0];
- specid = ((uint32_t *)data)[1];
+ specid = *((uint32_t *)(data + DBUF_SPECID));
+ epid = *((uint64_t *)(data + DBUF_EPID));
+ prid = epid >> 32;
+ if (prid > dtp->dt_probe_id)
+ return dt_set_errno(dtp, EDT_BADEPID);
/*
* Fill in the epid and address of the epid in the buffer. We need to
@@ -2209,6 +2215,7 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
&pdat->dtpda_pdesc);
if (rval != 0)
return dt_set_errno(dtp, EDT_BADEPID);
+ pdat->dtpda_pdesc = (dtrace_probedesc_t *)dtp->dt_probes[prid]->desc;
epd = pdat->dtpda_ddesc;
if (epd->dtdd_uarg != DT_ECB_DEFAULT) {
@@ -2639,9 +2646,8 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
* struct {
* struct perf_event_header header;
* uint32_t size;
- * uint32_t pad;
- * uint32_t epid;
* uint32_t specid;
+ * dtrace_epid_t epid;
* uint64_t data[n];
* }
* and 'data' points to the 'size' member at this point.
@@ -2651,13 +2657,17 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
return dt_set_errno(dtp, EDT_DSIZE);
size = *(uint32_t *)data;
- data += sizeof(size);
ptr += sizeof(size) + size;
if (ptr != buf + hdr->size)
return dt_set_errno(dtp, EDT_DSIZE);
- data += sizeof(uint32_t); /* skip padding */
- size -= sizeof(uint32_t);
+ /*
+ * The "size" measures from specid to the end. But our buffer
+ * offsets are relative to &size itself, to preserve 8-byte
+ * alignment. So, we leave data pointing at &size, and we
+ * increase size by 4 bytes.
+ */
+ size += 4;
return dt_consume_one_probe(dtp, fp, data, size, pdat, efunc,
rfunc, flow, quiet, peekflags,
diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h
index 1422ad24..6592bef1 100644
--- a/libdtrace/dt_dctx.h
+++ b/libdtrace/dt_dctx.h
@@ -18,7 +18,7 @@
* The DTrace machine state.
*/
typedef struct dt_mstate {
- uint32_t epid; /* Enabled probe ID */
+ uint32_t stid; /* Statement ID */
uint32_t prid; /* Probe ID */
uint32_t clid; /* Clause ID (unique per probe) */
uint32_t tag; /* Tag (for future use) */
@@ -33,7 +33,7 @@ typedef struct dt_mstate {
uint64_t saved_argv[10]; /* Saved probe arguments */
} dt_mstate_t;
-#define DMST_EPID offsetof(dt_mstate_t, epid)
+#define DMST_STID offsetof(dt_mstate_t, stid)
#define DMST_PRID offsetof(dt_mstate_t, prid)
#define DMST_CLID offsetof(dt_mstate_t, clid)
#define DMST_TAG offsetof(dt_mstate_t, tag)
@@ -82,16 +82,20 @@ typedef struct dt_dctx {
* The dctx->buf pointer references a block of memory that contains:
*
* +----------------+
- * 0 -> | EPID |
+ * 0 -> | pad |
* +----------------+
- * 4 -> | Speculation ID |
+ * 4 -> | Speculation ID |
* +----------------+
- * | Trace Data |
+ * 8 -> | EPID |
+ * +----------------+
+ * 16 -> | Trace Data |
* | ... |
* +----------------+
*/
-#define DBUF_EPID 0
+#define DBUF_PAD 0
#define DBUF_SPECID 4
+#define DBUF_EPID 8
+#define DBUF_DATA 16
/*
* The dctx->mem pointer references a block of memory that contains:
diff --git a/libdtrace/dt_handle.c b/libdtrace/dt_handle.c
index 4c9b9413..b1ba5f9f 100644
--- a/libdtrace/dt_handle.c
+++ b/libdtrace/dt_handle.c
@@ -14,6 +14,7 @@
#include <alloca.h>
#include <dt_impl.h>
+#include <dt_probe.h>
#include <dt_program.h>
static const char _dt_errprog[] =
@@ -147,11 +148,11 @@ dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
* This is an error. We have the following items here: EPID,
* faulting action, BPF pc, fault code and faulting address.
*/
- epid = (uint32_t)DT_REC(uint64_t, 0);
+ epid = DT_REC(uint64_t, 0);
if (dt_epid_lookup(dtp, epid, &errdd, &errpd) != 0)
return dt_set_errno(dtp, EDT_BADERROR);
-
+ errpd = (dtrace_probedesc_t *)dtp->dt_probes[epid>>32]->desc;
err.dteda_ddesc = errdd;
err.dteda_pdesc = errpd;
err.dteda_cpu = data->dtpda_cpu;
@@ -195,7 +196,7 @@ no_addr:
details[0] = 0;
}
- snprintf(str, len, "error on enabled probe ID %u (ID %u: %s:%s:%s:%s): "
+ snprintf(str, len, "error on enabled probe ID %lu (ID %u: %s:%s:%s:%s): "
"%s%s in %s%s",
epid, errpd->id, errpd->prv, errpd->mod, errpd->fun,
errpd->prb, dtrace_faultstr(dtp, err.dteda_fault), details,
@@ -256,7 +257,7 @@ dt_handle_liberr(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
str = alloca(len);
snprintf(str, len,
- "error on enabled probe ID %u (ID %u: %s:%s:%s:%s): %s",
+ "error on enabled probe ID %lu (ID %u: %s:%s:%s:%s): %s",
data->dtpda_epid, errpd->id, errpd->prv, errpd->mod,
errpd->fun, errpd->prb, faultstr);
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 98fddc23..a2ae84f6 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -275,6 +275,7 @@ struct dtrace_hdl {
dt_list_t dt_programs; /* linked list of dtrace_prog_t's */
dt_list_t dt_xlators; /* linked list of dt_xlator_t's */
dt_list_t dt_enablings; /* list of (to be) enabled probes */
+ dtrace_stmtdesc_t **dt_stmts; /* array of stmts */
struct dt_xlator **dt_xlatormap; /* dt_xlator_t's indexed by dx_id */
id_t dt_xlatorid; /* next dt_xlator_t id to assign */
dt_ident_t *dt_externs; /* linked list of external symbol identifiers */
diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
index 60a2eca2..87ce5707 100644
--- a/libdtrace/dt_map.c
+++ b/libdtrace/dt_map.c
@@ -138,14 +138,17 @@ int
dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp,
dtrace_probedesc_t **pdp)
{
- if (epid >= dtp->dt_maxprobe ||
- dtp->dt_ddesc[epid] == NULL || dtp->dt_pdesc[epid] == NULL)
+ /* Remove the PRID portion of the EPID. */
+ epid &= 0xffffffff;
+
+ if (epid >= dtp->dt_clause_nextid)
return -1;
- *ddp = dtp->dt_ddesc[epid];
+ dtrace_difo_t *rdp = dt_dlib_get_func_difo(dtp, dtp->dt_stmts[epid]->dtsd_clause);
+ *ddp = dt_datadesc_hold(rdp->dtdo_ddesc); // FIXME what releases the hold?
*pdp = dtp->dt_pdesc[epid];
- return 0;
+ return (*ddp == NULL) ? -1 : 0;
}
void
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 77ffb6d2..8ae6cdfa 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -170,7 +170,7 @@ static const dt_ident_t _dtrace_globals[] = {
{ "discard", DT_IDENT_ACTFUNC, 0, DT_ACT_DISCARD, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "void(int)" },
{ "epid", DT_IDENT_SCALAR, 0, DIF_VAR_EPID, DT_ATTR_STABCMN, DT_VERS_1_0,
- &dt_idops_type, "uint_t" },
+ &dt_idops_type, "uint64_t" },
{ "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "int" },
{ "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME,
diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
index afbf7265..ee743589 100644
--- a/libdtrace/dt_program.c
+++ b/libdtrace/dt_program.c
@@ -165,6 +165,13 @@ dt_prog_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
dtrace_probedesc_t *pdp = &sdp->dtsd_ecbdesc->dted_probe;
int rc;
+ if (dtp->dt_stmts == NULL) {
+ dtp->dt_stmts = dt_calloc(dtp, dtp->dt_clause_nextid, sizeof(dtrace_stmtdesc_t *));
+ if (dtp->dt_stmts == NULL)
+ return dt_set_errno(dtp, EDT_NOMEM);
+ }
+ dtp->dt_stmts[sdp->dtsd_index] = sdp;
+
st.cnt = cnt;
st.sdp = sdp;
rc = dt_probe_iter(dtp, pdp, (dt_probe_f *)dt_stmt_probe, NULL, &st);
diff --git a/libdtrace/dtrace.h b/libdtrace/dtrace.h
index 09a87977..a23052e4 100644
--- a/libdtrace/dtrace.h
+++ b/libdtrace/dtrace.h
@@ -150,6 +150,7 @@ typedef struct dtrace_stmtdesc {
dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
dtrace_attribute_t dtsd_stmtattr; /* statement attributes */
int dtsd_clauseflags; /* clause flags */
+ int dtsd_index; /* index in dtp->dt_stmts */
} dtrace_stmtdesc_t;
/* dtsd clause flags */
diff --git a/test/demo/dtrace/error.r b/test/demo/dtrace/error.r
index d3904f47..50b52370 100644
--- a/test/demo/dtrace/error.r
+++ b/test/demo/dtrace/error.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/demo/dtrace/error.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/stress/buffering/tst.resize3-manual.r b/test/stress/buffering/tst.resize3-manual.r
index 43b647c7..5493783e 100644
--- a/test/stress/buffering/tst.resize3-manual.r
+++ b/test/stress/buffering/tst.resize3-manual.r
@@ -1,5 +1,5 @@
FUNCTION:NAME
- :BEGIN 3
+ :BEGIN 4294967297
:BEGIN
-- @@stderr --
diff --git a/test/stress/buffering/tst.resize3.r b/test/stress/buffering/tst.resize3.r
index 9c471158..807c4d1c 100644
--- a/test/stress/buffering/tst.resize3.r
+++ b/test/stress/buffering/tst.resize3.r
@@ -1,5 +1,5 @@
FUNCTION:NAME
- :BEGIN 3
+ :BEGIN 4294967297
:BEGIN
-- @@stderr --
diff --git a/test/unittest/actions/setopt/tst.badopt.r b/test/unittest/actions/setopt/tst.badopt.r
index 29e39fd4..9373951c 100644
--- a/test/unittest/actions/setopt/tst.badopt.r
+++ b/test/unittest/actions/setopt/tst.badopt.r
@@ -1,16 +1,16 @@
-- @@stderr --
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "Nixon" to "1": Invalid option name
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "Nixon" to "1": Invalid option name
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "Harding" to "1": Invalid option name
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "Harding" to "1": Invalid option name
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "Hoover" to "1": Invalid option name
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "Hoover" to "1": Invalid option name
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "Bush" to "1": Invalid option name
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "Bush" to "1": Invalid option name
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "quiet" to "um, no": Invalid value for specified option
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "quiet" to "um, no": Invalid value for specified option
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "aggrate" to "0.5hz": Invalid value for specified option
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "aggrate" to "0.5hz": Invalid value for specified option
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "bufsize" to "1m": Operation illegal when tracing is active
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "bufsize" to "1m": Operation illegal when tracing is active
diff --git a/test/unittest/arrays/tst.declared-bounds.runtime_out.r b/test/unittest/arrays/tst.declared-bounds.runtime_out.r
index 4917528d..43892f61 100644
--- a/test/unittest/arrays/tst.declared-bounds.runtime_out.r
+++ b/test/unittest/arrays/tst.declared-bounds.runtime_out.r
@@ -1,3 +1,3 @@
expected run-time error
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): index out of bounds (8) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): index out of bounds (8) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_0.r b/test/unittest/codegen/err.deref_0.r
index 07c1dc52..654b9ece 100644
--- a/test/unittest/codegen/err.deref_0.r
+++ b/test/unittest/codegen/err.deref_0.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address (0) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address (0) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_1.r b/test/unittest/codegen/err.deref_1.r
index a2ca8ac4..d4a80bb3 100644
--- a/test/unittest/codegen/err.deref_1.r
+++ b/test/unittest/codegen/err.deref_1.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address (1) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address (1) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_i0.r b/test/unittest/codegen/err.deref_i0.r
index 07c1dc52..654b9ece 100644
--- a/test/unittest/codegen/err.deref_i0.r
+++ b/test/unittest/codegen/err.deref_i0.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address (0) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address (0) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_i1.r b/test/unittest/codegen/err.deref_i1.r
index a2ca8ac4..d4a80bb3 100644
--- a/test/unittest/codegen/err.deref_i1.r
+++ b/test/unittest/codegen/err.deref_i1.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address (1) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address (1) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_string-assoc.r b/test/unittest/codegen/err.deref_string-assoc.r
index 08277992..aa78c6eb 100644
--- a/test/unittest/codegen/err.deref_string-assoc.r
+++ b/test/unittest/codegen/err.deref_string-assoc.r
@@ -1,3 +1,3 @@
66
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_string-gvar.r b/test/unittest/codegen/err.deref_string-gvar.r
index 08277992..aa78c6eb 100644
--- a/test/unittest/codegen/err.deref_string-gvar.r
+++ b/test/unittest/codegen/err.deref_string-gvar.r
@@ -1,3 +1,3 @@
66
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_string-lvar.r b/test/unittest/codegen/err.deref_string-lvar.r
index 08277992..aa78c6eb 100644
--- a/test/unittest/codegen/err.deref_string-lvar.r
+++ b/test/unittest/codegen/err.deref_string-lvar.r
@@ -1,3 +1,3 @@
66
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
diff --git a/test/unittest/codegen/err.deref_string-tvar.r b/test/unittest/codegen/err.deref_string-tvar.r
index 08277992..aa78c6eb 100644
--- a/test/unittest/codegen/err.deref_string-tvar.r
+++ b/test/unittest/codegen/err.deref_string-tvar.r
@@ -1,3 +1,3 @@
66
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address (1) in action #2 at BPF pc NNN
diff --git a/test/unittest/codegen/err.str_NULL_plus_offset-assoc.r b/test/unittest/codegen/err.str_NULL_plus_offset-assoc.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/codegen/err.str_NULL_plus_offset-assoc.r
+++ b/test/unittest/codegen/err.str_NULL_plus_offset-assoc.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.str_NULL_plus_offset-lvar.r b/test/unittest/codegen/err.str_NULL_plus_offset-lvar.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/codegen/err.str_NULL_plus_offset-lvar.r
+++ b/test/unittest/codegen/err.str_NULL_plus_offset-lvar.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.str_NULL_plus_offset-tvar.r b/test/unittest/codegen/err.str_NULL_plus_offset-tvar.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/codegen/err.str_NULL_plus_offset-tvar.r
+++ b/test/unittest/codegen/err.str_NULL_plus_offset-tvar.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/codegen/err.str_NULL_plus_offset.r b/test/unittest/codegen/err.str_NULL_plus_offset.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/codegen/err.str_NULL_plus_offset.r
+++ b/test/unittest/codegen/err.str_NULL_plus_offset.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/disasm/tst.vartab-bvar.r b/test/unittest/disasm/tst.vartab-bvar.r
index 06d7c52b..53e5f618 100644
--- a/test/unittest/disasm/tst.vartab-bvar.r
+++ b/test/unittest/disasm/tst.vartab-bvar.r
@@ -4,7 +4,7 @@ curthread scl glb r D type (pointer) (size 8)
timestamp scl glb r D type (integer) (size 8)
vtimestamp scl glb r D type (integer) (size 8)
ipl scl glb r D type (integer) (size 4)
-epid scl glb r D type (integer) (size 4)
+epid scl glb r D type (integer) (size 8)
id scl glb r D type (integer) (size 4)
arg0 scl glb r D type (integer) (size 8)
arg1 scl glb r D type (integer) (size 8)
diff --git a/test/unittest/drops/drp.DTRACEDROP_DBLERROR.r b/test/unittest/drops/drp.DTRACEDROP_DBLERROR.r
index 9fa54dd9..b62b05f3 100644
--- a/test/unittest/drops/drp.DTRACEDROP_DBLERROR.r
+++ b/test/unittest/drops/drp.DTRACEDROP_DBLERROR.r
@@ -4,4 +4,4 @@
-- @@stderr --
dtrace: script 'test/unittest/drops/drp.DTRACEDROP_DBLERROR.d' matched 3 probes
dtrace: [DTRACEDROP_DBLERROR] 1 error in ERROR probe enabling
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.DTRACEFLT_BADADDR.null_ptr_field.r b/test/unittest/error/tst.DTRACEFLT_BADADDR.null_ptr_field.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/error/tst.DTRACEFLT_BADADDR.null_ptr_field.r
+++ b/test/unittest/error/tst.DTRACEFLT_BADADDR.null_ptr_field.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.DTRACEFLT_BADADDR.r b/test/unittest/error/tst.DTRACEFLT_BADADDR.r
index b9f5f43c..3fe68c05 100644
--- a/test/unittest/error/tst.DTRACEFLT_BADADDR.r
+++ b/test/unittest/error/tst.DTRACEFLT_BADADDR.r
@@ -1,6 +1,6 @@
-The arguments are 3 1 1 0
+The arguments are 4294967297 1 1 0
The value of arg4 should be 1
The value of arg5 should be 0
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.DTRACEFLT_BADADDR2.r b/test/unittest/error/tst.DTRACEFLT_BADADDR2.r
index 6c5fa119..afa91eb1 100644
--- a/test/unittest/error/tst.DTRACEFLT_BADADDR2.r
+++ b/test/unittest/error/tst.DTRACEFLT_BADADDR2.r
@@ -1,6 +1,6 @@
-The arguments are 3 1 1 16384
+The arguments are 4294967297 1 1 16384
The value of arg4 should be 1
The value of arg5 should be 16384
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.DTRACEFLT_DIVZERO.div.r b/test/unittest/error/tst.DTRACEFLT_DIVZERO.div.r
index e6d6afa2..671f4806 100644
--- a/test/unittest/error/tst.DTRACEFLT_DIVZERO.div.r
+++ b/test/unittest/error/tst.DTRACEFLT_DIVZERO.div.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): divide-by-zero in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): divide-by-zero in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.DTRACEFLT_DIVZERO.mod.r b/test/unittest/error/tst.DTRACEFLT_DIVZERO.mod.r
index e6d6afa2..671f4806 100644
--- a/test/unittest/error/tst.DTRACEFLT_DIVZERO.mod.r
+++ b/test/unittest/error/tst.DTRACEFLT_DIVZERO.mod.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): divide-by-zero in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): divide-by-zero in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.DTRACEFLT_UNKNOWN.r b/test/unittest/error/tst.DTRACEFLT_UNKNOWN.r
index 1e4fdd64..21a52283 100644
--- a/test/unittest/error/tst.DTRACEFLT_UNKNOWN.r
+++ b/test/unittest/error/tst.DTRACEFLT_UNKNOWN.r
@@ -1,5 +1,5 @@
-The arguments are 3 1 PC 1 64
+The arguments are 4294967297 1 PC 1 64
The value of arg4 = 0
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.clause_scope-begin-ended.r b/test/unittest/error/tst.clause_scope-begin-ended.r
index 8d57382e..d4c5ffd2 100644
--- a/test/unittest/error/tst.clause_scope-begin-ended.r
+++ b/test/unittest/error/tst.clause_scope-begin-ended.r
@@ -2,4 +2,4 @@ Error fired
Clause executed
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.clause_scope-begin.r b/test/unittest/error/tst.clause_scope-begin.r
index 8d57382e..d4c5ffd2 100644
--- a/test/unittest/error/tst.clause_scope-begin.r
+++ b/test/unittest/error/tst.clause_scope-begin.r
@@ -2,4 +2,4 @@ Error fired
Clause executed
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.clause_scope-regular.r b/test/unittest/error/tst.clause_scope-regular.r
index fff6fe1e..8f2adaf0 100644
--- a/test/unittest/error/tst.clause_scope-regular.r
+++ b/test/unittest/error/tst.clause_scope-regular.r
@@ -2,4 +2,4 @@ Error fired
Clause executed
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID nnn: profile:::tick-10ms): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 1 (ID nnn: profile:::tick-10ms): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.clause_scope-regular.r.p b/test/unittest/error/tst.clause_scope-regular.r.p
index 7659601b..8117b8ab 100755
--- a/test/unittest/error/tst.clause_scope-regular.r.p
+++ b/test/unittest/error/tst.clause_scope-regular.r.p
@@ -1,3 +1,11 @@
-#!/bin/sed -f
+#!/usr/bin/awk -f
+
# This report has a variable probe ID in it.
-s/ID [0-9][0-9]*: profile/ID nnn: profile/
+/^dtrace: error on enabled probe ID / {
+ $7 = and($7, 0xffffffff); # mask out the high 32 bits (variable prid)
+}
+
+{
+ sub("ID [0-9][0-9]*: profile", "ID nnn: profile");
+ print;
+}
diff --git a/test/unittest/error/tst.error.r b/test/unittest/error/tst.error.r
index 0d29bcc8..e349434d 100644
--- a/test/unittest/error/tst.error.r
+++ b/test/unittest/error/tst.error.r
@@ -1,4 +1,4 @@
Error fired
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/error/tst.errorend.r b/test/unittest/error/tst.errorend.r
index 73abf697..918abd84 100644
--- a/test/unittest/error/tst.errorend.r
+++ b/test/unittest/error/tst.errorend.r
@@ -2,4 +2,4 @@ Error fired
End fired after exit
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967298 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r b/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-before-beyond.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.r b/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.r
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-before-bottom.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r b/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-beyond-top.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.r b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.r
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-bottom.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r
index 4257f567..5078f69e 100644
--- a/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r
+++ b/test/unittest/funcs/alloca/err.alloca-bcopy-crossing-top.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-crossing-clauses.r b/test/unittest/funcs/alloca/err.alloca-crossing-clauses.r
index f5ff855d..420d9393 100644
--- a/test/unittest/funcs/alloca/err.alloca-crossing-clauses.r
+++ b/test/unittest/funcs/alloca/err.alloca-crossing-clauses.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #2 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-load-before-bottom.r b/test/unittest/funcs/alloca/err.alloca-load-before-bottom.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-load-before-bottom.r
+++ b/test/unittest/funcs/alloca/err.alloca-load-before-bottom.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-load-beyond-top.r b/test/unittest/funcs/alloca/err.alloca-load-beyond-top.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-load-beyond-top.r
+++ b/test/unittest/funcs/alloca/err.alloca-load-beyond-top.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r b/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r
+++ b/test/unittest/funcs/alloca/err.alloca-load-crossing-bottom.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r b/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r
+++ b/test/unittest/funcs/alloca/err.alloca-null-deref-lvalue.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-null-deref.r b/test/unittest/funcs/alloca/err.alloca-null-deref.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-null-deref.r
+++ b/test/unittest/funcs/alloca/err.alloca-null-deref.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r b/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r
index 4257f567..5078f69e 100644
--- a/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r
+++ b/test/unittest/funcs/alloca/err.alloca-scratch-exceeding-bcopy.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-store-before-bottom.r b/test/unittest/funcs/alloca/err.alloca-store-before-bottom.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-store-before-bottom.r
+++ b/test/unittest/funcs/alloca/err.alloca-store-before-bottom.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-store-beyond-top.r b/test/unittest/funcs/alloca/err.alloca-store-beyond-top.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-store-beyond-top.r
+++ b/test/unittest/funcs/alloca/err.alloca-store-beyond-top.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r b/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r
+++ b/test/unittest/funcs/alloca/err.alloca-store-crossing-bottom.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/bcopy/err.badbcopy1.r b/test/unittest/funcs/bcopy/err.badbcopy1.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/bcopy/err.badbcopy1.r
+++ b/test/unittest/funcs/bcopy/err.badbcopy1.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/bcopy/err.badbcopy4.r b/test/unittest/funcs/bcopy/err.badbcopy4.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/bcopy/err.badbcopy4.r
+++ b/test/unittest/funcs/bcopy/err.badbcopy4.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/bcopy/err.badbcopy5.r b/test/unittest/funcs/bcopy/err.badbcopy5.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/bcopy/err.badbcopy5.r
+++ b/test/unittest/funcs/bcopy/err.badbcopy5.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/bcopy/err.badbcopy6.r b/test/unittest/funcs/bcopy/err.badbcopy6.r
index 4257f567..5078f69e 100644
--- a/test/unittest/funcs/bcopy/err.badbcopy6.r
+++ b/test/unittest/funcs/bcopy/err.badbcopy6.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/bcopy/err.badbcopy7.r b/test/unittest/funcs/bcopy/err.badbcopy7.r
index 4257f567..5078f69e 100644
--- a/test/unittest/funcs/bcopy/err.badbcopy7.r
+++ b/test/unittest/funcs/bcopy/err.badbcopy7.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/bcopy/err.badbcopy8.r b/test/unittest/funcs/bcopy/err.badbcopy8.r
index 4257f567..5078f69e 100644
--- a/test/unittest/funcs/bcopy/err.badbcopy8.r
+++ b/test/unittest/funcs/bcopy/err.badbcopy8.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyin/err.badaddr.r b/test/unittest/funcs/copyin/err.badaddr.r
index ba4a4695..2ad8c0e1 100644
--- a/test/unittest/funcs/copyin/err.badaddr.r
+++ b/test/unittest/funcs/copyin/err.badaddr.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/copyin/err.badaddr.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyin/err.null_arg1.r b/test/unittest/funcs/copyin/err.null_arg1.r
index a806d107..40f558cd 100644
--- a/test/unittest/funcs/copyin/err.null_arg1.r
+++ b/test/unittest/funcs/copyin/err.null_arg1.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/copyin/err.null_arg1.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyinstr/err.badaddr.r b/test/unittest/funcs/copyinstr/err.badaddr.r
index 0f566d6e..30811f5c 100644
--- a/test/unittest/funcs/copyinstr/err.badaddr.r
+++ b/test/unittest/funcs/copyinstr/err.badaddr.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/copyinstr/err.badaddr.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyinstr/err.null_arg1.r b/test/unittest/funcs/copyinstr/err.null_arg1.r
index cdd7c22c..31dd9088 100644
--- a/test/unittest/funcs/copyinstr/err.null_arg1.r
+++ b/test/unittest/funcs/copyinstr/err.null_arg1.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/copyinstr/err.null_arg1.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyinto/err.badaddr.r b/test/unittest/funcs/copyinto/err.badaddr.r
index 11861e1f..f2e92fd7 100644
--- a/test/unittest/funcs/copyinto/err.badaddr.r
+++ b/test/unittest/funcs/copyinto/err.badaddr.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/copyinto/err.badaddr.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyinto/err.badsize.r b/test/unittest/funcs/copyinto/err.badsize.r
index ec4b062e..8e8c1579 100644
--- a/test/unittest/funcs/copyinto/err.badsize.r
+++ b/test/unittest/funcs/copyinto/err.badsize.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/copyinto/err.badsize.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid size ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/copyinto/err.null_arg1.r b/test/unittest/funcs/copyinto/err.null_arg1.r
index f568ee5c..346063c1 100644
--- a/test/unittest/funcs/copyinto/err.null_arg1.r
+++ b/test/unittest/funcs/copyinto/err.null_arg1.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/copyinto/err.null_arg1.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/err.badalloca.r b/test/unittest/funcs/err.badalloca.r
index 30224330..e2d013c8 100644
--- a/test/unittest/funcs/err.badalloca.r
+++ b/test/unittest/funcs/err.badalloca.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID NNN: profile:::tick-1): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 1 (ID NNN: profile:::tick-1): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/err.badalloca.r.p b/test/unittest/funcs/err.badalloca.r.p
index d7a88a39..15f99035 100755
--- a/test/unittest/funcs/err.badalloca.r.p
+++ b/test/unittest/funcs/err.badalloca.r.p
@@ -1,3 +1,11 @@
-#!/bin/sed -f
+#!/usr/bin/awk -f
-s/(ID [0-9]*/(ID NNN/g
+# This report has a variable probe ID in it.
+/^dtrace: error on enabled probe ID / {
+ $7 = and($7, 0xffffffff); # mask out the high 32 bits (variable prid)
+}
+
+{
+ sub("ID [0-9]*: profile", "ID NNN: profile");
+ print;
+}
diff --git a/test/unittest/funcs/err.link_ntopbadaddr.r b/test/unittest/funcs/err.link_ntopbadaddr.r
index b798b5e0..acdf019c 100644
--- a/test/unittest/funcs/err.link_ntopbadaddr.r
+++ b/test/unittest/funcs/err.link_ntopbadaddr.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/err.link_ntopbadarg.r b/test/unittest/funcs/err.link_ntopbadarg.r
index e386a67c..2a22d504 100644
--- a/test/unittest/funcs/err.link_ntopbadarg.r
+++ b/test/unittest/funcs/err.link_ntopbadarg.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): illegal operation in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): illegal operation in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null.r b/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null.r
+++ b/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null_const.r b/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null_const.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null_const.r
+++ b/test/unittest/funcs/inet_ntoa6/err.inet_ntoa6.arg1_null_const.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/strlen/tst.null.r b/test/unittest/funcs/strlen/tst.null.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/strlen/tst.null.r
+++ b/test/unittest/funcs/strlen/tst.null.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/strtok/tst.strtok_null.r b/test/unittest/funcs/strtok/tst.strtok_null.r
index 03226aa1..f7ae9418 100644
--- a/test/unittest/funcs/strtok/tst.strtok_null.r
+++ b/test/unittest/funcs/strtok/tst.strtok_null.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/strtok/tst.strtok_null.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/strtok/tst.strtok_nulldel.r b/test/unittest/funcs/strtok/tst.strtok_nulldel.r
index 70f8e4e2..d6bd31aa 100644
--- a/test/unittest/funcs/strtok/tst.strtok_nulldel.r
+++ b/test/unittest/funcs/strtok/tst.strtok_nulldel.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/strtok/tst.strtok_nulldel.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/strtok/tst.strtok_nullstr.r b/test/unittest/funcs/strtok/tst.strtok_nullstr.r
index a57b2469..0a555af5 100644
--- a/test/unittest/funcs/strtok/tst.strtok_nullstr.r
+++ b/test/unittest/funcs/strtok/tst.strtok_nullstr.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/strtok/tst.strtok_nullstr.d' matched 2 probes
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/funcs/strtok/tst.strtok_nullstr2.r b/test/unittest/funcs/strtok/tst.strtok_nullstr2.r
index d7df3aca..3ec82a69 100644
--- a/test/unittest/funcs/strtok/tst.strtok_nullstr2.r
+++ b/test/unittest/funcs/strtok/tst.strtok_nullstr2.r
@@ -4,4 +4,4 @@
-- @@stderr --
dtrace: script 'test/unittest/funcs/strtok/tst.strtok_nullstr2.d' matched 4 probes
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #2 at BPF pc NNN
diff --git a/test/unittest/funcs/substr/err.substr_null_arg1.r b/test/unittest/funcs/substr/err.substr_null_arg1.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/funcs/substr/err.substr_null_arg1.r
+++ b/test/unittest/funcs/substr/err.substr_null_arg1.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/pointers/err.AllocaOverrun.r b/test/unittest/pointers/err.AllocaOverrun.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/pointers/err.AllocaOverrun.r
+++ b/test/unittest/pointers/err.AllocaOverrun.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/pointers/err.BadAlign.r b/test/unittest/pointers/err.BadAlign.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/pointers/err.BadAlign.r
+++ b/test/unittest/pointers/err.BadAlign.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/pointers/err.InvalidAddress2.r b/test/unittest/pointers/err.InvalidAddress2.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/pointers/err.InvalidAddress2.r
+++ b/test/unittest/pointers/err.InvalidAddress2.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/pointers/err.InvalidAddress4.r b/test/unittest/pointers/err.InvalidAddress4.r
index 187543b6..2b87fa68 100644
--- a/test/unittest/pointers/err.InvalidAddress4.r
+++ b/test/unittest/pointers/err.InvalidAddress4.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
diff --git a/test/unittest/speculation/err.CommitWithInvalid.r b/test/unittest/speculation/err.CommitWithInvalid.r
index fc072417..d37b53c5 100644
--- a/test/unittest/speculation/err.CommitWithInvalid.r
+++ b/test/unittest/speculation/err.CommitWithInvalid.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): illegal operation in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): illegal operation in action #2 at BPF pc NNN
diff --git a/test/unittest/speculation/err.DiscardWithInvalid.r b/test/unittest/speculation/err.DiscardWithInvalid.r
index fc072417..d37b53c5 100644
--- a/test/unittest/speculation/err.DiscardWithInvalid.r
+++ b/test/unittest/speculation/err.DiscardWithInvalid.r
@@ -1,3 +1,3 @@
-- @@stderr --
-dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): illegal operation in action #2 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967297 (ID 1: dtrace:::BEGIN): illegal operation in action #2 at BPF pc NNN
diff --git a/test/unittest/speculation/tst.negcommit.r b/test/unittest/speculation/tst.negcommit.r
index 69f246a0..82f7a8f0 100644
--- a/test/unittest/speculation/tst.negcommit.r
+++ b/test/unittest/speculation/tst.negcommit.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/speculation/tst.negcommit.d' matched 2 probes
-dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): illegal operation in action #1 at BPF pc NNN
+dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): illegal operation in action #1 at BPF pc NNN
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 04/19] Eliminate dt_pdesc
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
2024-08-29 5:25 ` [PATCH 02/19] Add a hook for a provider-specific "update" function eugene.loh
2024-08-29 5:25 ` [PATCH 03/19] Widen the EPID to include the PRID eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-09-03 17:47 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 05/19] Add flag to dt_pid_create_probes() eugene.loh
` (15 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
The probe descriptions dt_pdesc are superfluous and are
eliminated here.
Consequently, we also no longer need the last args to
dt_epid_add()
dt_epid_lookup()
Nor so we need to track prid in dt_link_construct().
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_cc.c | 8 +-------
libdtrace/dt_consume.c | 3 +--
libdtrace/dt_handle.c | 2 +-
libdtrace/dt_impl.h | 7 ++-----
libdtrace/dt_map.c | 33 ++++++---------------------------
5 files changed, 11 insertions(+), 42 deletions(-)
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index cf3c5504..e66d76fb 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -959,7 +959,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
uint_t len = sdp->dtdo_brelen;
const dof_relodesc_t *rp = sdp->dtdo_breltab;
dof_relodesc_t *nrp = &dp->dtdo_breltab[rc];
- dtrace_id_t prid = prp->desc->id;
int no_deps = 0;
if (idp != NULL) {
@@ -1197,11 +1196,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
case DT_CONST_STACK_SKIP:
nrp->dofr_data = prp->prov->impl->stack_skip;
continue;
- default:
- /* probe name -> value is probe id */
- if (strchr(idp->di_name, ':') != NULL)
- prid = rp->dofr_data;
- continue;
}
continue;
@@ -1218,7 +1212,7 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
if (rdp == NULL)
return -1;
if (rdp->dtdo_ddesc != NULL) {
- nepid = dt_epid_add(dtp, rdp->dtdo_ddesc, prid);
+ nepid = dt_epid_add(dtp, rdp->dtdo_ddesc);
clid++;
} else
nepid = 0;
diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
index e3ce2d3b..88083b19 100644
--- a/libdtrace/dt_consume.c
+++ b/libdtrace/dt_consume.c
@@ -2211,8 +2211,7 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
pdat->dtpda_epid = epid;
pdat->dtpda_data = data;
- rval = dt_epid_lookup(dtp, epid, &pdat->dtpda_ddesc,
- &pdat->dtpda_pdesc);
+ rval = dt_epid_lookup(dtp, epid, &pdat->dtpda_ddesc);
if (rval != 0)
return dt_set_errno(dtp, EDT_BADEPID);
pdat->dtpda_pdesc = (dtrace_probedesc_t *)dtp->dt_probes[prid]->desc;
diff --git a/libdtrace/dt_handle.c b/libdtrace/dt_handle.c
index b1ba5f9f..79ecbac8 100644
--- a/libdtrace/dt_handle.c
+++ b/libdtrace/dt_handle.c
@@ -150,7 +150,7 @@ dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
*/
epid = DT_REC(uint64_t, 0);
- if (dt_epid_lookup(dtp, epid, &errdd, &errpd) != 0)
+ if (dt_epid_lookup(dtp, epid, &errdd) != 0)
return dt_set_errno(dtp, EDT_BADERROR);
errpd = (dtrace_probedesc_t *)dtp->dt_probes[epid>>32]->desc;
err.dteda_ddesc = errdd;
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index a2ae84f6..c2b18b0b 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -345,7 +345,6 @@ struct dtrace_hdl {
dtrace_epid_t dt_nextepid; /* next enabled probe ID to assign */
size_t dt_maxprobe; /* max enabled probe ID */
dtrace_datadesc_t **dt_ddesc; /* probe data descriptions */
- dtrace_probedesc_t **dt_pdesc; /* probe descriptions for enabled prbs */
size_t dt_maxagg; /* max aggregation ID */
dtrace_aggdesc_t **dt_adesc; /* aggregation descriptions */
struct dt_aggregate *dt_aggregate; /* aggregate */
@@ -774,10 +773,8 @@ extern dtrace_datadesc_t *dt_datadesc_hold(dtrace_datadesc_t *ddp);
extern void dt_datadesc_release(dtrace_hdl_t *, dtrace_datadesc_t *);
extern dtrace_datadesc_t *dt_datadesc_create(dtrace_hdl_t *);
extern int dt_datadesc_finalize(dtrace_hdl_t *, dtrace_datadesc_t *);
-extern dtrace_epid_t dt_epid_add(dtrace_hdl_t *, dtrace_datadesc_t *,
- dtrace_id_t);
-extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_datadesc_t **,
- dtrace_probedesc_t **);
+extern dtrace_epid_t dt_epid_add(dtrace_hdl_t *, dtrace_datadesc_t *);
+extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_datadesc_t **);
extern void dt_epid_destroy(dtrace_hdl_t *);
typedef void (*dt_cg_gap_f)(dt_pcb_t *, int);
extern uint32_t dt_rec_add(dtrace_hdl_t *, dt_cg_gap_f, dtrace_actkind_t,
diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
index 87ce5707..9011da5d 100644
--- a/libdtrace/dt_map.c
+++ b/libdtrace/dt_map.c
@@ -92,7 +92,7 @@ dt_datadesc_finalize(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
* description.
*/
dtrace_epid_t
-dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp, dtrace_id_t prid)
+dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
{
dtrace_id_t max = dtp->dt_maxprobe;
dtrace_epid_t epid;
@@ -101,27 +101,19 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp, dtrace_id_t prid)
if (epid >= max || dtp->dt_ddesc == NULL) {
dtrace_id_t nmax = max ? (max << 1) : 2;
dtrace_datadesc_t **nddesc;
- dtrace_probedesc_t **npdesc;
nddesc = dt_calloc(dtp, nmax, sizeof(void *));
- npdesc = dt_calloc(dtp, nmax, sizeof(void *));
- if (nddesc == NULL || npdesc == NULL) {
- dt_free(dtp, nddesc);
- dt_free(dtp, npdesc);
+ if (nddesc == NULL)
return dt_set_errno(dtp, EDT_NOMEM);
- }
if (dtp->dt_ddesc != NULL) {
size_t osize = max * sizeof(void *);
memcpy(nddesc, dtp->dt_ddesc, osize);
dt_free(dtp, dtp->dt_ddesc);
- memcpy(npdesc, dtp->dt_pdesc, osize);
- dt_free(dtp, dtp->dt_pdesc);
}
dtp->dt_ddesc = nddesc;
- dtp->dt_pdesc = npdesc;
dtp->dt_maxprobe = nmax;
}
@@ -129,14 +121,12 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp, dtrace_id_t prid)
return epid;
dtp->dt_ddesc[epid] = dt_datadesc_hold(ddp);
- dtp->dt_pdesc[epid] = (dtrace_probedesc_t *)dtp->dt_probes[prid]->desc;
return epid;
}
int
-dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp,
- dtrace_probedesc_t **pdp)
+dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp)
{
/* Remove the PRID portion of the EPID. */
epid &= 0xffffffff;
@@ -146,7 +136,6 @@ dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp,
dtrace_difo_t *rdp = dt_dlib_get_func_difo(dtp, dtp->dt_stmts[epid]->dtsd_clause);
*ddp = dt_datadesc_hold(rdp->dtdo_ddesc); // FIXME what releases the hold?
- *pdp = dtp->dt_pdesc[epid];
return (*ddp == NULL) ? -1 : 0;
}
@@ -156,26 +145,16 @@ dt_epid_destroy(dtrace_hdl_t *dtp)
{
size_t i;
- assert((dtp->dt_pdesc != NULL && dtp->dt_ddesc != NULL &&
- dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
- dtp->dt_ddesc == NULL && dtp->dt_maxprobe == 0));
-
- if (dtp->dt_pdesc == NULL)
- return;
+ assert((dtp->dt_ddesc != NULL && dtp->dt_maxprobe > 0) ||
+ (dtp->dt_ddesc == NULL && dtp->dt_maxprobe == 0));
for (i = 0; i < dtp->dt_maxprobe; i++) {
- if (dtp->dt_ddesc[i] == NULL) {
- assert(dtp->dt_pdesc[i] == NULL);
+ if (dtp->dt_ddesc[i] == NULL)
continue;
- }
dt_datadesc_release(dtp, dtp->dt_ddesc[i]);
- assert(dtp->dt_pdesc[i] != NULL);
}
- free(dtp->dt_pdesc);
- dtp->dt_pdesc = NULL;
-
free(dtp->dt_ddesc);
dtp->dt_ddesc = NULL;
dtp->dt_nextepid = 0;
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 05/19] Add flag to dt_pid_create_probes()
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (2 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 04/19] Eliminate dt_pdesc eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-09-18 20:33 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 06/19] Allow for USDT wildcards eugene.loh
` (14 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
The function dt_pid_create_probes() creates both pid and usdt probes.
Once the dtrace session has started, however, we only need to watch
for new usdt probes. So add a usdt_only argument to the function.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_cc.c | 2 +-
libdtrace/dt_pid.c | 4 ++--
libdtrace/dt_pid.h | 3 +--
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index e66d76fb..cfd4d3d1 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -282,7 +282,7 @@ dt_setcontext(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
isdigit(pdp->prv[strlen(pdp->prv) - 1]) &&
((pvp = dt_provider_lookup(dtp, pdp->prv)) == NULL ||
pvp->pv_flags & DT_PROVIDER_PID) &&
- dt_pid_create_probes((dtrace_probedesc_t *)pdp, dtp, yypcb) != 0) {
+ dt_pid_create_probes((dtrace_probedesc_t *)pdp, dtp, yypcb, 0) != 0) {
longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
}
diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
index 996543b1..3f3453af 100644
--- a/libdtrace/dt_pid.c
+++ b/libdtrace/dt_pid.c
@@ -1095,7 +1095,7 @@ dt_pid_get_pid(const dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
}
int
-dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
+dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb, int usdt_only)
{
char provname[DTRACE_PROVNAMELEN];
dt_proc_t *dpr;
@@ -1109,7 +1109,7 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
snprintf(provname, sizeof(provname), "pid%d", (int)pid);
- if (gmatch(provname, pdp->prv) != 0) {
+ if ((usdt_only == 0) && gmatch(provname, pdp->prv) != 0) {
if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING) < 0) {
dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB,
"failed to grab process %d", (int)pid);
diff --git a/libdtrace/dt_pid.h b/libdtrace/dt_pid.h
index 497c7751..dc200f4d 100644
--- a/libdtrace/dt_pid.h
+++ b/libdtrace/dt_pid.h
@@ -16,8 +16,7 @@
extern "C" {
#endif
-extern int dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *,
- dt_pcb_t *);
+extern int dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *, dt_pcb_t *, int);
extern int dt_pid_create_probes_module(dtrace_hdl_t *, dt_proc_t *);
extern pid_t dt_pid_get_pid(const dtrace_probedesc_t *, dtrace_hdl_t *, dt_pcb_t *,
dt_proc_t *);
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 06/19] Allow for USDT wildcards
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (3 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 05/19] Add flag to dt_pid_create_probes() eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-09-17 17:34 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 07/19] Create the BPF usdt_prids map eugene.loh
` (13 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
To look for pid probes, we can require that the provider description
should end in a digit. For USDT probes, however, there can be wildcard
descriptions. This includes a blank provider description as well as
a description that ends in an '*'.
So expand the criteria appropriately.
---
libdtrace/dt_cc.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index cfd4d3d1..a9934d10 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -278,8 +278,9 @@ dt_setcontext(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
* On an error, dt_pid_create_probes() will set the error message
* and tag -- we just have to longjmp() out of here.
*/
- if (pdp->prv && pdp->prv[0] &&
- isdigit(pdp->prv[strlen(pdp->prv) - 1]) &&
+ if (pdp->prv &&
+ (pdp->prv[0] == '\0' || isdigit(pdp->prv[strlen(pdp->prv) - 1]) ||
+ pdp->prv[strlen(pdp->prv) - 1] == '*') &&
((pvp = dt_provider_lookup(dtp, pdp->prv)) == NULL ||
pvp->pv_flags & DT_PROVIDER_PID) &&
dt_pid_create_probes((dtrace_probedesc_t *)pdp, dtp, yypcb, 0) != 0) {
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 07/19] Create the BPF usdt_prids map
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (4 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 06/19] Allow for USDT wildcards eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 5:25 ` [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline eugene.loh
` (12 subsequent siblings)
18 siblings, 0 replies; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
As USDT processes come and go, the overlying probes for an underlying
probe will change. Hence, we will move to a scheme in which an
underlying probe will walk all possible clauses it could call,
deciding at run time (using a bit mask for the overlying USDT probe)
which of the clauses to call.
In this patch, we create and update the BPF "usdt_prids" map. This
is a hash map, where:
*) the key (size: dtp->dt_usdt_pridsmap_ksz) comprises
- the PID of the firing process
- the PRID of the underlying probe
*) the value (size: dtp->dt_usdt_pridsmap_vsz) comprises
- the PRID over the overlying USDT probe
- a bit mask indicating which clauses should be called
As processes start up, we also add new overlying USDT probes,
requiring updates of the BPF "probes" and "strtab" maps and of
the list of enablings.
The underlying-probes "update" function is called sporadically.
The focus of this patch is the function. When it is called can
be tuned in future patches.
This patch guesses certain sizes very crudely. These sizes should
be handled more robustly in future patches:
*) The allocated size of the string table. For example,
new provider names have to be added as new processes
start.
*) The number of entries in the BPF "usdt_prids" map.
There is a little relief here in that, as processes
terminate, they can be removed from the map.
*) The size of the bit mask -- that is, the greatest
number of clauses an underlying probe might call.
This is relatively easy to extend; nevertheless,
that work is left for a future patch.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_bpf.c | 42 +++++-
libdtrace/dt_cc.c | 2 +-
libdtrace/dt_dlibs.c | 1 +
libdtrace/dt_impl.h | 6 +
libdtrace/dt_prov_uprobe.c | 266 +++++++++++++++++++++++++++++++++++++
libdtrace/dt_work.c | 2 +
6 files changed, 317 insertions(+), 2 deletions(-)
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 3f9c42ea..70803e3c 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -841,7 +841,8 @@ gmap_create_strtab(dtrace_hdl_t *dtp)
int fd, rc, err;
dtp->dt_strlen = dt_strtab_size(dtp->dt_ccstab);
- dtp->dt_rooffset = P2ROUNDUP(dtp->dt_strlen, 8);
+ dtp->dt_strmax = dtp->dt_strlen + 1000; // FIXME pad some arbitrary amount to account for new USDT probes as new processes start
+ dtp->dt_rooffset = P2ROUNDUP(dtp->dt_strmax, 8);
dtp->dt_rosize = dt_rodata_size(dtp->dt_rodata);
dtp->dt_zerooffset = P2ROUNDUP(dtp->dt_rooffset + dtp->dt_rosize, 8);
dtp->dt_zerosize = 0;
@@ -899,6 +900,7 @@ gmap_create_strtab(dtrace_hdl_t *dtp)
if (rc == -1)
return dt_bpf_error(dtp, "cannot update BPF map 'strtab': %s\n",
strerror(err));
+ dtp->dt_strtabmap_fd = fd;
return 0;
}
@@ -936,6 +938,43 @@ gmap_create_probes(dtrace_hdl_t *dtp)
dtp, "cannot update BPF map 'probes': %s\n",
strerror(errno));
}
+ dtp->dt_probesmap_fd = fd;
+
+ return 0;
+}
+
+/*
+ * Create the 'usdt_prids' BPF map.
+ *
+ * USDT-PRID information map. This is a global hash map for use
+ * with USDT probes. It is indexed by (pid, underlying probe ID).
+ * The value is a probe ID for the overlying USDT probe and a bit
+ * mask indicating which clauses to execute for this pid.
+ *
+ * WIP. Just make up some sizes for now.
+ *
+ * How big is a probe ID? Sometimes, it's a dtrace_id_t.
+ * And uts/common/sys/dtrace_types.h gives us "typedef uint32_t dtrace_id_t".
+ * Meanwhile, libdtrace/dt_impl.h has "uint32_t dt_probe_id".
+ * So either uint32_t or dtrace_id_t is fine.
+ *
+ * How big should our bit mask be? Start with 8*sizeof(long long) bits.
+ *
+ * How many entries should we allow? Start with 1000.
+ *
+ * Note that for a given (pid, PRID) key, there can be at most one
+ * overlying USDT probe.
+ */
+static int
+gmap_create_usdt_prids(dtrace_hdl_t *dtp)
+{
+ dtp->dt_usdt_pridsmap_fd = create_gmap(dtp, "usdt_prids", BPF_MAP_TYPE_HASH,
+ dtp->dt_usdt_pridsmap_ksz, dtp->dt_usdt_pridsmap_vsz, 1000);
+ if (dtp->dt_usdt_pridsmap_fd == -1)
+ return -1;
+
+ /* Populate the newly created map. FIXME: this is probably not the right place for this. */
+ dt_uprobe.update(dtp, NULL);
return 0;
}
@@ -1045,6 +1084,7 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp)
CREATE_MAP(scratchmem)
CREATE_MAP(strtab)
CREATE_MAP(probes)
+ CREATE_MAP(usdt_prids)
CREATE_MAP(gvars)
CREATE_MAP(lvars)
CREATE_MAP(dvars)
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index a9934d10..2510db86 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -1058,7 +1058,7 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
nrp->dofr_data = 0; /* FIXME */
continue;
case DT_CONST_STBSZ:
- nrp->dofr_data = dtp->dt_strlen;
+ nrp->dofr_data = dtp->dt_strmax;
continue;
case DT_CONST_STRSZ:
nrp->dofr_data =
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index bc883e11..060cf28b 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -66,6 +66,7 @@ static const dt_ident_t dt_bpf_symbols[] = {
DT_BPF_SYMBOL(lvars, DT_IDENT_PTR),
DT_BPF_SYMBOL(mem, DT_IDENT_PTR),
DT_BPF_SYMBOL(probes, DT_IDENT_PTR),
+ DT_BPF_SYMBOL(usdt_prids, DT_IDENT_PTR),
DT_BPF_SYMBOL(scratchmem, DT_IDENT_PTR),
DT_BPF_SYMBOL(specs, DT_IDENT_PTR),
DT_BPF_SYMBOL(state, DT_IDENT_PTR),
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index c2b18b0b..2378235c 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -287,6 +287,7 @@ struct dtrace_hdl {
dt_strtab_t *dt_ccstab; /* global string table (during compilation) */
dt_rodata_t *dt_rodata; /* global read-only data */
uint_t dt_strlen; /* global string table (runtime) size */
+ uint_t dt_strmax; /* global string table (runtime) size, allocated */
uint_t dt_rooffset; /* read-only data offset */
uint_t dt_rosize; /* read-only data size */
uint_t dt_zerooffset; /* zero region, offset */
@@ -397,6 +398,11 @@ struct dtrace_hdl {
int dt_aggmap_fd; /* file descriptor for the 'aggs' BPF map */
int dt_genmap_fd; /* file descriptor for the 'agggen' BPF map */
int dt_cpumap_fd; /* file descriptor for the 'cpuinfo' BPF map */
+ int dt_strtabmap_fd; /* file descriptor for the 'strtab' BPF map */
+ int dt_probesmap_fd; /* file descriptor for the 'probes' BPF map */
+ int dt_usdt_pridsmap_fd; /* file descriptor for the 'usdt_prids' BPF map */
+ int dt_usdt_pridsmap_ksz; /* 'usdt_prids' BPF map key size */
+ int dt_usdt_pridsmap_vsz; /* 'usdt_prids' BPF map value size */
dtrace_handle_err_f *dt_errhdlr; /* error handler, if any */
void *dt_errarg; /* error handler argument */
dtrace_handle_drop_f *dt_drophdlr; /* drop handler, if any */
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index cbde6a48..70e5c32d 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -37,8 +37,10 @@
#include "dt_list.h"
#include "dt_provider_tp.h"
#include "dt_probe.h"
+#include "dt_program.h"
#include "dt_pid.h"
#include "dt_string.h"
+#include "port.h"
/* Provider name for the underlying probes. */
static const char prvname[] = "uprobe";
@@ -63,6 +65,15 @@ typedef struct list_probe {
dt_probe_t *probe;
} list_probe_t;
+typedef struct usdt_prids_map_key {
+ pid_t pid;
+ dtrace_id_t uprid;
+} usdt_prids_map_key_t;
+typedef struct usdt_prids_map_val {
+ dtrace_id_t prid;
+ long long mask;
+} usdt_prids_map_val_t;
+
static const dtrace_pattr_t pattr = {
{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
@@ -77,6 +88,9 @@ dt_provimpl_t dt_usdt;
static int populate(dtrace_hdl_t *dtp)
{
+ dtp->dt_usdt_pridsmap_ksz = sizeof(usdt_prids_map_key_t);
+ dtp->dt_usdt_pridsmap_vsz = sizeof(usdt_prids_map_val_t);
+
if (dt_provider_create(dtp, dt_uprobe.name, &dt_uprobe, &pattr,
NULL) == NULL ||
dt_provider_create(dtp, dt_uprobe_is_enabled.name,
@@ -123,6 +137,257 @@ static void probe_destroy(dtrace_hdl_t *dtp, void *datap)
free_probe_list(dtp, datap);
}
+/*
+ * Clean up the BPF "usdt_prids" map.
+ */
+static int
+purge_BPFmap(dtrace_hdl_t *dtp)
+{
+ int fd = dtp->dt_usdt_pridsmap_fd;
+ usdt_prids_map_key_t key, nxt;
+ usdt_prids_map_val_t val;
+
+ /* Initialize key to a pid/uprid that cannot be found. */
+ key.pid = 0;
+ key.uprid = 0;
+
+ /* Loop over all entries. */
+ while (dt_bpf_map_next_key(fd, &key, &nxt) == 0) {
+ memcpy(&key, &nxt, sizeof(usdt_prids_map_key_t));
+
+ if (dt_bpf_map_lookup(fd, &key, &val) == -1)
+ return dt_set_errno(dtp, EDT_BPF);
+
+ /* Check if the process is still running. */
+ if (!Pexists(key.pid)) {
+ dt_bpf_map_delete(fd, &key); // FIXME: bpf_map_next_key() iteration restarts each time we delete an elem!!!
+ continue;
+ }
+
+ /*
+ * FIXME. There might be another case, where the process
+ * is still running, but some of its USDT probes are gone?
+ * So maybe we have to check for the existence of one of
+ * dtrace_probedesc_t *pdp = dtp->dt_probes[val.prid]->desc;
+ * char *prv = ...pdp->prv minus the numerial part;
+ *
+ * /run/dtrace/probes/$pid/$pdp->prv/$pdp->mod/$pdp->fun/$pdp->prb
+ * /run/dtrace/stash/dof-pid/$pid/0/parsed/$prv:$pdp->mod:$pdp->fun:$pdp->prb
+ * /run/dtrace/stash/dof-pid/$pid/.../parsed/$prv:$pdp->mod:$pdp->fun:$pdp->prb
+ */
+ }
+
+ return 0;
+}
+
+/*
+ * Grow the string table map. It includes the string table (which might
+ * grow due to new USDT probes). It also includes the read-only data and
+ * the block of zeros, but these remain fixed.
+ *
+ * FIXME Is there a danger of the BPF map update colliding with map reads?
+ */
+static int
+grow_strtab(dtrace_hdl_t *dtp)
+{
+ size_t sz = dtp->dt_zerooffset + dtp->dt_zerosize;
+ char *strtab;
+ uint8_t *buf, *end;
+ size_t strsize = dtp->dt_options[DTRACEOPT_STRSIZE];
+ uint32_t key = 0;
+ int rc, err;
+
+ strtab = dt_zalloc(dtp, sz);
+#if 0
+ // FIXME do something
+ if (strtab == NULL)
+ return dt_set_errno(dtp, EDT_NOMEM);
+#endif
+
+ /* Copy the string table data. */
+ dt_strtab_write(dtp->dt_ccstab, (dt_strtab_write_f *)dt_strtab_copystr, strtab);
+
+ /* Loop over the string table and truncate strings that are too long. */
+ buf = (uint8_t *)strtab;
+ end = buf + dtp->dt_strlen;
+ while (buf < end) {
+ uint_t len = strlen((char *)buf);
+
+ if (len > strsize)
+ buf[strsize] = '\0';
+
+ buf += len + 1;
+ }
+
+ /* Copy the read-only data. */
+ dt_rodata_write(dtp->dt_rodata, (dt_rodata_copy_f *)dt_rodata_copy, strtab + dtp->dt_rooffset);
+
+ rc = dt_bpf_map_update(dtp->dt_strtabmap_fd, &key, strtab);
+ err = errno;
+ dt_free(dtp, strtab);
+
+ // FIXME do something
+ if (rc == -1) {
+ strerror(err);
+ return -1;
+ // return dt_bpf_error(dtp, "cannot update BPF map 'strtab': %s\n", strerror(err));
+ }
+
+ return 0;
+}
+
+/*
+ * Update the uprobe provider.
+ */
+static void update_uprobe(dtrace_hdl_t *dtp, void *datap)
+{
+ dt_probe_t *prp;
+ dt_probe_t *prp_next;
+ int i, prid = dtp->dt_probe_id;
+ uint_t old_strlen = dtp->dt_strlen;
+ dt_pcb_t pcb;
+
+ /* Clear stale pids. */
+ purge_BPFmap(dtp);
+
+ /* Update dt_probes[] and dt_enablings. */
+ /*
+ * pcb is only used inside of dt_pid_error() to get:
+ * pcb->pcb_region
+ * pcb->pcb_filetag
+ * pcb->pcb_fileptr
+ * While pcb cannot be NULL, these other things apparently can be.
+ */
+ memset(&pcb, 0, sizeof(dt_pcb_t));
+ for (i = 0; i < dtp->dt_clause_nextid; i++)
+ dt_pid_create_probes(&dtp->dt_stmts[i]->dtsd_ecbdesc->dted_probe, dtp, &pcb, 1);
+
+ while (prid < dtp->dt_probe_id) {
+ dt_bpf_probe_t pinfo;
+ const dtrace_probedesc_t *pdp = dtp->dt_probes[prid]->desc;
+ int fd = dtp->dt_probesmap_fd;
+
+ dt_probe_enable(dtp, dtp->dt_probes[prid]);
+
+ pinfo.prv = dt_strtab_index(dtp->dt_ccstab, pdp->prv);
+ pinfo.mod = dt_strtab_index(dtp->dt_ccstab, pdp->mod);
+ pinfo.fun = dt_strtab_index(dtp->dt_ccstab, pdp->fun);
+ pinfo.prb = dt_strtab_index(dtp->dt_ccstab, pdp->prb);
+
+ if (dt_bpf_map_update(fd, &pdp->id, &pinfo) == -1)
+ assert(0); // FIXME do something here
+
+ prid++;
+ }
+
+ /* Grow the strtab if it has gotten bigger. */
+ dtp->dt_strlen = dt_strtab_size(dtp->dt_ccstab);
+
+ if (dtp->dt_strlen > dtp->dt_strmax)
+ assert(0); // FIXME handle this more gracefully
+ if (dtp->dt_strlen > old_strlen)
+ grow_strtab(dtp);
+
+ /* Review enablings. */
+ for (prp = dt_list_next(&dtp->dt_enablings); prp != NULL; prp = prp_next) {
+ pid_t pid;
+ list_probe_t *pup;
+
+ prp_next = dt_list_next(prp);
+
+ /* Make sure it is an overlying USDT probe. */
+ if (prp->prov->impl != &dt_usdt)
+ continue;
+
+ /* FIXME passing in NULL pcb and dpr wreaks havoc on error reporting? */
+ /*
+ * Nick writes:
+ * This is a general problem with running compiler-adjacent things outside
+ * compile time. I think we should adjust dt_pid_error() so that it works
+ * with NULL pcb and dpr at once, probably by using the code path for
+ * pcb != NULL and augmenting it so that it passes in NULL for the region and
+ * filename args and 0 for the lineno if pcb is NULL. (dt_set_errmsg can
+ * already handle this case.)
+ */
+ pid = dt_pid_get_pid(prp->desc, dtp, NULL, NULL);
+
+ if (!Pexists(pid)) {
+ /* Remove from enablings. */
+ dt_list_delete(&dtp->dt_enablings, prp);
+
+ /* Make it evident from the probe that it is not in enablings. */
+ ((dt_list_t *)prp)->dl_prev = NULL;
+ ((dt_list_t *)prp)->dl_next = NULL;
+
+ /* Free up its list of underlying probes. */
+ while ((pup = dt_list_next(prp->prv_data)) != NULL) {
+ dt_list_delete(prp->prv_data, pup);
+ dt_free(dtp, pup);
+ }
+ dt_free(dtp, prp->prv_data);
+ prp->prv_data = NULL;
+
+ /* Free up BPF "probes" map entry. */
+ dt_bpf_map_delete(dtp->dt_probesmap_fd, &prp->desc->id);
+
+ continue;
+ }
+
+ for (pup = prp->prv_data; pup != NULL; pup = dt_list_next(pup)) {
+ dt_probe_t *uprp = pup->probe;
+ long long mask = 0, bit = 1;
+ usdt_prids_map_key_t key;
+ usdt_prids_map_val_t val, oval;
+ dt_uprobe_t *upp = uprp->prv_data;
+
+ /*
+ * For is-enabled probes, the bit mask does not matter.
+ * It is possible that we have this underlying probe due to
+ * an overlying pid-offset probe and that we will not know
+ * until later, when some new pid is created, that we also
+ * have an overlying USDT is-enabled probe, but missing this
+ * optimization opportunity is okay.
+ */
+ if (uprp->prov->impl == &dt_uprobe && !(upp->flags & PP_IS_ENABLED)) {
+ int n;
+
+ for (n = 0; n < dtp->dt_clause_nextid; n++) {
+ if (dt_gmatch(prp->desc->prv, dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe.prv) &&
+ dt_gmatch(prp->desc->mod, dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe.mod) &&
+ dt_gmatch(prp->desc->fun, dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe.fun) &&
+ dt_gmatch(prp->desc->prb, dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe.prb))
+ mask |= bit;
+
+ bit <<= 1;
+ }
+ }
+
+ key.pid = pid;
+ key.uprid = uprp->desc->id;
+
+ val.prid = prp->desc->id;
+ val.mask = mask;
+
+ /* linux/bpf.h says error is -1, but it could be -2 */
+ if (dt_bpf_map_lookup(dtp->dt_usdt_pridsmap_fd, &key, &oval) < 0) {
+ /*
+ * Set the map entry.
+ */
+ // FIXME Check return value, but how should errors be handled?
+ dt_bpf_map_update(dtp->dt_usdt_pridsmap_fd, &key, &val);
+ } else if (val.prid != oval.prid || val.mask != oval.mask) {
+ /*
+ * This can happen when two overlying probes map to the same underlying probe for the same pid.
+ * E.g., pid:::entry and pid:::0, or pid:::$offset and usdt:::.
+ */
+ } else {
+ /*
+ * Nothing to do, it already is in the map.
+ */
+ }
+ }
+ }
+}
/*
* Look up or create an underlying (real) probe, corresponding directly to a
@@ -782,6 +1047,7 @@ dt_provimpl_t dt_uprobe = {
.probe_info = &probe_info,
.detach = &detach,
.probe_destroy = &probe_destroy_underlying,
+ .update = &update_uprobe,
};
/*
diff --git a/libdtrace/dt_work.c b/libdtrace/dt_work.c
index 599e2ae3..79da46fa 100644
--- a/libdtrace/dt_work.c
+++ b/libdtrace/dt_work.c
@@ -373,6 +373,8 @@ dtrace_work(dtrace_hdl_t *dtp, FILE *fp, dtrace_consume_probe_f *pfunc,
dtrace_workstatus_t rval;
int gen;
+dt_uprobe.update(dtp, NULL);
+
switch (dtrace_status(dtp)) {
case DTRACE_STATUS_EXITED:
case DTRACE_STATUS_STOPPED:
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (5 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 07/19] Create the BPF usdt_prids map eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-10-24 2:42 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 09/19] Use usdt_prids map to call clauses conditionally for USDT probes eugene.loh
` (11 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
An underlying probe could support all sorts of overlying probes:
- pid entry
- pid return
- pid offset
- USDT
- USDT is-enabled
The overlying probes belonging to an underlying probe match the
underlying probe -- except possibly in pid. So, an underlying
probe loops over its overlying probes, looking for a pid match.
The trampoline would look for only one match.
However, more than one overlying probe might match. Therefore,
change the loop to keep going even after a match has been found.
Incidentally, it is actually only pid offset probes that could
"collide" with any other overlying probes for a given pid:
-) pid return probes are implemented with uretprobes
and so cannot "collide" with any other probes
-) no two USDT probes -- is-enabled or not -- can map
to the same underlying probe for any pid
-) no USDT probe -- is-enabled or not -- can map to
to the same underlying probe as a pid entry
So, possibly one could optimize the trampoline -- e.g., by adding
BPF code to exit once two matches have been made.
Incidentally, there is a small error in the patch. The flag we
pass in to dt_cg_tramp_copy_args_from_regs() should depend on
whether the overlying probe is a pid or USDT probe. We used to
check PP_IS_FUNCALL, the upp could be for both. Instead of
fixing this problem, let us simply pretend it's a pid probe --
a later patch will move USDT probes to a different mechanism anyhow.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_uprobe.c | 53 +++++-------
test/unittest/pid/tst.entry_off0.sh | 125 ++++++++++++++++++++++++++++
2 files changed, 147 insertions(+), 31 deletions(-)
create mode 100755 test/unittest/pid/tst.entry_off0.sh
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index 70e5c32d..bc5545fb 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -687,45 +687,23 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
const list_probe_t *pop;
uint_t lbl_exit = pcb->pcb_exitlbl;
- dt_cg_tramp_prologue(pcb);
+ dt_cg_tramp_prologue(pcb); // call this only once... is PRID set/relocated correctly?
/*
* After the dt_cg_tramp_prologue() call, we have:
* // (%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);
- else
- dt_cg_tramp_copy_args_from_regs(pcb,
- !(upp->flags & PP_IS_FUNCALL));
-
- /*
- * Retrieve the PID of the process that caused the probe to fire.
- */
- emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
- emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
+ dt_cg_tramp_copy_regs(pcb); // call this only once for all clauses?
/*
- * Generate a composite conditional clause:
- *
- * 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 == ...) {
- * < ... >
- * }
+ * Loop over overlying probes, calling clauses for those that match:
*
- * 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.
+ * for overlying probes (that match except possibly for pid)
+ * if (pid matches) {
+ * dctx->mst->prid = PRID1;
+ * < any number of clause calls >
+ * }
*/
for (pop = dt_list_next(&upp->probes); pop != NULL;
pop = dt_list_next(pop)) {
@@ -740,6 +718,20 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
assert(idp != NULL);
+ /*
+ * Register copies. FIXME: What can be optimized?
+ */
+ if (upp->flags & PP_IS_RETURN)
+ dt_cg_tramp_copy_rval_from_regs(pcb);
+ else
+ dt_cg_tramp_copy_args_from_regs(pcb, 1);
+
+ /*
+ * Retrieve the PID of the process that caused the probe to fire.
+ */
+ emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
+ emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
+
/*
* Check whether this pid-provider probe serves the current
* process, and emit a sequence of clauses for it when it does.
@@ -747,7 +739,6 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
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));
emitl(dlp, lbl_next,
BPF_NOP());
}
diff --git a/test/unittest/pid/tst.entry_off0.sh b/test/unittest/pid/tst.entry_off0.sh
new file mode 100755
index 00000000..f1a75b6a
--- /dev/null
+++ b/test/unittest/pid/tst.entry_off0.sh
@@ -0,0 +1,125 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+
+dtrace=$1
+
+trig=`pwd`/test/triggers/ustack-tst-basic
+
+DIRNAME="$tmpdir/enter_off0.$$.$RANDOM"
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+# Run DTrace, dumping all probe functions and names, plus PC, in a.out.
+
+$dtrace $dt_flags -c $trig -n '
+pid$target:a.out::
+{
+ @[probefunc, probename, uregs[R_PC]] = count();
+}
+
+profile:::tick-1s
+{
+ exit(0);
+}' > D.out
+if [ $? -ne 0 ]; then
+ echo ERROR: dtrace
+ cat D.out
+ exit 1
+fi
+
+# Generate the expected list of functions for our trigger program.
+
+echo main > expected.tmp
+echo mycallee >> expected.tmp
+for x in 0 1 2 3 4 5 6 7 8 9 \
+ a b c d e f g h i j k l m n o p q r s t u v w x y z \
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z; do
+ echo myfunc_$x >> expected.tmp
+done
+sort expected.tmp > expected.txt
+
+# Check output for probe name "0" or "entry".
+
+awk '$2 == "0" || $2 == "entry"' D.out | awk '
+{
+ fun = $1;
+ prb = $2;
+ PC = $3;
+ cnt = $4;
+}
+
+# Check that the count is 1.
+cnt != 1 {
+ print "ERROR: count is not 1";
+ print;
+ exit(1);
+}
+
+# Check that we have not gotten the same (fun,prb) already.
+prb == "0" && fun in PC0 {
+ print "ERROR: already have offset 0 for this func";
+ print;
+ exit(1);
+}
+prb == "entry" && fun in PCentry {
+ print "ERROR: already have entry for this func";
+ print;
+ exit(1);
+}
+
+# Record the PC.
+prb == "0" { PC0[fun] = PC; }
+prb == "entry" { PCentry[fun] = PC; }
+
+# Do final matchup.
+END {
+ # Walk functions for the offset-0 probes.
+ for (fun in PC0) {
+ # Make sure each offset-0 probe has a matching entry probe.
+ if (!(fun in PCentry)) {
+ print "ERROR: func", fun, "has offset-0 but no entry";
+ exit(1);
+ }
+
+ # Make sure the matching probes report the same PC.
+ if (PC0[fun] != PCentry[fun]) {
+ print "ERROR: func", fun, "has mismatching PCs for offset-0 and entry:", PC0[fun], PCentry[fun];
+ exit(1);
+ }
+
+ # Dump the function name and delete these entries.
+ print fun;
+ delete PC0[fun];
+ delete PCentry[fun];
+ }
+
+ # Check if there are any leftover entry probes.
+ for (fun in PCentry) {
+ print "ERROR: func", fun, "has entry but no offset-0";
+ exit(1);
+ }
+}
+' | sort > awk.out
+
+# Report any problems.
+
+if ! diff -q awk.out expected.txt; then
+ echo ERROR: diff failure
+ echo ==== function list
+ cat awk.out
+ echo ==== expected function list
+ cat expected.txt
+ echo ==== diff
+ diff awk.out expected.txt
+ echo ==== DTrace output
+ cat D.out
+ exit 1
+fi
+
+echo success
+exit 0
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 09/19] Use usdt_prids map to call clauses conditionally for USDT probes
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (6 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 5:25 ` [PATCH 10/19] Remove the is-enabled provider eugene.loh
` (10 subsequent siblings)
18 siblings, 0 replies; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
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.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_uprobe.c | 159 +++++++++++++++++++++++++++----------
1 file changed, 116 insertions(+), 43 deletions(-)
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index bc5545fb..6403842f 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -681,11 +681,16 @@ static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp)
*/
static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
{
+ dtrace_hdl_t *dtp = pcb->pcb_hdl;
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 *usdt_prids = dt_dlib_get_map(dtp, "usdt_prids");
+ int n;
+
+ assert(usdt_prids != NULL);
dt_cg_tramp_prologue(pcb); // call this only once... is PRID set/relocated correctly?
@@ -697,14 +702,17 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
dt_cg_tramp_copy_regs(pcb); // call this only once for all clauses?
/*
- * Loop over overlying probes, calling clauses for those that match:
+ * pid probes.
+ *
+ * Loop over overlying pid probes, calling clauses for those that match:
*
- * for overlying probes (that match except possibly for pid)
+ * for overlying pid probes (that match except possibly for pid)
* if (pid matches) {
* dctx->mst->prid = PRID1;
* < any number of clause calls >
* }
*/
+
for (pop = dt_list_next(&upp->probes); pop != NULL;
pop = dt_list_next(pop)) {
const dt_probe_t *prp = pop->probe;
@@ -712,6 +720,9 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
pid_t pid;
dt_ident_t *idp;
+ if (prp->prov->impl != &dt_pid)
+ continue;
+
pid = dt_pid_get_pid(prp->desc, pcb->pcb_hdl, pcb, NULL);
assert(pid != -1);
@@ -743,6 +754,86 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
BPF_NOP());
}
+ /*
+ * USDT
+ */
+
+ /* In some cases, we know there are no USDT probes. */ // FIXME: add more checks
+ if (upp->flags & PP_IS_RETURN)
+ goto out;
+
+ dt_cg_tramp_copy_args_from_regs(pcb, 0);
+
+ /*
+ * Retrieve the PID of the process that caused the probe to fire.
+ */
+ emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
+ emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
+
+ /*
+ * Look up in the BPF 'usdt_prids' map. Space for the look-up key
+ * will be used on the BPF stack:
+ *
+ * offset value
+ *
+ * -sizeof(usdt_prids_map_key_t) pid (in %r0)
+ *
+ * -sizeof(usdt_prids_map_key_t) + sizeof(pid_t)
+ * ==
+ * -sizeof(dtrace_id_t) underlying-probe prid
+ */
+ emit(dlp, BPF_STORE(BPF_W, BPF_REG_9, (int)(-sizeof(usdt_prids_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, usdt_prids, DT_LBL_NONE, BPF_REG_1, usdt_prids->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(usdt_prids_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));
+
+ /* 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(usdt_prids_map_val_t, mask)));
+
+ /*
+ * Hold the bit mask in %r6 between clause calls.
+ */
+ for (n = 0; n < dtp->dt_clause_nextid; n++) {
+ dt_ident_t *idp = dtp->dt_stmts[n]->dtsd_clause;
+ uint_t lbl_next = dt_irlist_label(dlp);
+
+ /* 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));
+
+ /*
+ * if (*dctx.act != act) // ldw %r0, [%r9 + DCTX_ACT]
+ * goto exit; // ldw %r0, [%r0 + 0]
+ * // jne %r0, act, 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));
+ }
+
+out:
dt_cg_tramp_return(pcb);
return 0;
@@ -788,10 +879,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 *usdt_prids = dt_dlib_get_map(pcb->pcb_hdl, "usdt_prids");
+
+ assert(usdt_prids != NULL);
dt_cg_tramp_prologue(pcb);
@@ -800,7 +890,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);
/*
@@ -818,46 +907,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 'usdt_prids' 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(usdt_prids_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(usdt_prids_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(usdt_prids_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, usdt_prids, DT_LBL_NONE, BPF_REG_1, usdt_prids->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(usdt_prids_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
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 10/19] Remove the is-enabled provider
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (7 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 09/19] Use usdt_prids map to call clauses conditionally for USDT probes eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-10-24 15:18 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 11/19] Support USDT wildcard provider descriptions eugene.loh
` (9 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
The trampoline for the is-enabled provider is unnecessarily complicated.
We do not need dt_cg_tramp_copy_regs() since the copied values will not
be used. Nor do we need the (second) copy of regs[arg0] to mst->arg[0].
We can inline copyout_val().
Actually, we can simply consolidate the USDT and is-enabled providers.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_uprobe.c | 165 ++++++-------------------------------
1 file changed, 26 insertions(+), 139 deletions(-)
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index 6403842f..98d7b79b 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -44,7 +44,6 @@
/* Provider name for the underlying probes. */
static const char prvname[] = "uprobe";
-static const char prvname_is_enabled[] = "uprobe__is_enabled";
#define PP_IS_RETURN 1
#define PP_IS_FUNCALL 2
@@ -82,7 +81,6 @@ static const dtrace_pattr_t pattr = {
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
};
-dt_provimpl_t dt_uprobe_is_enabled;
dt_provimpl_t dt_pid;
dt_provimpl_t dt_usdt;
@@ -93,8 +91,6 @@ static int populate(dtrace_hdl_t *dtp)
if (dt_provider_create(dtp, dt_uprobe.name, &dt_uprobe, &pattr,
NULL) == NULL ||
- dt_provider_create(dtp, dt_uprobe_is_enabled.name,
- &dt_uprobe_is_enabled, &pattr, NULL) == NULL ||
dt_provider_create(dtp, dt_pid.name, &dt_pid, &pattr,
NULL) == NULL ||
dt_provider_create(dtp, dt_usdt.name, &dt_usdt, &pattr,
@@ -404,7 +400,6 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
dtrace_probedesc_t pd;
dt_probe_t *uprp;
dt_uprobe_t *upp;
- int is_enabled = 0;
/*
* The underlying probes (uprobes) represent the tracepoints that pid
@@ -427,8 +422,6 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
strcpy(prb, "return");
break;
case DTPPT_IS_ENABLED:
- is_enabled = 1;
- /* Fallthrough. */
case DTPPT_ENTRY:
case DTPPT_OFFSETS:
snprintf(prb, sizeof(prb), "%lx", psp->pps_off);
@@ -439,7 +432,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
}
pd.id = DTRACE_IDNONE;
- pd.prv = is_enabled ? prvname_is_enabled : prvname;
+ pd.prv = prvname;
pd.mod = mod;
pd.fun = psp->pps_fun;
pd.prb = prb;
@@ -631,21 +624,6 @@ static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp, int is_usdt)
dt_probe_enable(dtp, uprp);
}
- /*
- * If necessary, we need to enable is-enabled probes too (if they
- * exist).
- */
- if (is_usdt) {
- dtrace_probedesc_t pd;
- dt_probe_t *iep;
-
- memcpy(&pd, &prp->desc, sizeof(pd));
- pd.prv = prvname_is_enabled;
- iep = dt_probe_lookup(dtp, &pd);
- if (iep != NULL)
- dt_probe_enable(dtp, iep);
- }
-
/*
* Finally, ensure we're in the list of enablings as well.
* (This ensures that, among other things, the probes map
@@ -790,6 +768,29 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
emit(dlp, BPF_CALL_HELPER(BPF_FUNC_map_lookup_elem));
emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_exit));
+ if (upp->flags & PP_IS_ENABLED) {
+ /*
+ * Generate a BPF trampoline for an is-enabled probe. The is-enabled probe
+ * prototype looks like:
+ *
+ * int is_enabled(int *arg)
+ *
+ * The trampoline writes 1 into the location pointed to by the passed-in arg.
+ */
+ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), 1));
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, PT_REGS_ARG0));
+ emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP));
+ emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0)));
+ emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t)));
+ emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_write_user));
+
+ goto out;
+ }
+
+ /*
+ * Continue with normal USDT probes.
+ */
+
/* 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));
@@ -839,110 +840,11 @@ out:
return 0;
}
-/*
- * Copy the given immediate value into the address given by the specified probe
- * argument.
- */
-static void
-copyout_val(dt_pcb_t *pcb, uint_t lbl, uint32_t val, int arg)
-{
- dt_regset_t *drp = pcb->pcb_regs;
- dt_irlist_t *dlp = &pcb->pcb_ir;
-
- emitl(dlp, lbl, BPF_STORE_IMM(BPF_DW, BPF_REG_FP, DT_TRAMP_SP_SLOT(0),
- val));
-
- if (dt_regset_xalloc_args(drp) == -1)
- longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
- emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(arg)));
- emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP));
- emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0)));
- emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t)));
- dt_regset_xalloc(drp, BPF_REG_0);
- emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_write_user));
-
- /* XXX any point error-checking here? What can we possibly do? */
- dt_regset_free(drp, BPF_REG_0);
- dt_regset_free_args(drp);
-}
-
-/*
- * Generate a BPF trampoline for an is-enabled probe. The is-enabled probe
- * prototype looks like:
- *
- * int is_enabled(int *arg)
- *
- * The trampoline dereferences the passed-in arg and writes 1 into it if this is
- * one of the processes for which the probe is enabled.
- */
-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;
- dt_ident_t *usdt_prids = dt_dlib_get_map(pcb->pcb_hdl, "usdt_prids");
-
- assert(usdt_prids != NULL);
-
- dt_cg_tramp_prologue(pcb);
-
- /*
- * After the dt_cg_tramp_prologue() call, we have:
- * // (%r7 = dctx->mst)
- * // (%r8 = dctx->ctx)
- */
- dt_cg_tramp_copy_regs(pcb);
-
- /*
- * Copy in the first function argument, a pointer value to which
- * the is-enabled state of the probe will be written (necessarily
- * 1 if this probe is running at all).
- */
- emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, PT_REGS_ARG0));
- emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0));
-
- /*
- * Retrieve the PID of the process that caused the probe to fire.
- */
- emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
- emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
-
- /*
- * Look up in the BPF 'usdt_prids' map. Space for the look-up key
- * will be used on the BPF stack:
- *
- * offset value
- *
- * -sizeof(usdt_prids_map_key_t) pid (in %r0)
- *
- * -sizeof(usdt_prids_map_key_t) + sizeof(pid_t)
- * ==
- * -sizeof(dtrace_id_t) underlying-probe prid
- */
- emit(dlp, BPF_STORE(BPF_W, BPF_REG_9, (int)(-sizeof(usdt_prids_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, usdt_prids, DT_LBL_NONE, BPF_REG_1, usdt_prids->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(usdt_prids_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));
-
- /*
- * 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);
-
- return 0;
-}
-
static char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int flags)
{
char *name;
- if (asprintf(&name, "dt_pid%s/%c_%llx_%llx_%lx",
- flags & PP_IS_ENABLED ? "_is_enabled" : "",
+ if (asprintf(&name, "dt_pid/%c_%llx_%llx_%lx",
flags & PP_IS_RETURN ? 'r' : 'p', (unsigned long long)dev,
(unsigned long long)ino, (unsigned long)addr) < 0)
return NULL;
@@ -952,7 +854,7 @@ static char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int flags)
/*
* Create a uprobe for a given dev/ino, mapping filename, and address: the
- * uprobe may be a uretprobe or an is-enabled probe. Return the probe's name as
+ * uprobe may be a uretprobe. Return the probe's name as
* a new dynamically-allocated string, or NULL on error.
*/
static char *uprobe_create(dev_t dev, ino_t ino, const char *mapping_fn,
@@ -1114,21 +1016,6 @@ dt_provimpl_t dt_uprobe = {
.update = &update_uprobe,
};
-/*
- * Used for underlying is-enabled uprobes.
- */
-dt_provimpl_t dt_uprobe_is_enabled = {
- .name = prvname_is_enabled,
- .prog_type = BPF_PROG_TYPE_KPROBE,
- .populate = &populate,
- .load_prog = &dt_bpf_prog_load,
- .trampoline = &trampoline_is_enabled,
- .attach = &attach,
- .probe_info = &probe_info,
- .detach = &detach,
- .probe_destroy = &probe_destroy_underlying,
-};
-
/*
* Used for pid probes.
*/
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 11/19] Support USDT wildcard provider descriptions
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (8 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 10/19] Remove the is-enabled provider eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 5:25 ` [PATCH 12/19] Increase size of BPF probes map eugene.loh
` (8 subsequent siblings)
18 siblings, 0 replies; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
This is rudimentary support. We still need to:
- handle globs in dt_pid_create_probes_module()
- add process monitoring / inotify
- deal with FIXMEs
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_pid.c | 76 +++++++++++++++----
.../dtrace-util/tst.ListProbesFuncUSDT.sh | 1 -
.../dtrace-util/tst.ListProbesModuleUSDT.sh | 1 -
.../dtrace-util/tst.ListProbesNameUSDT.sh | 1 -
.../dtrace-util/tst.ListProbesProviderUSDT.sh | 1 -
test/unittest/usdt/tst.forker.sh | 1 -
6 files changed, 60 insertions(+), 21 deletions(-)
diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
index 3f3453af..356e02a4 100644
--- a/libdtrace/dt_pid.c
+++ b/libdtrace/dt_pid.c
@@ -605,6 +605,9 @@ dt_pid_fix_mod(dt_pid_probe_t *pp, dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
return pmp;
}
+/*
+ * Create pid probes for the specified process.
+ */
static int
dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
dt_pcb_t *pcb, dt_proc_t *dpr)
@@ -702,6 +705,7 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
return ret;
}
+
/*
* Read a file into a buffer and return it.
*/
@@ -780,8 +784,8 @@ validate_dof_record(const char *path, const dof_parsed_t *parsed,
/*
* Create underlying probes relating to the probespec passed on input.
*
- * If dpr is set, just set up probes relating to mappings found in that one
- * process. (dpr must in this case be locked.)
+ * dpr must be set and locked. Just set up probes relating to mappings found
+ * in this one process.
*
* Return 0 on success or -1 on error. (Failure to create specific underlying
* probes is not an error.)
@@ -795,9 +799,6 @@ dt_pid_create_usdt_probes(dtrace_hdl_t *dtp, dt_proc_t *dpr, dtrace_probedesc_t
char *probepath = NULL;
glob_t probeglob = {0};
- /*
- * Systemwide probing: not yet implemented.
- */
assert(dpr != NULL && dpr->dpr_proc);
assert(MUTEX_HELD(&dpr->dpr_lock));
@@ -1100,16 +1101,27 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
char provname[DTRACE_PROVNAMELEN];
dt_proc_t *dpr;
pid_t pid;
- int err = 0;
+ int err = 0, i, nmatches = 0;
+ glob_t globbuf;
+ char *globpat = NULL;
assert(pcb != NULL);
- if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1)
+ /* Exclude pid0 from being specifically requested. */
+ if (strcmp(pdp->prv, "pid0") == 0) {
+ dt_pid_error(dtp, pcb, NULL, D_PROC_BADPID,
+ "pid0 does not contain a valid pid");
return -1;
+ }
- snprintf(provname, sizeof(provname), "pid%d", (int)pid);
-
- if ((usdt_only == 0) && gmatch(provname, pdp->prv) != 0) {
+ /*
+ * Is this a pid$pid probe?
+ */
+ provname[0] = '\0';
+ if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) > 0 &&
+ snprintf(provname, sizeof(provname), "pid%d", (int)pid) > 0 &&
+ (usdt_only == 0) &&
+ gmatch(provname, pdp->prv) != 0) {
if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING) < 0) {
dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB,
"failed to grab process %d", (int)pid);
@@ -1119,14 +1131,45 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
dpr = dt_proc_lookup(dtp, pid);
assert(dpr != NULL);
+ // FIXME How should err be handled?
+ /*
+ * Nick writes (also, see USDT case below):
+ * Well, if you get an error, probe creation failed. I guess we do what
+ * DTrace normally does in that case: log an error about it and keep going
+ * as long as any probes at all are left...
+ */
err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr);
dt_proc_release_unlock(dtp, pid);
}
/*
- * If it's not strictly a pid provider, we might match a USDT provider.
+ * If it's strictly a pid provider, we're done.
+ */
+ if (pid > 0 && strcmp(provname, pdp->prv) == 0)
+ return err ? -1 : 0;
+
+ /*
+ * Look for USDT probes.
*/
- if (strcmp(provname, pdp->prv) != 0) {
+ asprintf(&globpat, "%s/probes/*/%s", dtp->dt_dofstash_path, pdp->prv[0] ? pdp->prv : "*");
+ nmatches = glob(globpat, 0, NULL, &globbuf) ? 0 : globbuf.gl_pathc;
+ for (i = 0; i < nmatches; i++) {
+ char *s = globbuf.gl_pathv[i]
+ + strlen(dtp->dt_dofstash_path)
+ + strlen("/probes/");
+ dtrace_probedesc_t pdptmp;
+
+ pdptmp.prv = strchr(s, '/') + 1;
+ pdptmp.mod = pdp->mod[0] == '\0' ? "*" : pdp->mod;
+ pdptmp.fun = pdp->fun[0] == '\0' ? "*" : pdp->fun;
+ pdptmp.prb = pdp->prb[0] == '\0' ? "*" : pdp->prb;
+
+ pid = atoll(s);
+
+ // Check, since dtprobed takes a while to clean up dead processes.
+ if (!Pexists(pid))
+ continue;
+
if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING |
DTRACE_PROC_SHORTLIVED) < 0) {
dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB,
@@ -1137,17 +1180,18 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
dpr = dt_proc_lookup(dtp, pid);
assert(dpr != NULL);
- err = dt_pid_create_usdt_probes(dtp, dpr, pdp, pcb);
+ // FIXME: How should err be handled?
+ err = dt_pid_create_usdt_probes(dtp, dpr, &pdptmp, pcb);
/*
* Put the module name in its canonical form.
*/
- dt_pid_fix_mod(NULL, pdp, dtp, dpr->dpr_pid);
+ dt_pid_fix_mod(NULL, &pdptmp, dtp, dpr->dpr_pid);
dt_proc_release_unlock(dtp, pid);
}
-
- /* (USDT systemwide probing goes here.) */
+ free(globpat);
+ globfree(&globbuf);
return err ? -1 : 0;
}
diff --git a/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh
index bd0552dc..99ae995e 100755
--- a/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh
+++ b/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh
@@ -5,7 +5,6 @@
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.
#
-# @@xfail: dtv2
##
#
diff --git a/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh
index 7b9c6a5f..5ae087fb 100755
--- a/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh
+++ b/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh
@@ -5,7 +5,6 @@
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.
#
-# @@xfail: dtv2
##
#
diff --git a/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh
index f9b1d8bf..5c0509d8 100755
--- a/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh
+++ b/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh
@@ -5,7 +5,6 @@
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.
#
-# @@xfail: dtv2
##
#
diff --git a/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh
index 644da2ac..6eae82ed 100755
--- a/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh
+++ b/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh
@@ -5,7 +5,6 @@
# Licensed under the Universal Permissive License v 1.0 as shown at
# http://oss.oracle.com/licenses/upl.
#
-# @@xfail: dtv2
##
#
diff --git a/test/unittest/usdt/tst.forker.sh b/test/unittest/usdt/tst.forker.sh
index 7cfa9eb5..92513eb5 100755
--- a/test/unittest/usdt/tst.forker.sh
+++ b/test/unittest/usdt/tst.forker.sh
@@ -7,7 +7,6 @@
#
#
# @@timeout: 120
-# @@xfail: dtv2 USDT wildcard
if [ $# != 1 ]; then
echo expected one argument: '<'dtrace-path'>'
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 12/19] Increase size of BPF probes map
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (9 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 11/19] Support USDT wildcard provider descriptions eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 20:30 ` [DTrace-devel] " Sam James
2024-10-08 22:15 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 13/19] Get rid of relocatable EPID, dt_nextepid, and dt_ddesc[] eugene.loh
` (7 subsequent siblings)
18 siblings, 2 replies; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
We are going to support discovery of new probes after dtrace is
launched. For example, there could be a pid or USDT probe with a
wildcard pid specification that could be matched by a process that
has not yet started. Or, a process could load a shared library.
This means the probe map will have to grow. For now, just wire in
some headroom, as ugly a hack as this is.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_bpf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 70803e3c..75e48962 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -920,7 +920,7 @@ gmap_create_probes(dtrace_hdl_t *dtp)
fd = create_gmap(dtp, "probes", BPF_MAP_TYPE_HASH, sizeof(uint32_t),
sizeof(dt_bpf_probe_t),
- dt_list_length(&dtp->dt_enablings));
+ dt_list_length(&dtp->dt_enablings) + 1000);
if (fd == -1)
return -1;
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 13/19] Get rid of relocatable EPID, dt_nextepid, and dt_ddesc[]
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (10 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 12/19] Increase size of BPF probes map eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-09-03 17:49 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 14/19] Ignore clauses in USDT trampoline if we know they are impossible eugene.loh
` (6 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
We no longer have to assign an EPID value during relocation. So we
no longer need dt_nextepid, dt_maxprobe, dt_ddesc[], dt_epid_add(),
or dt_epid_destroy() or to track an EPID during linking.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_bpf.h | 47 +++++++++++++++++-----------------
libdtrace/dt_cc.c | 20 +++++----------
libdtrace/dt_dlibs.c | 1 -
libdtrace/dt_impl.h | 5 ----
libdtrace/dt_map.c | 61 --------------------------------------------
libdtrace/dt_open.c | 3 ---
6 files changed, 29 insertions(+), 108 deletions(-)
diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
index 5b2df264..5981eb0e 100644
--- a/libdtrace/dt_bpf.h
+++ b/libdtrace/dt_bpf.h
@@ -32,30 +32,29 @@ extern "C" {
(dtp)->dt_bpffeatures |= (feat); \
} while (0)
-#define DT_CONST_EPID 1
-#define DT_CONST_PRID 2
-#define DT_CONST_CLID 3
-#define DT_CONST_ARGC 4
-#define DT_CONST_STBSZ 5
-#define DT_CONST_STRSZ 6
-#define DT_CONST_STKSIZ 7
-#define DT_CONST_BOOTTM 8
-#define DT_CONST_NSPEC 9
-#define DT_CONST_NCPUS 10
-#define DT_CONST_PC 11
-#define DT_CONST_TUPSZ 12
-#define DT_CONST_TASK_PID 13
-#define DT_CONST_TASK_TGID 14
-#define DT_CONST_TASK_REAL_PARENT 15
-#define DT_CONST_TASK_COMM 16
-#define DT_CONST_MUTEX_OWNER 17
-#define DT_CONST_RWLOCK_CNTS 18
-#define DT_CONST_DCTX_RODATA 19
-#define DT_CONST_RODATA_OFF 20
-#define DT_CONST_RODATA_SIZE 21
-#define DT_CONST_ZERO_OFF 22
-#define DT_CONST_STACK_OFF 23
-#define DT_CONST_STACK_SKIP 24
+#define DT_CONST_PRID 1
+#define DT_CONST_CLID 2
+#define DT_CONST_ARGC 3
+#define DT_CONST_STBSZ 4
+#define DT_CONST_STRSZ 5
+#define DT_CONST_STKSIZ 6
+#define DT_CONST_BOOTTM 7
+#define DT_CONST_NSPEC 8
+#define DT_CONST_NCPUS 9
+#define DT_CONST_PC 10
+#define DT_CONST_TUPSZ 11
+#define DT_CONST_TASK_PID 12
+#define DT_CONST_TASK_TGID 13
+#define DT_CONST_TASK_REAL_PARENT 14
+#define DT_CONST_TASK_COMM 15
+#define DT_CONST_MUTEX_OWNER 16
+#define DT_CONST_RWLOCK_CNTS 17
+#define DT_CONST_DCTX_RODATA 18
+#define DT_CONST_RODATA_OFF 19
+#define DT_CONST_RODATA_SIZE 20
+#define DT_CONST_ZERO_OFF 21
+#define DT_CONST_STACK_OFF 22
+#define DT_CONST_STACK_SKIP 23
#define DT_BPF_LOG_SIZE_DEFAULT (UINT32_MAX >> 8)
#define DT_BPF_LOG_SIZE_SMALL 4096
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index 2510db86..b801c87a 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -949,7 +949,7 @@ static int get_boottime() {
static int
dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
dt_ident_t *idp, const dtrace_difo_t *sdp, uint_t *pcp,
- uint_t *rcp, uint_t *vcp, dtrace_epid_t epid, uint_t clid)
+ uint_t *rcp, uint_t *vcp, uint_t clid)
{
uint_t pc = *pcp;
uint_t rc = *rcp;
@@ -1030,7 +1030,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
for (; len != 0; len--, rp++, nrp++) {
const char *name = dt_difo_getstr(sdp, rp->dofr_name);
dtrace_difo_t *rdp;
- dtrace_epid_t nepid;
int ipc;
idp = dt_dlib_get_sym(dtp, name);
@@ -1045,9 +1044,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
}
switch (idp->di_id) {
- case DT_CONST_EPID:
- nrp->dofr_data = epid;
- continue;
case DT_CONST_PRID:
nrp->dofr_data = prp->desc->id;
continue;
@@ -1212,13 +1208,10 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
rdp = dt_dlib_get_func_difo(dtp, idp);
if (rdp == NULL)
return -1;
- if (rdp->dtdo_ddesc != NULL) {
- nepid = dt_epid_add(dtp, rdp->dtdo_ddesc);
- clid++;
- } else
- nepid = 0;
+ if (rdp->dtdo_ddesc != NULL)
+ clid++; /* FIXME: dump this? */
ipc = dt_link_construct(dtp, prp, dp, idp, rdp, pcp,
- rcp, vcp, nepid, clid);
+ rcp, vcp, clid);
if (ipc == -1)
return -1;
@@ -1259,7 +1252,7 @@ dt_link_resolve(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
continue;
/*
- * We are only relocating constants (EPID and ARGC) and call
+ * We are only relocating constants and call
* instructions to functions that have been linked in.
*/
switch (idp->di_kind) {
@@ -1332,8 +1325,7 @@ dt_link(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
*/
insc = relc = varc = 0;
- rc = dt_link_construct(dtp, prp, fdp, idp, dp, &insc, &relc, &varc, 0,
- 0);
+ rc = dt_link_construct(dtp, prp, fdp, idp, dp, &insc, &relc, &varc, 0);
dt_dlib_reset(dtp, B_FALSE);
if (rc == -1)
goto fail;
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index 060cf28b..140ac9a6 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -74,7 +74,6 @@ static const dt_ident_t dt_bpf_symbols[] = {
DT_BPF_SYMBOL(tuples, DT_IDENT_PTR),
/* BPF internal identifiers */
- DT_BPF_SYMBOL_ID(EPID, DT_IDENT_SCALAR, DT_CONST_EPID),
DT_BPF_SYMBOL_ID(PRID, DT_IDENT_SCALAR, DT_CONST_PRID),
DT_BPF_SYMBOL_ID(CLID, DT_IDENT_SCALAR, DT_CONST_CLID),
DT_BPF_SYMBOL_ID(ARGC, DT_IDENT_SCALAR, DT_CONST_ARGC),
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 2378235c..3fa2b9d7 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -343,9 +343,6 @@ struct dtrace_hdl {
ctf_id_t dt_type_symaddr; /* cached CTF identifier for _symaddr type */
ctf_id_t dt_type_usymaddr; /* cached CTF ident. for _usymaddr type */
ctf_id_t dt_type_void; /* cached CTF identifier for void type */
- dtrace_epid_t dt_nextepid; /* next enabled probe ID to assign */
- size_t dt_maxprobe; /* max enabled probe ID */
- dtrace_datadesc_t **dt_ddesc; /* probe data descriptions */
size_t dt_maxagg; /* max aggregation ID */
dtrace_aggdesc_t **dt_adesc; /* aggregation descriptions */
struct dt_aggregate *dt_aggregate; /* aggregate */
@@ -779,9 +776,7 @@ extern dtrace_datadesc_t *dt_datadesc_hold(dtrace_datadesc_t *ddp);
extern void dt_datadesc_release(dtrace_hdl_t *, dtrace_datadesc_t *);
extern dtrace_datadesc_t *dt_datadesc_create(dtrace_hdl_t *);
extern int dt_datadesc_finalize(dtrace_hdl_t *, dtrace_datadesc_t *);
-extern dtrace_epid_t dt_epid_add(dtrace_hdl_t *, dtrace_datadesc_t *);
extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_datadesc_t **);
-extern void dt_epid_destroy(dtrace_hdl_t *);
typedef void (*dt_cg_gap_f)(dt_pcb_t *, int);
extern uint32_t dt_rec_add(dtrace_hdl_t *, dt_cg_gap_f, dtrace_actkind_t,
uint32_t, uint16_t, dt_pfargv_t *, uint64_t);
diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
index 9011da5d..26f101e4 100644
--- a/libdtrace/dt_map.c
+++ b/libdtrace/dt_map.c
@@ -85,46 +85,6 @@ dt_datadesc_finalize(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
return 0;
}
-/*
- * Associate a probe data description and probe description with an enabled
- * probe ID. This means that the given ID refers to the program matching the
- * probe data description being attached to the probe that matches the probe
- * description.
- */
-dtrace_epid_t
-dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
-{
- dtrace_id_t max = dtp->dt_maxprobe;
- dtrace_epid_t epid;
-
- epid = dtp->dt_nextepid++;
- if (epid >= max || dtp->dt_ddesc == NULL) {
- dtrace_id_t nmax = max ? (max << 1) : 2;
- dtrace_datadesc_t **nddesc;
-
- nddesc = dt_calloc(dtp, nmax, sizeof(void *));
- if (nddesc == NULL)
- return dt_set_errno(dtp, EDT_NOMEM);
-
- if (dtp->dt_ddesc != NULL) {
- size_t osize = max * sizeof(void *);
-
- memcpy(nddesc, dtp->dt_ddesc, osize);
- dt_free(dtp, dtp->dt_ddesc);
- }
-
- dtp->dt_ddesc = nddesc;
- dtp->dt_maxprobe = nmax;
- }
-
- if (dtp->dt_ddesc[epid] != NULL)
- return epid;
-
- dtp->dt_ddesc[epid] = dt_datadesc_hold(ddp);
-
- return epid;
-}
-
int
dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp)
{
@@ -140,27 +100,6 @@ dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp)
return (*ddp == NULL) ? -1 : 0;
}
-void
-dt_epid_destroy(dtrace_hdl_t *dtp)
-{
- size_t i;
-
- assert((dtp->dt_ddesc != NULL && dtp->dt_maxprobe > 0) ||
- (dtp->dt_ddesc == NULL && dtp->dt_maxprobe == 0));
-
- for (i = 0; i < dtp->dt_maxprobe; i++) {
- if (dtp->dt_ddesc[i] == NULL)
- continue;
-
- dt_datadesc_release(dtp, dtp->dt_ddesc[i]);
- }
-
- free(dtp->dt_ddesc);
- dtp->dt_ddesc = NULL;
- dtp->dt_nextepid = 0;
- dtp->dt_maxprobe = 0;
-}
-
uint32_t
dt_rec_add(dtrace_hdl_t *dtp, dt_cg_gap_f gapf, dtrace_actkind_t kind,
uint32_t size, uint16_t alignment, dt_pfargv_t *pfp, uint64_t arg)
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 8ae6cdfa..848141dd 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -739,8 +739,6 @@ dt_vopen(int version, int flags, int *errp,
dt_proc_hash_create(dtp);
dt_proc_signal_init(dtp);
dtp->dt_proc_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
- dtp->dt_nextepid = 1;
- dtp->dt_maxprobe = 0;
if (dt_aggregate_init(dtp) == -1)
return set_open_errno(dtp, errp, dtrace_errno(dtp));
dtp->dt_vmax = DT_VERS_LATEST;
@@ -1303,7 +1301,6 @@ dtrace_close(dtrace_hdl_t *dtp)
if (dtp->dt_poll_fd != -1)
close(dtp->dt_poll_fd);
- dt_epid_destroy(dtp);
dt_aggid_destroy(dtp);
dt_buffered_destroy(dtp);
dt_aggregate_destroy(dtp);
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 14/19] Ignore clauses in USDT trampoline if we know they are impossible
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (11 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 13/19] Get rid of relocatable EPID, dt_nextepid, and dt_ddesc[] eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 5:25 ` [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp eugene.loh
` (5 subsequent siblings)
18 siblings, 0 replies; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
An underlying probe might have to call all sorts of clauses if new
USDT processes start up. Currently, the underlying probe trampoline
simply loops over all clauses, deciding whether to call a clause
based on a run-time bit mask.
While this approach works, it can mean, e.g., that clauses are being
loaded unnecessarily into BPF programs, bloating code. It also means
that the trampoline is looping over unnecessarily many clauses.
Meanwhile, it is possible to know in certain cases that a clause
could never be called for a particular underlying probe. The
heuristics can be tricky, but that challenge can be faced incrementally.
Introduce an ignore_clause() function that, for an underlying probe,
determines whether some clause (denoted by index) can safely be
ignored.
The same ignore_clause() function should be called both during code
generation of the trampoline as well as during the construction of
the bit mask. Further, for a given clause n and underlying probe upp,
the function should always give the same output. The set of ignored
clauses should remain fixed over the lifetime of an underlying probe.
For now, conservatively, ignore_clause() ignores nothing. Later
patches will introduce heuristics for ignoring clauses.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_uprobe.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index 98d7b79b..883a3e9d 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -232,6 +232,17 @@ grow_strtab(dtrace_hdl_t *dtp)
return 0;
}
+/*
+ * Judge whether clause "n" could ever be called as a USDT probe
+ * for this underlying probe.
+ */
+static int
+ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp)
+{
+ /* To be safe, ignore nothing. */
+ return 0;
+}
+
/*
* Update the uprobe provider.
*/
@@ -348,6 +359,9 @@ static void update_uprobe(dtrace_hdl_t *dtp, void *datap)
int n;
for (n = 0; n < dtp->dt_clause_nextid; n++) {
+ if (ignore_clause(dtp, n, uprp))
+ continue;
+
if (dt_gmatch(prp->desc->prv, dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe.prv) &&
dt_gmatch(prp->desc->mod, dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe.mod) &&
dt_gmatch(prp->desc->fun, dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe.fun) &&
@@ -803,7 +817,12 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
*/
for (n = 0; n < dtp->dt_clause_nextid; n++) {
dt_ident_t *idp = dtp->dt_stmts[n]->dtsd_clause;
- uint_t lbl_next = dt_irlist_label(dlp);
+ uint_t lbl_next;
+
+ if (ignore_clause(dtp, n, uprp))
+ continue;
+
+ lbl_next = dt_irlist_label(dlp);
/* If the lowest %r6 bit is 0, skip over this clause. */
emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_6));
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (12 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 14/19] Ignore clauses in USDT trampoline if we know they are impossible eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 20:31 ` [DTrace-devel] " Sam James
2024-08-29 5:25 ` [PATCH 16/19] Ignore clauses: use underlying probe's function information eugene.loh
` (4 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
In ignore_clauses, for an underlying probe uprp, we try to
decide if we can safely ignore clause n.
Meanwhile, for some clauses, the probe description tells us the
clause will not be called for any USDT probe, regardless of the
underlying probe. For example, "syscall::write:" can safely be
ignored, for all uprp.
Add a dtsd_usdt variable to each statement to track status:
USDT_FLAG_UNINITIALIZED not yet initialized
USDT_FLAG_POSSIBLE clause could possibly be called
for some USDT probe
USDT_FLAG_IGNORE clause can safely be ignored for
all USDT probes
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_uprobe.c | 56 ++++++++++++++++++++++++++++++++++++--
libdtrace/dtrace.h | 1 +
2 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index 883a3e9d..454c53dc 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -27,6 +27,7 @@
*/
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
@@ -232,6 +233,10 @@ grow_strtab(dtrace_hdl_t *dtp)
return 0;
}
+#define USDT_FLAG_UNINITIALIZED 0
+#define USDT_FLAG_POSSIBLE 1
+#define USDT_FLAG_IGNORE 2
+
/*
* Judge whether clause "n" could ever be called as a USDT probe
* for this underlying probe.
@@ -239,7 +244,53 @@ grow_strtab(dtrace_hdl_t *dtp)
static int
ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp)
{
- /* To be safe, ignore nothing. */
+ dtrace_probedesc_t *pdp = &dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe;
+ int *usdt_stat = &dtp->dt_stmts[n]->dtsd_usdt;
+
+ /*
+ * Some clauses could never be called for a USDT probe,
+ * regardless of the underlying probe uprp. Cache this
+ * status in dt_stmts[n]->dtsd_usdt (pointed to by usdt_stat).
+ */
+ if (*usdt_stat == USDT_FLAG_UNINITIALIZED) {
+ char lastchar = pdp->prv[strlen(pdp->prv) - 1];
+
+ /*
+ * If the last char in the provider description is
+ * neither '*' nor a digit, it cannot be a USDT probe.
+ */
+ if (lastchar != '*' && !isdigit(lastchar)) {
+ *usdt_stat = USDT_FLAG_IGNORE;
+ return 1;
+ }
+
+ /*
+ * If the provider description is "pid[0-9]*", it
+ * is a pid probe, not USDT.
+ */
+ if (strncmp(pdp->prv, "pid", 3) == 0) {
+ int i, l = strlen(pdp->prv);
+
+ for (i = 3; i < l; i++)
+ if (!isdigit((pdp->prv[i])))
+ break;
+
+ if (i == l) {
+ *usdt_stat = USDT_FLAG_IGNORE;
+ return 1;
+ }
+ }
+
+ /* Otherwise, it is possibly a USDT probe. */
+ *usdt_stat = USDT_FLAG_POSSIBLE;
+ }
+ if (*usdt_stat == USDT_FLAG_IGNORE)
+ return 1;
+
+ /*
+ * If USDT_FLAG_POSSIBLE, try to use uprp.
+ */
+
return 0;
}
@@ -267,7 +318,8 @@ static void update_uprobe(dtrace_hdl_t *dtp, void *datap)
*/
memset(&pcb, 0, sizeof(dt_pcb_t));
for (i = 0; i < dtp->dt_clause_nextid; i++)
- dt_pid_create_probes(&dtp->dt_stmts[i]->dtsd_ecbdesc->dted_probe, dtp, &pcb, 1);
+ if (dtp->dt_stmts[i]->dtsd_usdt != USDT_FLAG_IGNORE)
+ dt_pid_create_probes(&dtp->dt_stmts[i]->dtsd_ecbdesc->dted_probe, dtp, &pcb, 1);
while (prid < dtp->dt_probe_id) {
dt_bpf_probe_t pinfo;
diff --git a/libdtrace/dtrace.h b/libdtrace/dtrace.h
index a23052e4..2de7067f 100644
--- a/libdtrace/dtrace.h
+++ b/libdtrace/dtrace.h
@@ -151,6 +151,7 @@ typedef struct dtrace_stmtdesc {
dtrace_attribute_t dtsd_stmtattr; /* statement attributes */
int dtsd_clauseflags; /* clause flags */
int dtsd_index; /* index in dtp->dt_stmts */
+ int dtsd_usdt; /* flags describing USDT use, see dt_prov_uprobe.c */
} dtrace_stmtdesc_t;
/* dtsd clause flags */
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 16/19] Ignore clauses: use underlying probe's function information
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (13 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-10-24 16:52 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 17/19] test: Add a pid-USDT test eugene.loh
` (3 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
libdtrace/dt_prov_uprobe.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
index 454c53dc..9d163d70 100644
--- a/libdtrace/dt_prov_uprobe.c
+++ b/libdtrace/dt_prov_uprobe.c
@@ -291,6 +291,11 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp)
* If USDT_FLAG_POSSIBLE, try to use uprp.
*/
+ /* We know what function we're in. It must match the probe description (unless "-"). */
+ if (strcmp(pdp->fun, "-") != 0 &&
+ !dt_gmatch(uprp->desc->fun, pdp->fun))
+ return 1;
+
return 0;
}
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 17/19] test: Add a pid-USDT test
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (14 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 16/19] Ignore clauses: use underlying probe's function information eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-08-29 20:32 ` [DTrace-devel] " Sam James
2024-08-29 5:25 ` [PATCH 18/19] test: Add a lazy USDT test eugene.loh
` (2 subsequent siblings)
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
This checks that pid entry, pid return, pid offset, USDT, and USDT
is-enabled probes can all coexist. Specifically, pid offset probes
can sit on the same PCs as pid entry, USDT, and USDT is-enabled
probes.
Note that PCs for pid return probes are apparently in the caller
function. I guess that's due to using uretprobe. I'm not convinced
yet that that isn't a bug. It isn't what Solaris did.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
test/unittest/usdt/tst.pidprobes.r | 1 +
test/unittest/usdt/tst.pidprobes.sh | 243 ++++++++++++++++++++++++++++
2 files changed, 244 insertions(+)
create mode 100644 test/unittest/usdt/tst.pidprobes.r
create mode 100755 test/unittest/usdt/tst.pidprobes.sh
diff --git a/test/unittest/usdt/tst.pidprobes.r b/test/unittest/usdt/tst.pidprobes.r
new file mode 100644
index 00000000..2e9ba477
--- /dev/null
+++ b/test/unittest/usdt/tst.pidprobes.r
@@ -0,0 +1 @@
+success
diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh
new file mode 100755
index 00000000..7eadb9b7
--- /dev/null
+++ b/test/unittest/usdt/tst.pidprobes.sh
@@ -0,0 +1,243 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+# This test verifies that USDT and pid probes can share underlying probes.
+
+dtrace=$1
+
+# Set up test directory.
+
+DIRNAME=$tmpdir/pidprobes.$$.$RANDOM
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+# Create test source files.
+
+cat > prov.d <<EOF
+provider pyramid {
+ probe entry(int, char, int, int);
+};
+EOF
+
+cat > main.c <<EOF
+#include <stdio.h>
+#include "prov.h"
+
+void foo() {
+ int n = 0;
+
+ PYRAMID_ENTRY(2, 'a', 16, 128);
+ if (PYRAMID_ENTRY_ENABLED())
+ n += 2;
+ PYRAMID_ENTRY(4, 'b', 32, 256);
+ if (PYRAMID_ENTRY_ENABLED())
+ n += 8;
+ printf("my result: %d\n", n);
+}
+
+int
+main(int argc, char **argv)
+{
+ foo();
+}
+EOF
+
+# Build the test program.
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ echo "failed to generate header file" >&2
+ exit 1
+fi
+cc $test_cppflags -c main.c
+if [ $? -ne 0 ]; then
+ echo "failed to compile test" >&2
+ exit 1
+fi
+$dtrace -G -64 -s prov.d main.o
+if [ $? -ne 0 ]; then
+ echo "failed to create DOF" >&2
+ exit 1
+fi
+cc $test_cppflags -o main main.o prov.o
+if [ $? -ne 0 ]; then
+ echo "failed to link final executable" >&2
+ exit 1
+fi
+
+# Check that the program output is 0 when the USDT probe is not enabled.
+# That is, the PYRAMID_ENTRY_ENABLED() is-enabled checks should not pass.
+
+./main > main.out
+echo "my result: 0" > main.out.expected
+if ! diff -q main.out main.out.expected > /dev/null; then
+ echo '"my result"' looks wrong when not using DTrace
+ echo === got ===
+ cat main.out
+ echo === expected ===
+ cat main.out.expected
+ exit 1
+fi
+
+# Run dtrace.
+
+$dtrace $dt_flags -q -c ./main -o dtrace.out -n '
+p*d$target::foo:
+{
+ printf("%d %s:%s:%s:%s %x\n", pid, probeprov, probemod, probefunc, probename, uregs[R_PC]);
+}' > main.out2
+if [ $? -ne 0 ]; then
+ echo "failed to run dtrace" >&2
+ cat main.out2
+ cat dtrace.out
+ exit 1
+fi
+echo "my result: 10" > main.out2.expected
+if ! diff -q main.out2 main.out2.expected > /dev/null; then
+ echo '"my result"' looks wrong when using DTrace
+ echo === got ===
+ cat main.out2
+ echo === expected ===
+ cat main.out2.expected
+ exit 1
+fi
+
+# Check that the program output is 10 when the USDT probe is enabled.
+# That is, the PYRAMID_ENTRY_ENABLED() is-enabled checks should pass.
+
+echo "my result: 10" > main.out2.expected
+
+if ! diff -q main.out2 main.out2.expected > /dev/null; then
+ echo '"my result"' looks wrong
+ echo === got ===
+ cat main.out2
+ echo === expected ===
+ cat main.out2.expected
+ exit 1
+fi
+
+# Get the reported pid.
+
+if [ `awk 'NF != 0 { print $1 }' dtrace.out | uniq | wc -l` -ne 1 ]; then
+ echo no unique pid
+ cat dtrace.out
+ exit 1
+fi
+pid=`awk 'NF != 0 { print $1 }' dtrace.out | uniq`
+
+# Disassemble foo().
+
+objdump -d main | awk '
+BEGIN { use = 0 } # start by not printing lines
+use == 1 && NF == 0 { exit } # if printing lines but hit a blank, then exit
+use == 1 { print } # print lines
+/<foo>:/ { use = 1 } # turn on printing when we hit "<foo>:" (without printing this line itself)
+' > disasm_foo.txt
+
+# From the disassembly, get the PCs for foo()'s instructions.
+
+pcs=`awk '{print strtonum("0x"$1)}' disasm_foo.txt`
+
+# From the disassembly, get the PCs for USDT probes.
+# Assume they are the first of several nop instructions in a row.
+
+usdt_pcs=`awk '
+BEGIN {
+ # actually, pc2 is never used
+ pc2 = -1; is_nop2 = 0; # pc2 is current instruction minus 2; is_nop2 is whether it is a nop
+ pc1 = -1; is_nop1 = 0; # pc1 is current instruction minus 1; is_nop1 is whether it is a nop
+}
+{
+ # pc0 is current instruction
+ pc0 = strtonum("0x"$1);
+
+ # is_nop0 is whether it is a nop (these heuristics may work for x86)
+ is_nop0 = 0;
+ if (NF == 3 &&
+ $2 == "90" &&
+ $3 == "nop") is_nop0 = 1;
+
+ # check for a USDT instruction (presumably, the first of multiple nop instructions)
+ if (is_nop2 == 0 &&
+ is_nop1 == 1 &&
+ is_nop0 == 1)
+ print pc1;
+
+ # prepare advance to next instruction
+ pc2 = pc1; is_nop2 = is_nop1;
+ pc1 = pc0; is_nop1 = is_nop0;
+}' disasm_foo.txt`
+
+if [ `echo $usdt_pcs | awk '{print NF}'` -ne 4 ]; then
+ # We expect 4 USDT probes (2 USDT and 2 is-enabled).
+ echo ERROR: expected 4 USDT probes but got $usdt_pcs
+ exit 1
+fi
+
+for pc in $usdt_pcs; do
+ # We expect all of the USDT probe PCs to be among the PCs in objdump output.
+ if echo $pcs | grep -q -vw $pc ; then
+ echo ERROR: cannot find USDT PC $pc in $pcs
+ exit 1
+ fi
+done
+
+# Get the PC for the pid return probe. (Just keep it in hex.)
+
+pc_return=`awk '/'$pid' pid'$pid':main:foo:return/ { print $NF }' dtrace.out`
+
+objdump -d main | awk '
+/^[0-9a-f]* <.*>:$/ { myfunc = $NF } # enter a new function
+/^ *'$pc_return'/ { print myfunc; exit(0) } # report the function $pc_return is in
+' > return_func.out
+
+echo "<main>:" > return_func.out.expected # since we use uretprobe for pid return probes, the PC will be in the caller
+
+if ! diff -q return_func.out return_func.out.expected > /dev/null; then
+ echo ERROR: return PC looks to be in the wrong function
+ echo === got ===
+ cat return_func.out
+ echo === expected ===
+ cat return_func.out.expected
+ exit 1
+fi
+
+# Build up a list of expected dtrace output:
+# - a blank line
+# - pid entry
+# - pid return
+# - pid offset
+# - two USDT probes (1st and 3rd; ignore 2nd and 4th since they are is-enabled probes)
+
+pc0=`echo $pcs | awk '{print $1}'`
+echo > dtrace.out.expected
+printf "$pid pid$pid:main:foo:entry %x\n" $pc0 >> dtrace.out.expected
+echo "$pid pid$pid:main:foo:return $pc_return" >> dtrace.out.expected
+for pc in $pcs; do
+ printf "$pid pid$pid:main:foo:%x %x\n" $(($pc - $pc0)) $pc >> dtrace.out.expected
+done
+echo $usdt_pcs | awk '{printf("'$pid' pyramid'$pid':main:foo:entry %x\n", $1);}' >> dtrace.out.expected
+echo $usdt_pcs | awk '{printf("'$pid' pyramid'$pid':main:foo:entry %x\n", $3);}' >> dtrace.out.expected
+
+# Sort and check.
+
+sort dtrace.out > dtrace.out.sorted
+sort dtrace.out.expected > dtrace.out.expected.sorted
+
+if ! diff -q dtrace.out.sorted dtrace.out.expected.sorted ; then
+ echo ERROR: dtrace output looks wrong
+ echo === got ===
+ cat dtrace.out.sorted
+ echo === expected ===
+ cat dtrace.out.expected.sorted
+ echo === diff ===
+ diff dtrace.out.sorted dtrace.out.expected.sorted
+ exit 1
+fi
+
+echo success
+exit 0
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 18/19] test: Add a lazy USDT test
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (15 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 17/19] test: Add a pid-USDT test eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-09-28 2:11 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 19/19] test: Add another USDT open/close test eugene.loh
2024-09-18 14:18 ` [PATCH 01/19] Change probes from having lists of clauses to lists of stmts Kris Van Hees
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
When new USDT processes start up, we do not immediately know
about their probes. Our detecting these processes is "lazy."
First, dtprobed has to see these processes and then dtrace has
to find them. Hence, many of our tests XFAIL.
Introduce a test that accounts for such laziness. That is,
the target program spins in "phase 1" waiting for USR1. Our
D script watches for a USDT probe in phase 1 and raises the
anticipated USR1.
Then we expect every USDT probe during phase 2 to fire.
Currently, another limitation is that at least one USDT process
has to be running when the dtrace session starts. So, start
one process first, then the dtrace session, then many more processes.
We start "many" processes so that we can filter on pids. Specifically,
we expect the phase 2 USDT probe to match the last digit of the pid.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
test/unittest/usdt/tst.lazy.r | 1 +
test/unittest/usdt/tst.lazy.sh | 245 +++++++++++++++++++++++++++++++++
2 files changed, 246 insertions(+)
create mode 100644 test/unittest/usdt/tst.lazy.r
create mode 100755 test/unittest/usdt/tst.lazy.sh
diff --git a/test/unittest/usdt/tst.lazy.r b/test/unittest/usdt/tst.lazy.r
new file mode 100644
index 00000000..2e9ba477
--- /dev/null
+++ b/test/unittest/usdt/tst.lazy.r
@@ -0,0 +1 @@
+success
diff --git a/test/unittest/usdt/tst.lazy.sh b/test/unittest/usdt/tst.lazy.sh
new file mode 100755
index 00000000..348a70f6
--- /dev/null
+++ b/test/unittest/usdt/tst.lazy.sh
@@ -0,0 +1,245 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+# This test verifies that USDT will see new processes, even if detection
+# is lazy.
+
+dtrace=$1
+
+# Set up test directory.
+
+DIRNAME=$tmpdir/lazy.$$.$RANDOM
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+# Create test source files.
+
+cat > prov.d <<EOF
+provider testprov {
+ probe foo();
+ probe bar(int, int, int);
+};
+EOF
+
+cat > main.c <<EOF
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include "prov.h"
+
+static int phase = 1;
+
+static void
+interrupt(int sig)
+{
+ phase = 2;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct sigaction act;
+ int i;
+ int nphase1 = 0, nphase1foo = 0, nphase1bar = 0;
+ int nphase2 = 0, nphase2foo = 0, nphase2bar = 0;
+
+ /* set the handler to listen for SIGUSR1 */
+ act.sa_handler = interrupt;
+ act.sa_flags = 0;
+ if (sigaction(SIGUSR1, &act, NULL)) {
+ printf("set handler failed\n");
+ return 1;
+ }
+
+ /* in phase 1, loop on probe "foo" to wait on USR1 */
+ while (phase == 1) {
+ nphase1++;
+ if (TESTPROV_FOO_ENABLED()) {
+ nphase1foo++;
+ phase = 2;
+ }
+ if (TESTPROV_BAR_ENABLED()) {
+ nphase1bar++;
+ phase = 2;
+ }
+ TESTPROV_FOO();
+ }
+
+ /* in phase 2, just loop over probe "bar" a fixed number of times */
+ for (int i = 0; i < 10; i++) {
+ nphase2++;
+ usleep(2000);
+ if (TESTPROV_FOO_ENABLED())
+ nphase2foo++;
+ usleep(2000);
+ if (TESTPROV_BAR_ENABLED())
+ nphase2bar++;
+ usleep(2000);
+ TESTPROV_BAR(i, i + 2, i * 2);
+ }
+
+ printf("%d: %d %d %d %d %d %d\n", getpid(),
+ nphase1, nphase1foo, nphase1bar, nphase2, nphase2foo, nphase2bar);
+
+ return 0;
+}
+EOF
+
+# Build the test program.
+
+$dtrace -h -s prov.d
+if [ $? -ne 0 ]; then
+ echo "failed to generate header file" >&2
+ exit 1
+fi
+cc $test_cppflags -c main.c
+if [ $? -ne 0 ]; then
+ echo "failed to compile test" >&2
+ exit 1
+fi
+$dtrace -G -64 -s prov.d main.o
+if [ $? -ne 0 ]; then
+ echo "failed to create DOF" >&2
+ exit 1
+fi
+cc $test_cppflags -o main main.o prov.o
+if [ $? -ne 0 ]; then
+ echo "failed to link final executable" >&2
+ exit 1
+fi
+
+# Check that the is-enabled probes are false when the USDT probes are not enabled.
+# That is, nphase1foo == nphase1bar == nphase2foo == nphase2bar == 0.
+# Also, nphase2 == 10.
+# Note that nphase1 will be undefined.
+
+./main > main.out &
+pid=$!
+sleep 1
+kill -USR1 $pid
+wait
+
+echo "$pid: undefined 0 0 10 0 0" > main.out.expected
+if ! awk '{ $2 = "undefined"; print }' main.out | diff -q - main.out.expected; then
+ echo program output looks wrong for the no-DTrace case
+ echo === got ===
+ cat main.out
+ echo === expected ===
+ cat main.out.expected
+ exit 1
+fi
+
+# Run dtrace.
+
+num=10
+
+# Start one process.
+./main > main.out0 &
+pids[0]=$!
+i=1
+
+# Figure out the pid's trailing digit.
+lastdigit=$((${pids[0]} % 10))
+
+# Start dtrace.
+$dtrace $dt_flags -wq -o dtrace.out -n '
+testprov*:::foo
+{
+ raise(SIGUSR1);
+}
+testprov*'$lastdigit':::bar
+{
+ @[pid, 0] = sum(arg0);
+ @[pid, 1] = sum(arg1);
+ @[pid, 2] = sum(arg2);
+}' &
+dtpid=$!
+sleep 2
+
+# Start remaining processes.
+while [ $i -lt $num ]; do
+ ./main > main.out$i &
+ pids[$i]=$!
+ i=$(($i + 1))
+done
+
+# Wait for processes to complete.
+
+i=0
+while [ $i -lt $num ]; do
+ wait ${pids[$i]}
+ i=$(($i + 1))
+done
+
+# Kill the dtrace process.
+
+kill $dtpid
+wait
+
+# Check the program output (main.out$i files).
+
+i=0
+while [ $i -lt $num ]; do
+ if [ $((${pids[$i]} % 10)) -eq $lastdigit ]; then
+ nphase2bar=10
+ else
+ nphase2bar=0
+ fi
+ echo "${pids[$i]}: undefined 0 0 10 10 $nphase2bar" > main.out$i.expected
+ awk '
+ $3 == "1" { $3 = 0 } # in phase 1, round 1 down to 0
+ $4 == "1" { $4 = 0 } # in phase 1, round 1 down to 0
+ { $2 = "undefined"; print }' main.out$i > main.out$i.post
+ if ! diff -q main.out$i.post main.out$i.expected; then
+ echo program output looks wrong for DTrace case $i
+ echo === was ===
+ cat main.out$i
+ echo === got ===
+ cat main.out$i.post
+ echo === expected ===
+ cat main.out$i.expected
+ exit 1
+ fi
+ i=$(($i + 1))
+done
+
+# Check the dtrace output.
+
+# regularize the dtrace output.
+awk 'NF != 0 { print $1, $2, $3 }' dtrace.out | sort > dtrace.out.post
+
+# determine what to expect
+
+i=0
+while [ $i -lt $num ]; do
+ if [ $((${pids[$i]} % 10)) -eq $lastdigit ]; then
+ echo ${pids[$i]} 0 45 >> dtrace.out.expected
+ echo ${pids[$i]} 1 65 >> dtrace.out.expected
+ echo ${pids[$i]} 2 90 >> dtrace.out.expected
+ fi
+
+ i=$(($i + 1))
+done
+
+# diff
+if ! sort dtrace.out.expected | diff -q - dtrace.out.post; then
+ echo dtrace output looks wrong for DTrace case $i
+ echo === was ===
+ cat dtrace.out
+ echo === got ===
+ cat dtrace.out.post
+ echo === expected ===
+ sort dtrace.out.expected
+ echo === diff ===
+ sort dtrace.out.expected | diff - dtrace.out.post
+ exit 1
+fi
+
+echo success
+
+exit 0
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* [PATCH 19/19] test: Add another USDT open/close test
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (16 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 18/19] test: Add a lazy USDT test eugene.loh
@ 2024-08-29 5:25 ` eugene.loh
2024-10-24 17:01 ` Kris Van Hees
2024-09-18 14:18 ` [PATCH 01/19] Change probes from having lists of clauses to lists of stmts Kris Van Hees
18 siblings, 1 reply; 44+ messages in thread
From: eugene.loh @ 2024-08-29 5:25 UTC (permalink / raw)
To: dtrace, dtrace-devel
From: Eugene Loh <eugene.loh@oracle.com>
There is already a test to check that "dtrace -l" sees USDT
probes come and go as an executable loads and unloads a shared
library with USDT probes. (See dlclose1.sh.) But it could
also fail if DTrace does not immediately notice USDT probes
coming or going.
Introduce a test that allows a grace period before DTrace
notices a USDT probe come or go.
There is a deadlib.so here. It is not needed for the test.
It simply mimics other, similar tests. The real thing to do
might be to put these shared libraries, common to multiple
tests, in test/triggers.
Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
test/unittest/usdt/tst.dlclose4.r | 5 +
test/unittest/usdt/tst.dlclose4.sh | 225 +++++++++++++++++++++++++++++
2 files changed, 230 insertions(+)
create mode 100644 test/unittest/usdt/tst.dlclose4.r
create mode 100755 test/unittest/usdt/tst.dlclose4.sh
diff --git a/test/unittest/usdt/tst.dlclose4.r b/test/unittest/usdt/tst.dlclose4.r
new file mode 100644
index 00000000..07927a4a
--- /dev/null
+++ b/test/unittest/usdt/tst.dlclose4.r
@@ -0,0 +1,5 @@
+as expected: USDT probe appeared
+as expected: USDT probe disappeared
+as expected: USDT probe appeared
+as expected: USDT probe disappeared
+success
diff --git a/test/unittest/usdt/tst.dlclose4.sh b/test/unittest/usdt/tst.dlclose4.sh
new file mode 100755
index 00000000..015bc52c
--- /dev/null
+++ b/test/unittest/usdt/tst.dlclose4.sh
@@ -0,0 +1,225 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+PATH=/usr/bin:/usr/sbin:$PATH
+
+#
+# In this test, we send alternating USR1 and USR2 signals to an executable
+# that responds by opening and closing, respectively, a shared library with
+# USDT probes. After each signal, we check "dtrace -l" to confirm that the
+# USDT probes are and are not listed, as expected.
+#
+
+dtrace=$1
+CC=/usr/bin/gcc
+CFLAGS=
+
+DIRNAME="$tmpdir/usdt-dlclose4.$$.$RANDOM"
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+#
+# Set up the source files.
+#
+
+cat > Makefile <<EOF
+all: main livelib.so deadlib.so
+
+main: main.o prov.o
+ \$(CC) -o main main.o -ldl
+
+main.o: main.c
+ \$(CC) -c main.c
+
+
+livelib.so: livelib.o prov.o
+ \$(CC) -shared -o livelib.so livelib.o prov.o -lc
+
+livelib.o: livelib.c prov.h
+ \$(CC) -c livelib.c
+
+prov.o: livelib.o prov.d
+ $dtrace -G -s prov.d livelib.o
+
+prov.h: prov.d
+ $dtrace -h -s prov.d
+
+
+deadlib.so: deadlib.o
+ \$(CC) -shared -o deadlib.so deadlib.o -lc
+
+deadlib.o: deadlib.c
+ \$(CC) -c deadlib.c
+
+clean:
+ rm -f main.o livelib.o prov.o prov.h deadlib.o
+
+clobber: clean
+ rm -f main livelib.so deadlib.so
+EOF
+
+cat > prov.d <<EOF
+provider test_prov {
+ probe go();
+};
+EOF
+
+cat > livelib.c <<EOF
+#include "prov.h"
+
+void
+go(void)
+{
+ TEST_PROV_GO();
+}
+EOF
+
+cat > deadlib.c <<EOF
+void
+go(void)
+{
+}
+EOF
+
+cat > main.c <<EOF
+#include <dlfcn.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void *live;
+
+/*
+ * Open and close livelib.so, thereby adding or removing USDT probes.
+ */
+
+static void my_open(int sig) {
+ live = dlopen("./livelib.so", RTLD_LAZY | RTLD_LOCAL);
+ if (live == NULL) {
+ printf("dlopen of livelib.so failed: %s\n", dlerror());
+ exit(1);
+ }
+}
+
+static void my_close(int sig) {
+ dlclose(live);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct sigaction act;
+
+ /*
+ * Set USR1 (USR2) to open (close) the livelib.so.
+ */
+ act.sa_flags = 0;
+ act.sa_handler = my_open;
+ if (sigaction(SIGUSR1, &act, NULL)) {
+ printf("set handler failed\n");
+ return 1;
+ }
+ act.sa_handler = my_close;
+ if (sigaction(SIGUSR2, &act, NULL)) {
+ printf("set handler failed\n");
+ return 1;
+ }
+
+ /*
+ * Listen for signals.
+ */
+ while (pause() == -1)
+ ;
+
+ return 0;
+}
+EOF
+
+#
+# Build.
+#
+
+make > /dev/null
+if [ $? -ne 0 ]; then
+ echo "failed to build" >& 2
+ exit 1
+fi
+
+# Define a function that looks for the USDT probe with "dtrace -l".
+# For debugging, one could also check:
+# ls /run/dtrace/probes/$pid/test_prov$pid/livelib.so/go/go
+# ls /run/dtrace/stash/dof-pid/$pid/*/parsed/test_prov:livelib.so:go:go
+
+function check_USDT_probes() {
+ $dtrace -lP test_prov$pid |& awk '
+ /ID *PROVIDER *MODULE *FUNCTION *NAME/ { next }
+ /test_prov'$pid' *livelib\.so *go *go/ { exit(0) }
+ /No probe matches description/ { exit(1) }'
+ return $?
+}
+
+# Define a function that checks loading the library:
+# send USR1 and wait up to 6 seconds for the USDT probe to appear.
+
+function load_lib() {
+ kill -s USR1 $pid
+ for iter in `seq 6`; do
+ sleep 1
+ if check_USDT_probes; then
+ iter=0
+ break
+ fi
+ done
+ if [[ $iter -ne 0 ]]; then
+ echo did not see USDT probe
+ kill -s KILL $pid
+ exit 1
+ fi
+ echo as expected: USDT probe appeared
+}
+
+# Define a function that checks unloading the library:
+# send USR2 and wait up to 6 seconds for the USDT probe to disappear.
+
+function unload_lib() {
+ kill -s USR2 $pid # send USR2 to unload library and USDT probe
+ for iter in `seq 6`; do
+ sleep 1
+ if ! check_USDT_probes; then
+ iter=0
+ break
+ fi
+ done
+ if [[ $iter -ne 0 ]]; then
+ echo still see USDT probe after timeout
+ kill -s KILL $pid
+ exit 1
+ fi
+ echo as expected: USDT probe disappeared
+}
+
+# Start the process.
+
+./main &
+pid=$!
+sleep 2
+
+# Check.
+
+load_lib
+unload_lib
+load_lib
+unload_lib
+
+# Clean up.
+
+kill -s KILL $pid
+wait $pid >& /dev/null
+
+echo success
+exit 0
--
2.43.5
^ permalink raw reply related [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 03/19] Widen the EPID to include the PRID
2024-08-29 5:25 ` [PATCH 03/19] Widen the EPID to include the PRID eugene.loh
@ 2024-08-29 20:28 ` Sam James
2024-08-29 20:38 ` Kris Van Hees
0 siblings, 1 reply; 44+ messages in thread
From: Sam James @ 2024-08-29 20:28 UTC (permalink / raw)
To: eugene.loh--- via DTrace-devel; +Cc: dtrace, eugene.loh
"eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> Each output record has an EPID associated with it. When the consumer
> reads a record, it uses the EPID to look up both a PRID (so it can
> report PRID and probe function and name) and a data description.
> During code generation, the PRID and data description are known,
> and so the EPID is set during relocation.
>
> However, we want to support underlying probes that trigger for PRIDs
> that will be discovered at run time. So, expand the EPID to 64 bits:
>
> *) the lower half, known at code generation, will index into an
> array dtp->dt_stmts[] of statements, which have information
> about probe descriptions, data descriptions, and clauses to call
>
> *) the upper half will have the PRID, which will be discovered
> at run time
>
> Statement descriptions include a new member dtsd_index, which is
> the index to dtp->dt_stmts[].
>
> The consumer gets information about the firing probe from the PRID,
> an index to dtp->dt_probes[].
>
> The lower half "EPID" depends only on the statement and no longer
> on the specific probe that is firing. Its value is known at code
> generation for a compiled clause. It no longer needs to be set in
> relocation; that relocation will be removed in a future patch.
>
> The buffer memory pointed to by dctx->buf is rearranged so that EPID
> will (still) fall on an 8-byte boundary but now take up 8 bytes.
>
> We do not need to expand:
>
> - the mstate (since it already had the PRID)
>
> Rename mstate's epid to be a statement ID, stid. When
> the producer needs the epid, it can construct it from
> mst->prid and mst->stid.
>
> - the output buffer (since it already had unused padding)
>
> The new, wider EPID is seen for the built-in variable epid as well
> as the epid that the consumer reads.
>
> The probe descriptions dt_pdesc become superfluous and will be
> eliminated in a future patch.
>
> Update test files:
>
> - Where the upper 32 bits of the EPID are known (since the PRID
> corresponds to a dtrace::: probe), update the expected EPID in
> the .r files.
>
> - Where the upper 32 bits of the EPID are not known, add .r.p
> processing to filter those bits out before comparing to known
> results in .r files.
>
> - Increase expected EPID width.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> bpf/get_bvar.c | 6 ++-
> bpf/probe_error.c | 2 +-
> include/dtrace/universal.h | 2 +-
> libdtrace/dt_bpf.c | 2 -
> libdtrace/dt_cc.c | 13 ++---
> libdtrace/dt_cg.c | 49 +++++++++++--------
> libdtrace/dt_consume.c | 28 +++++++----
> libdtrace/dt_dctx.h | 16 +++---
> libdtrace/dt_handle.c | 9 ++--
> libdtrace/dt_impl.h | 1 +
> libdtrace/dt_map.c | 11 +++--
> libdtrace/dt_open.c | 2 +-
> libdtrace/dt_program.c | 7 +++
> libdtrace/dtrace.h | 1 +
> test/demo/dtrace/error.r | 2 +-
> test/stress/buffering/tst.resize3-manual.r | 2 +-
> test/stress/buffering/tst.resize3.r | 2 +-
> test/unittest/actions/setopt/tst.badopt.r | 14 +++---
> .../arrays/tst.declared-bounds.runtime_out.r | 2 +-
> test/unittest/codegen/err.deref_0.r | 2 +-
> test/unittest/codegen/err.deref_1.r | 2 +-
> test/unittest/codegen/err.deref_i0.r | 2 +-
> test/unittest/codegen/err.deref_i1.r | 2 +-
> .../unittest/codegen/err.deref_string-assoc.r | 2 +-
> test/unittest/codegen/err.deref_string-gvar.r | 2 +-
> test/unittest/codegen/err.deref_string-lvar.r | 2 +-
> test/unittest/codegen/err.deref_string-tvar.r | 2 +-
> .../codegen/err.str_NULL_plus_offset-assoc.r | 2 +-
> .../codegen/err.str_NULL_plus_offset-lvar.r | 2 +-
> .../codegen/err.str_NULL_plus_offset-tvar.r | 2 +-
> .../codegen/err.str_NULL_plus_offset.r | 2 +-
> test/unittest/disasm/tst.vartab-bvar.r | 2 +-
> test/unittest/drops/drp.DTRACEDROP_DBLERROR.r | 2 +-
> .../tst.DTRACEFLT_BADADDR.null_ptr_field.r | 2 +-
> test/unittest/error/tst.DTRACEFLT_BADADDR.r | 4 +-
> test/unittest/error/tst.DTRACEFLT_BADADDR2.r | 4 +-
> .../error/tst.DTRACEFLT_DIVZERO.div.r | 2 +-
> .../error/tst.DTRACEFLT_DIVZERO.mod.r | 2 +-
> test/unittest/error/tst.DTRACEFLT_UNKNOWN.r | 4 +-
> .../error/tst.clause_scope-begin-ended.r | 2 +-
> test/unittest/error/tst.clause_scope-begin.r | 2 +-
> .../unittest/error/tst.clause_scope-regular.r | 2 +-
> .../error/tst.clause_scope-regular.r.p | 12 ++++-
> test/unittest/error/tst.error.r | 2 +-
> test/unittest/error/tst.errorend.r | 2 +-
> .../alloca/err.alloca-bcopy-before-beyond.r | 2 +-
> .../alloca/err.alloca-bcopy-before-bottom.r | 2 +-
> .../alloca/err.alloca-bcopy-beyond-top.r | 2 +-
> .../alloca/err.alloca-bcopy-crossing-bottom.r | 2 +-
> .../alloca/err.alloca-bcopy-crossing-top.r | 2 +-
> .../alloca/err.alloca-crossing-clauses.r | 2 +-
> .../alloca/err.alloca-load-before-bottom.r | 2 +-
> .../funcs/alloca/err.alloca-load-beyond-top.r | 2 +-
> .../alloca/err.alloca-load-crossing-bottom.r | 2 +-
> .../alloca/err.alloca-null-deref-lvalue.r | 2 +-
> .../funcs/alloca/err.alloca-null-deref.r | 2 +-
> .../err.alloca-scratch-exceeding-bcopy.r | 2 +-
> .../alloca/err.alloca-store-before-bottom.r | 2 +-
> .../alloca/err.alloca-store-beyond-top.r | 2 +-
> .../alloca/err.alloca-store-crossing-bottom.r | 2 +-
> test/unittest/funcs/bcopy/err.badbcopy1.r | 2 +-
> test/unittest/funcs/bcopy/err.badbcopy4.r | 2 +-
> test/unittest/funcs/bcopy/err.badbcopy5.r | 2 +-
> test/unittest/funcs/bcopy/err.badbcopy6.r | 2 +-
> test/unittest/funcs/bcopy/err.badbcopy7.r | 2 +-
> test/unittest/funcs/bcopy/err.badbcopy8.r | 2 +-
> test/unittest/funcs/copyin/err.badaddr.r | 2 +-
> test/unittest/funcs/copyin/err.null_arg1.r | 2 +-
> test/unittest/funcs/copyinstr/err.badaddr.r | 2 +-
> test/unittest/funcs/copyinstr/err.null_arg1.r | 2 +-
> test/unittest/funcs/copyinto/err.badaddr.r | 2 +-
> test/unittest/funcs/copyinto/err.badsize.r | 2 +-
> test/unittest/funcs/copyinto/err.null_arg1.r | 2 +-
> test/unittest/funcs/err.badalloca.r | 2 +-
> test/unittest/funcs/err.badalloca.r.p | 12 ++++-
> test/unittest/funcs/err.link_ntopbadaddr.r | 2 +-
> test/unittest/funcs/err.link_ntopbadarg.r | 2 +-
> .../inet_ntoa6/err.inet_ntoa6.arg1_null.r | 2 +-
> .../err.inet_ntoa6.arg1_null_const.r | 2 +-
> test/unittest/funcs/strlen/tst.null.r | 2 +-
> test/unittest/funcs/strtok/tst.strtok_null.r | 2 +-
> .../funcs/strtok/tst.strtok_nulldel.r | 2 +-
> .../funcs/strtok/tst.strtok_nullstr.r | 2 +-
> .../funcs/strtok/tst.strtok_nullstr2.r | 2 +-
> .../funcs/substr/err.substr_null_arg1.r | 2 +-
> test/unittest/pointers/err.AllocaOverrun.r | 2 +-
> test/unittest/pointers/err.BadAlign.r | 2 +-
> test/unittest/pointers/err.InvalidAddress2.r | 2 +-
> test/unittest/pointers/err.InvalidAddress4.r | 2 +-
> .../speculation/err.CommitWithInvalid.r | 2 +-
> .../speculation/err.DiscardWithInvalid.r | 2 +-
> test/unittest/speculation/tst.negcommit.r | 2 +-
> 92 files changed, 197 insertions(+), 146 deletions(-)
>
> diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
> index a0c04f3a..e9733bb1 100644
> --- a/bpf/get_bvar.c
> +++ b/bpf/get_bvar.c
> @@ -48,8 +48,10 @@ noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx)
> mst->tstamp = bpf_ktime_get_ns();
>
> return mst->tstamp;
> - case DIF_VAR_EPID:
> - return mst->epid;
> + case DIF_VAR_EPID: {
> + uint64_t val = mst->prid;
> + return (val << 32) | mst->stid;
> + }
> case DIF_VAR_ID:
> return mst->prid;
> case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2:
> diff --git a/bpf/probe_error.c b/bpf/probe_error.c
> index ee1a1793..fba779a8 100644
> --- a/bpf/probe_error.c
> +++ b/bpf/probe_error.c
> @@ -29,7 +29,7 @@ noinline void dt_probe_error(const dt_dctx_t *dctx, uint64_t pc, uint64_t fault,
> int oldprid = mst->prid;
>
> mst->argv[0] = 0;
> - mst->argv[1] = mst->epid;
> + mst->argv[1] = (((uint64_t)mst->prid) << 32) | mst->stid;
> mst->argv[2] = mst->clid;
> mst->argv[3] = pc;
> mst->argv[4] = fault;
> diff --git a/include/dtrace/universal.h b/include/dtrace/universal.h
> index d6562489..655ea772 100644
> --- a/include/dtrace/universal.h
> +++ b/include/dtrace/universal.h
> @@ -37,7 +37,7 @@ typedef uint16_t dtrace_actkind_t; /* action kind */
>
> typedef uint32_t dtrace_aggid_t; /* aggregation identifier */
> typedef uint32_t dtrace_cacheid_t; /* predicate cache identifier */
> -typedef uint32_t dtrace_epid_t; /* enabled probe identifier */
> +typedef uint64_t dtrace_epid_t; /* enabled probe identifier */
> typedef uint32_t dtrace_optid_t; /* option identifier */
> typedef uint32_t dtrace_specid_t; /* speculation identifier */
>
> diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
> index 70597d65..3f9c42ea 100644
> --- a/libdtrace/dt_bpf.c
> +++ b/libdtrace/dt_bpf.c
> @@ -774,7 +774,6 @@ gmap_create_cpuinfo(dtrace_hdl_t *dtp)
> * The size of the memory region is the sum of:
> * - size of the DTrace machine state, rounded up to the nearest
> * multiple of 8
> - * - 8 bytes padding for trace buffer alignment purposes
> * - maximum trace buffer record size, rounded up to the nearest
> * multiple of 8
> * - size of dctx->mem (see dt_dctx.h)
> @@ -783,7 +782,6 @@ static int
> gmap_create_mem(dtrace_hdl_t *dtp)
> {
> size_t sz = roundup(sizeof(dt_mstate_t), 8) +
> - 8 +
> roundup(dtp->dt_maxreclen, 8) +
> DMEM_SIZE(dtp);
>
> diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
> index d1ee3843..cf3c5504 100644
> --- a/libdtrace/dt_cc.c
> +++ b/libdtrace/dt_cc.c
> @@ -123,6 +123,7 @@ dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
> if (sdp == NULL)
> longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
>
> + sdp->dtsd_index = dtp->dt_clause_nextid++;
> assert(yypcb->pcb_stmt == NULL);
> yypcb->pcb_stmt = sdp;
> yypcb->pcb_maxrecs = 0;
> @@ -133,8 +134,8 @@ dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
> return sdp;
> }
>
> -static dt_ident_t *
> -dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
> +static void
> +dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp, dtrace_stmtdesc_t *sdp)
> {
> char *name;
> int len;
> @@ -156,12 +157,12 @@ dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
> /*
> * Generate a symbol name.
> */
> - len = snprintf(NULL, 0, "dt_clause_%d", dtp->dt_clause_nextid) + 1;
> + len = snprintf(NULL, 0, "dt_clause_%d", sdp->dtsd_index) + 1;
> name = dt_alloc(dtp, len);
> if (name == NULL)
> longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
>
> - snprintf(name, len, "dt_clause_%d", dtp->dt_clause_nextid++);
> + snprintf(name, len, "dt_clause_%d", sdp->dtsd_index);
>
> /*
> * Add the symbol to the BPF identifier table and associate the DIFO
> @@ -174,7 +175,7 @@ dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
>
> dt_ident_set_data(idp, dp);
>
> - return idp;
> + sdp->dtsd_clause = idp;
> }
>
> static void
> @@ -214,7 +215,7 @@ dt_compile_one_clause(dtrace_hdl_t *dtp, dt_node_t *cnp, dt_node_t *pnp)
> * Compile the clause (predicate and action).
> */
> dt_cg(yypcb, cnp);
> - sdp->dtsd_clause = dt_clause_create(dtp, dt_as(yypcb));
> + dt_clause_create(dtp, dt_as(yypcb), sdp);
>
> assert(yypcb->pcb_stmt == sdp);
> if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0)
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index a7861829..2c559868 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -277,15 +277,9 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
> * buf = rc + roundup(sizeof(dt_mstate_t), 8);
> * // add %r0, roundup(
> * sizeof(dt_mstate_t), 8)
> - * *((uint64_t *)&buf[0]) = 0;
> - * // stdw [%r0 + 0], 0
> - * buf += 8; // add %r0, 8
> - * // (%r0 = pointer to buffer space)
> * dctx.buf = buf; // stdw [%r9 + DCTX_BUF], %r0
> */
> emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, roundup(sizeof(dt_mstate_t), 8)));
> - emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, 0, 0));
> - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8));
> emit(dlp, BPF_STORE(BPF_DW, BPF_REG_9, DCTX_BUF, BPF_REG_0));
>
> /*
> @@ -1057,10 +1051,8 @@ static void
> dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> {
> dt_irlist_t *dlp = &pcb->pcb_ir;
> - dt_ident_t *epid = dt_dlib_get_var(pcb->pcb_hdl, "EPID");
> dt_ident_t *clid = dt_dlib_get_var(pcb->pcb_hdl, "CLID");
>
> - assert(epid != NULL);
> assert(clid != NULL);
>
> /*
> @@ -1093,18 +1085,22 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> * // stdw [%r0 + DMST_FAULT], 0
> * dctx->mst->tstamp = 0; // stdw [%r0 + DMST_TSTAMP], 0
> * dctx->mst->specsize = 0;// stdw [%r0 + DMST_SPECSIZE], 0
> - * dctx->mst->epid = EPID; // stw [%r0 + DMST_EPID], EPID
> + * dctx->mst->stid = STID; // stw [%r0 + DMST_STID], STID
> * dctx->mst->clid = CLID; // stw [%r0 + DMST_CLID], CLID
> - * *((uint32_t *)&buf[DBUF_EPID]) = EPID;
> - * // stw [%r9 + DBUF_EPID], EPID
> */
> emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_0, DCTX_MST));
> emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_FAULT, 0));
> emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_TSTAMP, 0));
> emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_SPECSIZE, 0));
> - emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_EPID, -1), epid);
> + emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_STID, pcb->pcb_stmt->dtsd_index));
> emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_CLID, -1), clid);
> - emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_EPID, -1), epid);
> +
> + /*
> + * Zero out the leading 4 bytes of the buffer.
> + * *((uint32_t *)&buf[DBUF_PAD]) = 0;
> + * // stw [%r9 + DBUF_PAD], 0
> + */
> + emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_PAD, 0));
>
> /*
> * Set the speculation ID field to zero to indicate no active
> @@ -1114,6 +1110,18 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> */
> emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_SPECID, 0));
>
> + /*
> + * *((uint64_t *)&buf[DBUF_EPID]) = (dctx->mst->prid << 32) | stid;
> + * // ld %r1, [%r0 + DMST_PRID]
> + * // lsh %r1, 32
> + * // or %r1, stid
> + * // stdw [%r9 + DBUF_EPID], %r1
> + */
> + emit (dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_0, DMST_PRID));
> + emit (dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 32));
> + emit (dlp, BPF_ALU64_IMM(BPF_OR, BPF_REG_1, pcb->pcb_stmt->dtsd_index));
> + emit (dlp, BPF_STORE(BPF_DW, BPF_REG_9, DBUF_EPID, BPF_REG_1));
> +
> /*
> * If there is a predicate:
> *
> @@ -1132,10 +1140,9 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> TRACE_REGSET("Prologue: End ");
>
> /*
> - * Account for 32-bit EPID (at offset 0) and 32-bit speculation ID (at
> - * offset 4).
> + * Set the offset for the beginning of trace data.
> */
> - pcb->pcb_bufoff += 2 * sizeof(uint32_t);
> + pcb->pcb_bufoff = DBUF_DATA;
> }
>
> /*
> @@ -1170,15 +1177,15 @@ dt_cg_epilogue(dt_pcb_t *pcb)
> /*
> * rc = bpf_perf_event_output(dctx->ctx, &buffers,
> * BPF_F_CURRENT_CPU,
> - * buf - 4, bufoff + 4);
> + * buf + 4, bufoff - 4);
> * // lddw %r1, [%fp + DT_STK_DCTX]
> * // lddw %r1, [%r1 + DCTX_CTX]
> * // lddw %r2, &buffers
> * // lddw %r3, BPF_F_CURRENT_CPU
> * // mov %r4, %r9
> - * // add %r4, -4
> + * // add %r4, 4
> * // mov %r5, pcb->pcb_bufoff
> - * // add %r5, 4
> + * // add %r5, -4
> * // call bpf_perf_event_output
> */
> emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_DCTX));
> @@ -1186,9 +1193,9 @@ dt_cg_epilogue(dt_pcb_t *pcb)
> dt_cg_xsetx(dlp, buffers, DT_LBL_NONE, BPF_REG_2, buffers->di_id);
> dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, BPF_REG_3, BPF_F_CURRENT_CPU);
> emit(dlp, BPF_MOV_REG(BPF_REG_4, BPF_REG_9));
> - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -4));
> + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4));
> emit(dlp, BPF_MOV_IMM(BPF_REG_5, pcb->pcb_bufoff));
> - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4));
> + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -4));
> emit(dlp, BPF_CALL_HELPER(BPF_FUNC_perf_event_output));
>
> /*
> diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
> index 51eb6c80..e3ce2d3b 100644
> --- a/libdtrace/dt_consume.c
> +++ b/libdtrace/dt_consume.c
> @@ -15,9 +15,11 @@
> #include <alloca.h>
> #include <dt_impl.h>
> #include <dt_aggregate.h>
> +#include <dt_dctx.h>
> #include <dt_module.h>
> #include <dt_pcap.h>
> #include <dt_peb.h>
> +#include <dt_probe.h>
> #include <dt_state.h>
> #include <dt_string.h>
> #include <libproc.h>
> @@ -479,7 +481,7 @@ dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last)
> */
> if (flow == DTRACEFLOW_ENTRY) {
> if (last != DTRACE_EPIDNONE && id != last &&
> - pd->id == dtp->dt_pdesc[last]->id)
> + pd->id == dtp->dt_probes[last >> 32]->desc->id)
> flow = DTRACEFLOW_NONE;
> }
>
> @@ -2184,19 +2186,23 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
> int peekflags, dtrace_epid_t *last, int committing,
> void *arg)
> {
> + int specid;
> dtrace_epid_t epid;
> + uint32_t prid;
> dtrace_datadesc_t *epd;
> dt_spec_buf_t tmpl;
> dt_spec_buf_t *dtsb;
> - int specid;
> int i;
> int rval;
> dtrace_workstatus_t ret;
> int commit_discard_seen, only_commit_discards;
> int data_recording = 1;
>
> - epid = ((uint32_t *)data)[0];
> - specid = ((uint32_t *)data)[1];
> + specid = *((uint32_t *)(data + DBUF_SPECID));
> + epid = *((uint64_t *)(data + DBUF_EPID));
> + prid = epid >> 32;
> + if (prid > dtp->dt_probe_id)
> + return dt_set_errno(dtp, EDT_BADEPID);
>
> /*
> * Fill in the epid and address of the epid in the buffer. We need to
> @@ -2209,6 +2215,7 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
> &pdat->dtpda_pdesc);
> if (rval != 0)
> return dt_set_errno(dtp, EDT_BADEPID);
> + pdat->dtpda_pdesc = (dtrace_probedesc_t *)dtp->dt_probes[prid]->desc;
>
> epd = pdat->dtpda_ddesc;
> if (epd->dtdd_uarg != DT_ECB_DEFAULT) {
> @@ -2639,9 +2646,8 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
> * struct {
> * struct perf_event_header header;
> * uint32_t size;
> - * uint32_t pad;
> - * uint32_t epid;
> * uint32_t specid;
> + * dtrace_epid_t epid;
> * uint64_t data[n];
> * }
> * and 'data' points to the 'size' member at this point.
> @@ -2651,13 +2657,17 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
> return dt_set_errno(dtp, EDT_DSIZE);
>
> size = *(uint32_t *)data;
> - data += sizeof(size);
> ptr += sizeof(size) + size;
> if (ptr != buf + hdr->size)
> return dt_set_errno(dtp, EDT_DSIZE);
>
> - data += sizeof(uint32_t); /* skip padding */
> - size -= sizeof(uint32_t);
> + /*
> + * The "size" measures from specid to the end. But our buffer
> + * offsets are relative to &size itself, to preserve 8-byte
> + * alignment. So, we leave data pointing at &size, and we
> + * increase size by 4 bytes.
> + */
> + size += 4;
>
> return dt_consume_one_probe(dtp, fp, data, size, pdat, efunc,
> rfunc, flow, quiet, peekflags,
> diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h
> index 1422ad24..6592bef1 100644
> --- a/libdtrace/dt_dctx.h
> +++ b/libdtrace/dt_dctx.h
> @@ -18,7 +18,7 @@
> * The DTrace machine state.
> */
> typedef struct dt_mstate {
> - uint32_t epid; /* Enabled probe ID */
> + uint32_t stid; /* Statement ID */
> uint32_t prid; /* Probe ID */
> uint32_t clid; /* Clause ID (unique per probe) */
> uint32_t tag; /* Tag (for future use) */
> @@ -33,7 +33,7 @@ typedef struct dt_mstate {
> uint64_t saved_argv[10]; /* Saved probe arguments */
> } dt_mstate_t;
>
> -#define DMST_EPID offsetof(dt_mstate_t, epid)
> +#define DMST_STID offsetof(dt_mstate_t, stid)
> #define DMST_PRID offsetof(dt_mstate_t, prid)
> #define DMST_CLID offsetof(dt_mstate_t, clid)
> #define DMST_TAG offsetof(dt_mstate_t, tag)
> @@ -82,16 +82,20 @@ typedef struct dt_dctx {
> * The dctx->buf pointer references a block of memory that contains:
> *
> * +----------------+
> - * 0 -> | EPID |
> + * 0 -> | pad |
> * +----------------+
> - * 4 -> | Speculation ID |
> + * 4 -> | Speculation ID |
> * +----------------+
> - * | Trace Data |
> + * 8 -> | EPID |
> + * +----------------+
> + * 16 -> | Trace Data |
> * | ... |
> * +----------------+
> */
> -#define DBUF_EPID 0
> +#define DBUF_PAD 0
> #define DBUF_SPECID 4
> +#define DBUF_EPID 8
> +#define DBUF_DATA 16
>
> /*
> * The dctx->mem pointer references a block of memory that contains:
> diff --git a/libdtrace/dt_handle.c b/libdtrace/dt_handle.c
> index 4c9b9413..b1ba5f9f 100644
> --- a/libdtrace/dt_handle.c
> +++ b/libdtrace/dt_handle.c
> @@ -14,6 +14,7 @@
> #include <alloca.h>
>
> #include <dt_impl.h>
> +#include <dt_probe.h>
> #include <dt_program.h>
>
> static const char _dt_errprog[] =
> @@ -147,11 +148,11 @@ dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
> * This is an error. We have the following items here: EPID,
> * faulting action, BPF pc, fault code and faulting address.
> */
> - epid = (uint32_t)DT_REC(uint64_t, 0);
> + epid = DT_REC(uint64_t, 0);
>
> if (dt_epid_lookup(dtp, epid, &errdd, &errpd) != 0)
> return dt_set_errno(dtp, EDT_BADERROR);
> -
> + errpd = (dtrace_probedesc_t *)dtp->dt_probes[epid>>32]->desc;
> err.dteda_ddesc = errdd;
> err.dteda_pdesc = errpd;
> err.dteda_cpu = data->dtpda_cpu;
> @@ -195,7 +196,7 @@ no_addr:
> details[0] = 0;
> }
>
> - snprintf(str, len, "error on enabled probe ID %u (ID %u: %s:%s:%s:%s): "
> + snprintf(str, len, "error on enabled probe ID %lu (ID %u: %s:%s:%s:%s): "
> "%s%s in %s%s",
> epid, errpd->id, errpd->prv, errpd->mod, errpd->fun,
> errpd->prb, dtrace_faultstr(dtp, err.dteda_fault), details,
> @@ -256,7 +257,7 @@ dt_handle_liberr(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
> str = alloca(len);
>
> snprintf(str, len,
> - "error on enabled probe ID %u (ID %u: %s:%s:%s:%s): %s",
> + "error on enabled probe ID %lu (ID %u: %s:%s:%s:%s): %s",
> data->dtpda_epid, errpd->id, errpd->prv, errpd->mod,
> errpd->fun, errpd->prb, faultstr);
>
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index 98fddc23..a2ae84f6 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -275,6 +275,7 @@ struct dtrace_hdl {
> dt_list_t dt_programs; /* linked list of dtrace_prog_t's */
> dt_list_t dt_xlators; /* linked list of dt_xlator_t's */
> dt_list_t dt_enablings; /* list of (to be) enabled probes */
> + dtrace_stmtdesc_t **dt_stmts; /* array of stmts */
> struct dt_xlator **dt_xlatormap; /* dt_xlator_t's indexed by dx_id */
> id_t dt_xlatorid; /* next dt_xlator_t id to assign */
> dt_ident_t *dt_externs; /* linked list of external symbol identifiers */
> diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
> index 60a2eca2..87ce5707 100644
> --- a/libdtrace/dt_map.c
> +++ b/libdtrace/dt_map.c
> @@ -138,14 +138,17 @@ int
> dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp,
> dtrace_probedesc_t **pdp)
> {
> - if (epid >= dtp->dt_maxprobe ||
> - dtp->dt_ddesc[epid] == NULL || dtp->dt_pdesc[epid] == NULL)
> + /* Remove the PRID portion of the EPID. */
> + epid &= 0xffffffff;
> +
> + if (epid >= dtp->dt_clause_nextid)
> return -1;
>
> - *ddp = dtp->dt_ddesc[epid];
> + dtrace_difo_t *rdp = dt_dlib_get_func_difo(dtp, dtp->dt_stmts[epid]->dtsd_clause);
> + *ddp = dt_datadesc_hold(rdp->dtdo_ddesc); // FIXME what releases the hold?
> *pdp = dtp->dt_pdesc[epid];
>
> - return 0;
> + return (*ddp == NULL) ? -1 : 0;
> }
>
> void
> diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
> index 77ffb6d2..8ae6cdfa 100644
> --- a/libdtrace/dt_open.c
> +++ b/libdtrace/dt_open.c
> @@ -170,7 +170,7 @@ static const dt_ident_t _dtrace_globals[] = {
> { "discard", DT_IDENT_ACTFUNC, 0, DT_ACT_DISCARD, DT_ATTR_STABCMN, DT_VERS_1_0,
> &dt_idops_func, "void(int)" },
> { "epid", DT_IDENT_SCALAR, 0, DIF_VAR_EPID, DT_ATTR_STABCMN, DT_VERS_1_0,
> - &dt_idops_type, "uint_t" },
> + &dt_idops_type, "uint64_t" },
> { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0,
> &dt_idops_type, "int" },
> { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME,
> diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
> index afbf7265..ee743589 100644
> --- a/libdtrace/dt_program.c
> +++ b/libdtrace/dt_program.c
> @@ -165,6 +165,13 @@ dt_prog_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
> dtrace_probedesc_t *pdp = &sdp->dtsd_ecbdesc->dted_probe;
> int rc;
>
> + if (dtp->dt_stmts == NULL) {
> + dtp->dt_stmts = dt_calloc(dtp, dtp->dt_clause_nextid, sizeof(dtrace_stmtdesc_t *));
> + if (dtp->dt_stmts == NULL)
> + return dt_set_errno(dtp, EDT_NOMEM);
> + }
> + dtp->dt_stmts[sdp->dtsd_index] = sdp;
> +
> st.cnt = cnt;
> st.sdp = sdp;
> rc = dt_probe_iter(dtp, pdp, (dt_probe_f *)dt_stmt_probe, NULL, &st);
> diff --git a/libdtrace/dtrace.h b/libdtrace/dtrace.h
> index 09a87977..a23052e4 100644
> --- a/libdtrace/dtrace.h
> +++ b/libdtrace/dtrace.h
> @@ -150,6 +150,7 @@ typedef struct dtrace_stmtdesc {
> dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
> dtrace_attribute_t dtsd_stmtattr; /* statement attributes */
> int dtsd_clauseflags; /* clause flags */
> + int dtsd_index; /* index in dtp->dt_stmts */
> } dtrace_stmtdesc_t;
>
> /* dtsd clause flags */
> diff --git a/test/demo/dtrace/error.r b/test/demo/dtrace/error.r
> index d3904f47..50b52370 100644
> --- a/test/demo/dtrace/error.r
> +++ b/test/demo/dtrace/error.r
> @@ -3,4 +3,4 @@
>
> -- @@stderr --
> dtrace: script 'test/demo/dtrace/error.d' matched 2 probes
> -dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
> +dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
> diff --git a/test/stress/buffering/tst.resize3-manual.r b/test/stress/buffering/tst.resize3-manual.r
> index 43b647c7..5493783e 100644
> --- a/test/stress/buffering/tst.resize3-manual.r
> +++ b/test/stress/buffering/tst.resize3-manual.r
> @@ -1,5 +1,5 @@
> FUNCTION:NAME
> - :BEGIN 3
> + :BEGIN 4294967297
> :BEGIN
>
> -- @@stderr --
> diff --git a/test/stress/buffering/tst.resize3.r b/test/stress/buffering/tst.resize3.r
> index 9c471158..807c4d1c 100644
> --- a/test/stress/buffering/tst.resize3.r
> +++ b/test/stress/buffering/tst.resize3.r
> @@ -1,5 +1,5 @@
> FUNCTION:NAME
> - :BEGIN 3
> + :BEGIN 4294967297
> :BEGIN
>
> -- @@stderr --
> diff --git a/test/unittest/actions/setopt/tst.badopt.r b/test/unittest/actions/setopt/tst.badopt.r
> index 29e39fd4..9373951c 100644
> --- a/test/unittest/actions/setopt/tst.badopt.r
> +++ b/test/unittest/actions/setopt/tst.badopt.r
> @@ -1,16 +1,16 @@
>
> -- @@stderr --
> -dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "Nixon" to "1": Invalid option name
> +dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "Nixon" to "1": Invalid option name
>
I'm very much *not* familiar enough to say if this is intended but can I
ask if it is?
That starts to look kind of inelegant (to print such a large ID for a
basic bad option diagnostic), where the probe wasn't doing anything
fancy? What am I missing?
> [...]
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 12/19] Increase size of BPF probes map
2024-08-29 5:25 ` [PATCH 12/19] Increase size of BPF probes map eugene.loh
@ 2024-08-29 20:30 ` Sam James
2024-10-08 22:15 ` Eugene Loh
1 sibling, 0 replies; 44+ messages in thread
From: Sam James @ 2024-08-29 20:30 UTC (permalink / raw)
To: eugene.loh--- via DTrace-devel; +Cc: dtrace, eugene.loh
"eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> We are going to support discovery of new probes after dtrace is
> launched. For example, there could be a pid or USDT probe with a
> wildcard pid specification that could be matched by a process that
> has not yet started. Or, a process could load a shared library.
>
> This means the probe map will have to grow. For now, just wire in
> some headroom, as ugly a hack as this is.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_bpf.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
> index 70803e3c..75e48962 100644
> --- a/libdtrace/dt_bpf.c
> +++ b/libdtrace/dt_bpf.c
> @@ -920,7 +920,7 @@ gmap_create_probes(dtrace_hdl_t *dtp)
>
> fd = create_gmap(dtp, "probes", BPF_MAP_TYPE_HASH, sizeof(uint32_t),
> sizeof(dt_bpf_probe_t),
> - dt_list_length(&dtp->dt_enablings));
> + dt_list_length(&dtp->dt_enablings) + 1000);
I think this might merit a FIXME comment. Also, maybe a static_assert
(or a #define for now with a comment above it saying it's a temporary
hack) to ensure it matches the + 1000 from 'Create the BPF usdt_prids map'?
> if (fd == -1)
> return -1;
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp
2024-08-29 5:25 ` [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp eugene.loh
@ 2024-08-29 20:31 ` Sam James
2024-09-03 19:54 ` Eugene Loh
0 siblings, 1 reply; 44+ messages in thread
From: Sam James @ 2024-08-29 20:31 UTC (permalink / raw)
To: eugene.loh--- via DTrace-devel; +Cc: dtrace, eugene.loh
"eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> In ignore_clauses, for an underlying probe uprp, we try to
> decide if we can safely ignore clause n.
>
> Meanwhile, for some clauses, the probe description tells us the
> clause will not be called for any USDT probe, regardless of the
> underlying probe. For example, "syscall::write:" can safely be
> ignored, for all uprp.
>
> Add a dtsd_usdt variable to each statement to track status:
Not that it really matters here, but I wonder why not an enum?
>
> USDT_FLAG_UNINITIALIZED not yet initialized
>
> USDT_FLAG_POSSIBLE clause could possibly be called
> for some USDT probe
>
> USDT_FLAG_IGNORE clause can safely be ignored for
> all USDT probes
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_prov_uprobe.c | 56 ++++++++++++++++++++++++++++++++++++--
> libdtrace/dtrace.h | 1 +
> 2 files changed, 55 insertions(+), 2 deletions(-)
>
> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> index 883a3e9d..454c53dc 100644
> --- a/libdtrace/dt_prov_uprobe.c
> +++ b/libdtrace/dt_prov_uprobe.c
> @@ -27,6 +27,7 @@
> */
> #include <sys/types.h>
> #include <assert.h>
> +#include <ctype.h>
> #include <errno.h>
> #include <string.h>
>
> @@ -232,6 +233,10 @@ grow_strtab(dtrace_hdl_t *dtp)
> return 0;
> }
>
> +#define USDT_FLAG_UNINITIALIZED 0
> +#define USDT_FLAG_POSSIBLE 1
> +#define USDT_FLAG_IGNORE 2
> +
> /*
> * Judge whether clause "n" could ever be called as a USDT probe
> * for this underlying probe.
> @@ -239,7 +244,53 @@ grow_strtab(dtrace_hdl_t *dtp)
> static int
> ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp)
> {
> - /* To be safe, ignore nothing. */
> + dtrace_probedesc_t *pdp = &dtp->dt_stmts[n]->dtsd_ecbdesc->dted_probe;
> + int *usdt_stat = &dtp->dt_stmts[n]->dtsd_usdt;
> +
> + /*
> + * Some clauses could never be called for a USDT probe,
> + * regardless of the underlying probe uprp. Cache this
> + * status in dt_stmts[n]->dtsd_usdt (pointed to by usdt_stat).
> + */
> + if (*usdt_stat == USDT_FLAG_UNINITIALIZED) {
> + char lastchar = pdp->prv[strlen(pdp->prv) - 1];
> +
> + /*
> + * If the last char in the provider description is
> + * neither '*' nor a digit, it cannot be a USDT probe.
> + */
> + if (lastchar != '*' && !isdigit(lastchar)) {
> + *usdt_stat = USDT_FLAG_IGNORE;
> + return 1;
> + }
> +
> + /*
> + * If the provider description is "pid[0-9]*", it
> + * is a pid probe, not USDT.
> + */
> + if (strncmp(pdp->prv, "pid", 3) == 0) {
> + int i, l = strlen(pdp->prv);
> +
> + for (i = 3; i < l; i++)
> + if (!isdigit((pdp->prv[i])))
> + break;
> +
> + if (i == l) {
> + *usdt_stat = USDT_FLAG_IGNORE;
> + return 1;
> + }
> + }
> +
> + /* Otherwise, it is possibly a USDT probe. */
> + *usdt_stat = USDT_FLAG_POSSIBLE;
> + }
> + if (*usdt_stat == USDT_FLAG_IGNORE)
> + return 1;
> +
> + /*
> + * If USDT_FLAG_POSSIBLE, try to use uprp.
> + */
> +
> return 0;
> }
>
> @@ -267,7 +318,8 @@ static void update_uprobe(dtrace_hdl_t *dtp, void *datap)
> */
> memset(&pcb, 0, sizeof(dt_pcb_t));
> for (i = 0; i < dtp->dt_clause_nextid; i++)
> - dt_pid_create_probes(&dtp->dt_stmts[i]->dtsd_ecbdesc->dted_probe, dtp, &pcb, 1);
> + if (dtp->dt_stmts[i]->dtsd_usdt != USDT_FLAG_IGNORE)
> + dt_pid_create_probes(&dtp->dt_stmts[i]->dtsd_ecbdesc->dted_probe, dtp, &pcb, 1);
>
> while (prid < dtp->dt_probe_id) {
> dt_bpf_probe_t pinfo;
> diff --git a/libdtrace/dtrace.h b/libdtrace/dtrace.h
> index a23052e4..2de7067f 100644
> --- a/libdtrace/dtrace.h
> +++ b/libdtrace/dtrace.h
> @@ -151,6 +151,7 @@ typedef struct dtrace_stmtdesc {
> dtrace_attribute_t dtsd_stmtattr; /* statement attributes */
> int dtsd_clauseflags; /* clause flags */
> int dtsd_index; /* index in dtp->dt_stmts */
> + int dtsd_usdt; /* flags describing USDT use, see dt_prov_uprobe.c */
> } dtrace_stmtdesc_t;
>
> /* dtsd clause flags */
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 17/19] test: Add a pid-USDT test
2024-08-29 5:25 ` [PATCH 17/19] test: Add a pid-USDT test eugene.loh
@ 2024-08-29 20:32 ` Sam James
2024-10-04 4:49 ` Eugene Loh
0 siblings, 1 reply; 44+ messages in thread
From: Sam James @ 2024-08-29 20:32 UTC (permalink / raw)
To: eugene.loh--- via DTrace-devel; +Cc: dtrace, eugene.loh
"eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> This checks that pid entry, pid return, pid offset, USDT, and USDT
> is-enabled probes can all coexist. Specifically, pid offset probes
> can sit on the same PCs as pid entry, USDT, and USDT is-enabled
> probes.
>
> Note that PCs for pid return probes are apparently in the caller
> function. I guess that's due to using uretprobe. I'm not convinced
> yet that that isn't a bug. It isn't what Solaris did.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> test/unittest/usdt/tst.pidprobes.r | 1 +
> test/unittest/usdt/tst.pidprobes.sh | 243 ++++++++++++++++++++++++++++
> 2 files changed, 244 insertions(+)
> create mode 100644 test/unittest/usdt/tst.pidprobes.r
> create mode 100755 test/unittest/usdt/tst.pidprobes.sh
>
> diff --git a/test/unittest/usdt/tst.pidprobes.r b/test/unittest/usdt/tst.pidprobes.r
> new file mode 100644
> index 00000000..2e9ba477
> --- /dev/null
> +++ b/test/unittest/usdt/tst.pidprobes.r
> @@ -0,0 +1 @@
> +success
> diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh
> new file mode 100755
> index 00000000..7eadb9b7
> --- /dev/null
> +++ b/test/unittest/usdt/tst.pidprobes.sh
> @@ -0,0 +1,243 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +#
> +# This test verifies that USDT and pid probes can share underlying probes.
> +
> +dtrace=$1
> +
> +# Set up test directory.
> +
> +DIRNAME=$tmpdir/pidprobes.$$.$RANDOM
> +mkdir -p $DIRNAME
> +cd $DIRNAME
> +
Let's do mktemp -d?
> [...]
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 03/19] Widen the EPID to include the PRID
2024-08-29 20:28 ` [DTrace-devel] " Sam James
@ 2024-08-29 20:38 ` Kris Van Hees
0 siblings, 0 replies; 44+ messages in thread
From: Kris Van Hees @ 2024-08-29 20:38 UTC (permalink / raw)
To: Sam James; +Cc: eugene.loh--- via DTrace-devel, dtrace, eugene.loh
On Thu, Aug 29, 2024 at 09:28:12PM +0100, Sam James wrote:
> "eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
>
> > From: Eugene Loh <eugene.loh@oracle.com>
> >
> > Each output record has an EPID associated with it. When the consumer
> > reads a record, it uses the EPID to look up both a PRID (so it can
> > report PRID and probe function and name) and a data description.
> > During code generation, the PRID and data description are known,
> > and so the EPID is set during relocation.
> >
> > However, we want to support underlying probes that trigger for PRIDs
> > that will be discovered at run time. So, expand the EPID to 64 bits:
> >
> > *) the lower half, known at code generation, will index into an
> > array dtp->dt_stmts[] of statements, which have information
> > about probe descriptions, data descriptions, and clauses to call
> >
> > *) the upper half will have the PRID, which will be discovered
> > at run time
> >
> > Statement descriptions include a new member dtsd_index, which is
> > the index to dtp->dt_stmts[].
> >
> > The consumer gets information about the firing probe from the PRID,
> > an index to dtp->dt_probes[].
> >
> > The lower half "EPID" depends only on the statement and no longer
> > on the specific probe that is firing. Its value is known at code
> > generation for a compiled clause. It no longer needs to be set in
> > relocation; that relocation will be removed in a future patch.
> >
> > The buffer memory pointed to by dctx->buf is rearranged so that EPID
> > will (still) fall on an 8-byte boundary but now take up 8 bytes.
> >
> > We do not need to expand:
> >
> > - the mstate (since it already had the PRID)
> >
> > Rename mstate's epid to be a statement ID, stid. When
> > the producer needs the epid, it can construct it from
> > mst->prid and mst->stid.
> >
> > - the output buffer (since it already had unused padding)
> >
> > The new, wider EPID is seen for the built-in variable epid as well
> > as the epid that the consumer reads.
> >
> > The probe descriptions dt_pdesc become superfluous and will be
> > eliminated in a future patch.
> >
> > Update test files:
> >
> > - Where the upper 32 bits of the EPID are known (since the PRID
> > corresponds to a dtrace::: probe), update the expected EPID in
> > the .r files.
> >
> > - Where the upper 32 bits of the EPID are not known, add .r.p
> > processing to filter those bits out before comparing to known
> > results in .r files.
> >
> > - Increase expected EPID width.
> >
> > Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> > ---
> > bpf/get_bvar.c | 6 ++-
> > bpf/probe_error.c | 2 +-
> > include/dtrace/universal.h | 2 +-
> > libdtrace/dt_bpf.c | 2 -
> > libdtrace/dt_cc.c | 13 ++---
> > libdtrace/dt_cg.c | 49 +++++++++++--------
> > libdtrace/dt_consume.c | 28 +++++++----
> > libdtrace/dt_dctx.h | 16 +++---
> > libdtrace/dt_handle.c | 9 ++--
> > libdtrace/dt_impl.h | 1 +
> > libdtrace/dt_map.c | 11 +++--
> > libdtrace/dt_open.c | 2 +-
> > libdtrace/dt_program.c | 7 +++
> > libdtrace/dtrace.h | 1 +
> > test/demo/dtrace/error.r | 2 +-
> > test/stress/buffering/tst.resize3-manual.r | 2 +-
> > test/stress/buffering/tst.resize3.r | 2 +-
> > test/unittest/actions/setopt/tst.badopt.r | 14 +++---
> > .../arrays/tst.declared-bounds.runtime_out.r | 2 +-
> > test/unittest/codegen/err.deref_0.r | 2 +-
> > test/unittest/codegen/err.deref_1.r | 2 +-
> > test/unittest/codegen/err.deref_i0.r | 2 +-
> > test/unittest/codegen/err.deref_i1.r | 2 +-
> > .../unittest/codegen/err.deref_string-assoc.r | 2 +-
> > test/unittest/codegen/err.deref_string-gvar.r | 2 +-
> > test/unittest/codegen/err.deref_string-lvar.r | 2 +-
> > test/unittest/codegen/err.deref_string-tvar.r | 2 +-
> > .../codegen/err.str_NULL_plus_offset-assoc.r | 2 +-
> > .../codegen/err.str_NULL_plus_offset-lvar.r | 2 +-
> > .../codegen/err.str_NULL_plus_offset-tvar.r | 2 +-
> > .../codegen/err.str_NULL_plus_offset.r | 2 +-
> > test/unittest/disasm/tst.vartab-bvar.r | 2 +-
> > test/unittest/drops/drp.DTRACEDROP_DBLERROR.r | 2 +-
> > .../tst.DTRACEFLT_BADADDR.null_ptr_field.r | 2 +-
> > test/unittest/error/tst.DTRACEFLT_BADADDR.r | 4 +-
> > test/unittest/error/tst.DTRACEFLT_BADADDR2.r | 4 +-
> > .../error/tst.DTRACEFLT_DIVZERO.div.r | 2 +-
> > .../error/tst.DTRACEFLT_DIVZERO.mod.r | 2 +-
> > test/unittest/error/tst.DTRACEFLT_UNKNOWN.r | 4 +-
> > .../error/tst.clause_scope-begin-ended.r | 2 +-
> > test/unittest/error/tst.clause_scope-begin.r | 2 +-
> > .../unittest/error/tst.clause_scope-regular.r | 2 +-
> > .../error/tst.clause_scope-regular.r.p | 12 ++++-
> > test/unittest/error/tst.error.r | 2 +-
> > test/unittest/error/tst.errorend.r | 2 +-
> > .../alloca/err.alloca-bcopy-before-beyond.r | 2 +-
> > .../alloca/err.alloca-bcopy-before-bottom.r | 2 +-
> > .../alloca/err.alloca-bcopy-beyond-top.r | 2 +-
> > .../alloca/err.alloca-bcopy-crossing-bottom.r | 2 +-
> > .../alloca/err.alloca-bcopy-crossing-top.r | 2 +-
> > .../alloca/err.alloca-crossing-clauses.r | 2 +-
> > .../alloca/err.alloca-load-before-bottom.r | 2 +-
> > .../funcs/alloca/err.alloca-load-beyond-top.r | 2 +-
> > .../alloca/err.alloca-load-crossing-bottom.r | 2 +-
> > .../alloca/err.alloca-null-deref-lvalue.r | 2 +-
> > .../funcs/alloca/err.alloca-null-deref.r | 2 +-
> > .../err.alloca-scratch-exceeding-bcopy.r | 2 +-
> > .../alloca/err.alloca-store-before-bottom.r | 2 +-
> > .../alloca/err.alloca-store-beyond-top.r | 2 +-
> > .../alloca/err.alloca-store-crossing-bottom.r | 2 +-
> > test/unittest/funcs/bcopy/err.badbcopy1.r | 2 +-
> > test/unittest/funcs/bcopy/err.badbcopy4.r | 2 +-
> > test/unittest/funcs/bcopy/err.badbcopy5.r | 2 +-
> > test/unittest/funcs/bcopy/err.badbcopy6.r | 2 +-
> > test/unittest/funcs/bcopy/err.badbcopy7.r | 2 +-
> > test/unittest/funcs/bcopy/err.badbcopy8.r | 2 +-
> > test/unittest/funcs/copyin/err.badaddr.r | 2 +-
> > test/unittest/funcs/copyin/err.null_arg1.r | 2 +-
> > test/unittest/funcs/copyinstr/err.badaddr.r | 2 +-
> > test/unittest/funcs/copyinstr/err.null_arg1.r | 2 +-
> > test/unittest/funcs/copyinto/err.badaddr.r | 2 +-
> > test/unittest/funcs/copyinto/err.badsize.r | 2 +-
> > test/unittest/funcs/copyinto/err.null_arg1.r | 2 +-
> > test/unittest/funcs/err.badalloca.r | 2 +-
> > test/unittest/funcs/err.badalloca.r.p | 12 ++++-
> > test/unittest/funcs/err.link_ntopbadaddr.r | 2 +-
> > test/unittest/funcs/err.link_ntopbadarg.r | 2 +-
> > .../inet_ntoa6/err.inet_ntoa6.arg1_null.r | 2 +-
> > .../err.inet_ntoa6.arg1_null_const.r | 2 +-
> > test/unittest/funcs/strlen/tst.null.r | 2 +-
> > test/unittest/funcs/strtok/tst.strtok_null.r | 2 +-
> > .../funcs/strtok/tst.strtok_nulldel.r | 2 +-
> > .../funcs/strtok/tst.strtok_nullstr.r | 2 +-
> > .../funcs/strtok/tst.strtok_nullstr2.r | 2 +-
> > .../funcs/substr/err.substr_null_arg1.r | 2 +-
> > test/unittest/pointers/err.AllocaOverrun.r | 2 +-
> > test/unittest/pointers/err.BadAlign.r | 2 +-
> > test/unittest/pointers/err.InvalidAddress2.r | 2 +-
> > test/unittest/pointers/err.InvalidAddress4.r | 2 +-
> > .../speculation/err.CommitWithInvalid.r | 2 +-
> > .../speculation/err.DiscardWithInvalid.r | 2 +-
> > test/unittest/speculation/tst.negcommit.r | 2 +-
> > 92 files changed, 197 insertions(+), 146 deletions(-)
> >
> > diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
> > index a0c04f3a..e9733bb1 100644
> > --- a/bpf/get_bvar.c
> > +++ b/bpf/get_bvar.c
> > @@ -48,8 +48,10 @@ noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx)
> > mst->tstamp = bpf_ktime_get_ns();
> >
> > return mst->tstamp;
> > - case DIF_VAR_EPID:
> > - return mst->epid;
> > + case DIF_VAR_EPID: {
> > + uint64_t val = mst->prid;
> > + return (val << 32) | mst->stid;
> > + }
> > case DIF_VAR_ID:
> > return mst->prid;
> > case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2:
> > diff --git a/bpf/probe_error.c b/bpf/probe_error.c
> > index ee1a1793..fba779a8 100644
> > --- a/bpf/probe_error.c
> > +++ b/bpf/probe_error.c
> > @@ -29,7 +29,7 @@ noinline void dt_probe_error(const dt_dctx_t *dctx, uint64_t pc, uint64_t fault,
> > int oldprid = mst->prid;
> >
> > mst->argv[0] = 0;
> > - mst->argv[1] = mst->epid;
> > + mst->argv[1] = (((uint64_t)mst->prid) << 32) | mst->stid;
> > mst->argv[2] = mst->clid;
> > mst->argv[3] = pc;
> > mst->argv[4] = fault;
> > diff --git a/include/dtrace/universal.h b/include/dtrace/universal.h
> > index d6562489..655ea772 100644
> > --- a/include/dtrace/universal.h
> > +++ b/include/dtrace/universal.h
> > @@ -37,7 +37,7 @@ typedef uint16_t dtrace_actkind_t; /* action kind */
> >
> > typedef uint32_t dtrace_aggid_t; /* aggregation identifier */
> > typedef uint32_t dtrace_cacheid_t; /* predicate cache identifier */
> > -typedef uint32_t dtrace_epid_t; /* enabled probe identifier */
> > +typedef uint64_t dtrace_epid_t; /* enabled probe identifier */
> > typedef uint32_t dtrace_optid_t; /* option identifier */
> > typedef uint32_t dtrace_specid_t; /* speculation identifier */
> >
> > diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
> > index 70597d65..3f9c42ea 100644
> > --- a/libdtrace/dt_bpf.c
> > +++ b/libdtrace/dt_bpf.c
> > @@ -774,7 +774,6 @@ gmap_create_cpuinfo(dtrace_hdl_t *dtp)
> > * The size of the memory region is the sum of:
> > * - size of the DTrace machine state, rounded up to the nearest
> > * multiple of 8
> > - * - 8 bytes padding for trace buffer alignment purposes
> > * - maximum trace buffer record size, rounded up to the nearest
> > * multiple of 8
> > * - size of dctx->mem (see dt_dctx.h)
> > @@ -783,7 +782,6 @@ static int
> > gmap_create_mem(dtrace_hdl_t *dtp)
> > {
> > size_t sz = roundup(sizeof(dt_mstate_t), 8) +
> > - 8 +
> > roundup(dtp->dt_maxreclen, 8) +
> > DMEM_SIZE(dtp);
> >
> > diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
> > index d1ee3843..cf3c5504 100644
> > --- a/libdtrace/dt_cc.c
> > +++ b/libdtrace/dt_cc.c
> > @@ -123,6 +123,7 @@ dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
> > if (sdp == NULL)
> > longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
> >
> > + sdp->dtsd_index = dtp->dt_clause_nextid++;
> > assert(yypcb->pcb_stmt == NULL);
> > yypcb->pcb_stmt = sdp;
> > yypcb->pcb_maxrecs = 0;
> > @@ -133,8 +134,8 @@ dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp,
> > return sdp;
> > }
> >
> > -static dt_ident_t *
> > -dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
> > +static void
> > +dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp, dtrace_stmtdesc_t *sdp)
> > {
> > char *name;
> > int len;
> > @@ -156,12 +157,12 @@ dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
> > /*
> > * Generate a symbol name.
> > */
> > - len = snprintf(NULL, 0, "dt_clause_%d", dtp->dt_clause_nextid) + 1;
> > + len = snprintf(NULL, 0, "dt_clause_%d", sdp->dtsd_index) + 1;
> > name = dt_alloc(dtp, len);
> > if (name == NULL)
> > longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
> >
> > - snprintf(name, len, "dt_clause_%d", dtp->dt_clause_nextid++);
> > + snprintf(name, len, "dt_clause_%d", sdp->dtsd_index);
> >
> > /*
> > * Add the symbol to the BPF identifier table and associate the DIFO
> > @@ -174,7 +175,7 @@ dt_clause_create(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
> >
> > dt_ident_set_data(idp, dp);
> >
> > - return idp;
> > + sdp->dtsd_clause = idp;
> > }
> >
> > static void
> > @@ -214,7 +215,7 @@ dt_compile_one_clause(dtrace_hdl_t *dtp, dt_node_t *cnp, dt_node_t *pnp)
> > * Compile the clause (predicate and action).
> > */
> > dt_cg(yypcb, cnp);
> > - sdp->dtsd_clause = dt_clause_create(dtp, dt_as(yypcb));
> > + dt_clause_create(dtp, dt_as(yypcb), sdp);
> >
> > assert(yypcb->pcb_stmt == sdp);
> > if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0)
> > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> > index a7861829..2c559868 100644
> > --- a/libdtrace/dt_cg.c
> > +++ b/libdtrace/dt_cg.c
> > @@ -277,15 +277,9 @@ dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act)
> > * buf = rc + roundup(sizeof(dt_mstate_t), 8);
> > * // add %r0, roundup(
> > * sizeof(dt_mstate_t), 8)
> > - * *((uint64_t *)&buf[0]) = 0;
> > - * // stdw [%r0 + 0], 0
> > - * buf += 8; // add %r0, 8
> > - * // (%r0 = pointer to buffer space)
> > * dctx.buf = buf; // stdw [%r9 + DCTX_BUF], %r0
> > */
> > emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, roundup(sizeof(dt_mstate_t), 8)));
> > - emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, 0, 0));
> > - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8));
> > emit(dlp, BPF_STORE(BPF_DW, BPF_REG_9, DCTX_BUF, BPF_REG_0));
> >
> > /*
> > @@ -1057,10 +1051,8 @@ static void
> > dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> > {
> > dt_irlist_t *dlp = &pcb->pcb_ir;
> > - dt_ident_t *epid = dt_dlib_get_var(pcb->pcb_hdl, "EPID");
> > dt_ident_t *clid = dt_dlib_get_var(pcb->pcb_hdl, "CLID");
> >
> > - assert(epid != NULL);
> > assert(clid != NULL);
> >
> > /*
> > @@ -1093,18 +1085,22 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> > * // stdw [%r0 + DMST_FAULT], 0
> > * dctx->mst->tstamp = 0; // stdw [%r0 + DMST_TSTAMP], 0
> > * dctx->mst->specsize = 0;// stdw [%r0 + DMST_SPECSIZE], 0
> > - * dctx->mst->epid = EPID; // stw [%r0 + DMST_EPID], EPID
> > + * dctx->mst->stid = STID; // stw [%r0 + DMST_STID], STID
> > * dctx->mst->clid = CLID; // stw [%r0 + DMST_CLID], CLID
> > - * *((uint32_t *)&buf[DBUF_EPID]) = EPID;
> > - * // stw [%r9 + DBUF_EPID], EPID
> > */
> > emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_0, DCTX_MST));
> > emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_FAULT, 0));
> > emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_TSTAMP, 0));
> > emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_0, DMST_SPECSIZE, 0));
> > - emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_EPID, -1), epid);
> > + emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_STID, pcb->pcb_stmt->dtsd_index));
> > emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_CLID, -1), clid);
> > - emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_EPID, -1), epid);
> > +
> > + /*
> > + * Zero out the leading 4 bytes of the buffer.
> > + * *((uint32_t *)&buf[DBUF_PAD]) = 0;
> > + * // stw [%r9 + DBUF_PAD], 0
> > + */
> > + emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_PAD, 0));
> >
> > /*
> > * Set the speculation ID field to zero to indicate no active
> > @@ -1114,6 +1110,18 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> > */
> > emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, DBUF_SPECID, 0));
> >
> > + /*
> > + * *((uint64_t *)&buf[DBUF_EPID]) = (dctx->mst->prid << 32) | stid;
> > + * // ld %r1, [%r0 + DMST_PRID]
> > + * // lsh %r1, 32
> > + * // or %r1, stid
> > + * // stdw [%r9 + DBUF_EPID], %r1
> > + */
> > + emit (dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_0, DMST_PRID));
> > + emit (dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 32));
> > + emit (dlp, BPF_ALU64_IMM(BPF_OR, BPF_REG_1, pcb->pcb_stmt->dtsd_index));
> > + emit (dlp, BPF_STORE(BPF_DW, BPF_REG_9, DBUF_EPID, BPF_REG_1));
> > +
> > /*
> > * If there is a predicate:
> > *
> > @@ -1132,10 +1140,9 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
> > TRACE_REGSET("Prologue: End ");
> >
> > /*
> > - * Account for 32-bit EPID (at offset 0) and 32-bit speculation ID (at
> > - * offset 4).
> > + * Set the offset for the beginning of trace data.
> > */
> > - pcb->pcb_bufoff += 2 * sizeof(uint32_t);
> > + pcb->pcb_bufoff = DBUF_DATA;
> > }
> >
> > /*
> > @@ -1170,15 +1177,15 @@ dt_cg_epilogue(dt_pcb_t *pcb)
> > /*
> > * rc = bpf_perf_event_output(dctx->ctx, &buffers,
> > * BPF_F_CURRENT_CPU,
> > - * buf - 4, bufoff + 4);
> > + * buf + 4, bufoff - 4);
> > * // lddw %r1, [%fp + DT_STK_DCTX]
> > * // lddw %r1, [%r1 + DCTX_CTX]
> > * // lddw %r2, &buffers
> > * // lddw %r3, BPF_F_CURRENT_CPU
> > * // mov %r4, %r9
> > - * // add %r4, -4
> > + * // add %r4, 4
> > * // mov %r5, pcb->pcb_bufoff
> > - * // add %r5, 4
> > + * // add %r5, -4
> > * // call bpf_perf_event_output
> > */
> > emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_DCTX));
> > @@ -1186,9 +1193,9 @@ dt_cg_epilogue(dt_pcb_t *pcb)
> > dt_cg_xsetx(dlp, buffers, DT_LBL_NONE, BPF_REG_2, buffers->di_id);
> > dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, BPF_REG_3, BPF_F_CURRENT_CPU);
> > emit(dlp, BPF_MOV_REG(BPF_REG_4, BPF_REG_9));
> > - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, -4));
> > + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4));
> > emit(dlp, BPF_MOV_IMM(BPF_REG_5, pcb->pcb_bufoff));
> > - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4));
> > + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, -4));
> > emit(dlp, BPF_CALL_HELPER(BPF_FUNC_perf_event_output));
> >
> > /*
> > diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
> > index 51eb6c80..e3ce2d3b 100644
> > --- a/libdtrace/dt_consume.c
> > +++ b/libdtrace/dt_consume.c
> > @@ -15,9 +15,11 @@
> > #include <alloca.h>
> > #include <dt_impl.h>
> > #include <dt_aggregate.h>
> > +#include <dt_dctx.h>
> > #include <dt_module.h>
> > #include <dt_pcap.h>
> > #include <dt_peb.h>
> > +#include <dt_probe.h>
> > #include <dt_state.h>
> > #include <dt_string.h>
> > #include <libproc.h>
> > @@ -479,7 +481,7 @@ dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last)
> > */
> > if (flow == DTRACEFLOW_ENTRY) {
> > if (last != DTRACE_EPIDNONE && id != last &&
> > - pd->id == dtp->dt_pdesc[last]->id)
> > + pd->id == dtp->dt_probes[last >> 32]->desc->id)
> > flow = DTRACEFLOW_NONE;
> > }
> >
> > @@ -2184,19 +2186,23 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
> > int peekflags, dtrace_epid_t *last, int committing,
> > void *arg)
> > {
> > + int specid;
> > dtrace_epid_t epid;
> > + uint32_t prid;
> > dtrace_datadesc_t *epd;
> > dt_spec_buf_t tmpl;
> > dt_spec_buf_t *dtsb;
> > - int specid;
> > int i;
> > int rval;
> > dtrace_workstatus_t ret;
> > int commit_discard_seen, only_commit_discards;
> > int data_recording = 1;
> >
> > - epid = ((uint32_t *)data)[0];
> > - specid = ((uint32_t *)data)[1];
> > + specid = *((uint32_t *)(data + DBUF_SPECID));
> > + epid = *((uint64_t *)(data + DBUF_EPID));
> > + prid = epid >> 32;
> > + if (prid > dtp->dt_probe_id)
> > + return dt_set_errno(dtp, EDT_BADEPID);
> >
> > /*
> > * Fill in the epid and address of the epid in the buffer. We need to
> > @@ -2209,6 +2215,7 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
> > &pdat->dtpda_pdesc);
> > if (rval != 0)
> > return dt_set_errno(dtp, EDT_BADEPID);
> > + pdat->dtpda_pdesc = (dtrace_probedesc_t *)dtp->dt_probes[prid]->desc;
> >
> > epd = pdat->dtpda_ddesc;
> > if (epd->dtdd_uarg != DT_ECB_DEFAULT) {
> > @@ -2639,9 +2646,8 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
> > * struct {
> > * struct perf_event_header header;
> > * uint32_t size;
> > - * uint32_t pad;
> > - * uint32_t epid;
> > * uint32_t specid;
> > + * dtrace_epid_t epid;
> > * uint64_t data[n];
> > * }
> > * and 'data' points to the 'size' member at this point.
> > @@ -2651,13 +2657,17 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
> > return dt_set_errno(dtp, EDT_DSIZE);
> >
> > size = *(uint32_t *)data;
> > - data += sizeof(size);
> > ptr += sizeof(size) + size;
> > if (ptr != buf + hdr->size)
> > return dt_set_errno(dtp, EDT_DSIZE);
> >
> > - data += sizeof(uint32_t); /* skip padding */
> > - size -= sizeof(uint32_t);
> > + /*
> > + * The "size" measures from specid to the end. But our buffer
> > + * offsets are relative to &size itself, to preserve 8-byte
> > + * alignment. So, we leave data pointing at &size, and we
> > + * increase size by 4 bytes.
> > + */
> > + size += 4;
> >
> > return dt_consume_one_probe(dtp, fp, data, size, pdat, efunc,
> > rfunc, flow, quiet, peekflags,
> > diff --git a/libdtrace/dt_dctx.h b/libdtrace/dt_dctx.h
> > index 1422ad24..6592bef1 100644
> > --- a/libdtrace/dt_dctx.h
> > +++ b/libdtrace/dt_dctx.h
> > @@ -18,7 +18,7 @@
> > * The DTrace machine state.
> > */
> > typedef struct dt_mstate {
> > - uint32_t epid; /* Enabled probe ID */
> > + uint32_t stid; /* Statement ID */
> > uint32_t prid; /* Probe ID */
> > uint32_t clid; /* Clause ID (unique per probe) */
> > uint32_t tag; /* Tag (for future use) */
> > @@ -33,7 +33,7 @@ typedef struct dt_mstate {
> > uint64_t saved_argv[10]; /* Saved probe arguments */
> > } dt_mstate_t;
> >
> > -#define DMST_EPID offsetof(dt_mstate_t, epid)
> > +#define DMST_STID offsetof(dt_mstate_t, stid)
> > #define DMST_PRID offsetof(dt_mstate_t, prid)
> > #define DMST_CLID offsetof(dt_mstate_t, clid)
> > #define DMST_TAG offsetof(dt_mstate_t, tag)
> > @@ -82,16 +82,20 @@ typedef struct dt_dctx {
> > * The dctx->buf pointer references a block of memory that contains:
> > *
> > * +----------------+
> > - * 0 -> | EPID |
> > + * 0 -> | pad |
> > * +----------------+
> > - * 4 -> | Speculation ID |
> > + * 4 -> | Speculation ID |
> > * +----------------+
> > - * | Trace Data |
> > + * 8 -> | EPID |
> > + * +----------------+
> > + * 16 -> | Trace Data |
> > * | ... |
> > * +----------------+
> > */
> > -#define DBUF_EPID 0
> > +#define DBUF_PAD 0
> > #define DBUF_SPECID 4
> > +#define DBUF_EPID 8
> > +#define DBUF_DATA 16
> >
> > /*
> > * The dctx->mem pointer references a block of memory that contains:
> > diff --git a/libdtrace/dt_handle.c b/libdtrace/dt_handle.c
> > index 4c9b9413..b1ba5f9f 100644
> > --- a/libdtrace/dt_handle.c
> > +++ b/libdtrace/dt_handle.c
> > @@ -14,6 +14,7 @@
> > #include <alloca.h>
> >
> > #include <dt_impl.h>
> > +#include <dt_probe.h>
> > #include <dt_program.h>
> >
> > static const char _dt_errprog[] =
> > @@ -147,11 +148,11 @@ dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
> > * This is an error. We have the following items here: EPID,
> > * faulting action, BPF pc, fault code and faulting address.
> > */
> > - epid = (uint32_t)DT_REC(uint64_t, 0);
> > + epid = DT_REC(uint64_t, 0);
> >
> > if (dt_epid_lookup(dtp, epid, &errdd, &errpd) != 0)
> > return dt_set_errno(dtp, EDT_BADERROR);
> > -
> > + errpd = (dtrace_probedesc_t *)dtp->dt_probes[epid>>32]->desc;
> > err.dteda_ddesc = errdd;
> > err.dteda_pdesc = errpd;
> > err.dteda_cpu = data->dtpda_cpu;
> > @@ -195,7 +196,7 @@ no_addr:
> > details[0] = 0;
> > }
> >
> > - snprintf(str, len, "error on enabled probe ID %u (ID %u: %s:%s:%s:%s): "
> > + snprintf(str, len, "error on enabled probe ID %lu (ID %u: %s:%s:%s:%s): "
> > "%s%s in %s%s",
> > epid, errpd->id, errpd->prv, errpd->mod, errpd->fun,
> > errpd->prb, dtrace_faultstr(dtp, err.dteda_fault), details,
> > @@ -256,7 +257,7 @@ dt_handle_liberr(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
> > str = alloca(len);
> >
> > snprintf(str, len,
> > - "error on enabled probe ID %u (ID %u: %s:%s:%s:%s): %s",
> > + "error on enabled probe ID %lu (ID %u: %s:%s:%s:%s): %s",
> > data->dtpda_epid, errpd->id, errpd->prv, errpd->mod,
> > errpd->fun, errpd->prb, faultstr);
> >
> > diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> > index 98fddc23..a2ae84f6 100644
> > --- a/libdtrace/dt_impl.h
> > +++ b/libdtrace/dt_impl.h
> > @@ -275,6 +275,7 @@ struct dtrace_hdl {
> > dt_list_t dt_programs; /* linked list of dtrace_prog_t's */
> > dt_list_t dt_xlators; /* linked list of dt_xlator_t's */
> > dt_list_t dt_enablings; /* list of (to be) enabled probes */
> > + dtrace_stmtdesc_t **dt_stmts; /* array of stmts */
> > struct dt_xlator **dt_xlatormap; /* dt_xlator_t's indexed by dx_id */
> > id_t dt_xlatorid; /* next dt_xlator_t id to assign */
> > dt_ident_t *dt_externs; /* linked list of external symbol identifiers */
> > diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
> > index 60a2eca2..87ce5707 100644
> > --- a/libdtrace/dt_map.c
> > +++ b/libdtrace/dt_map.c
> > @@ -138,14 +138,17 @@ int
> > dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp,
> > dtrace_probedesc_t **pdp)
> > {
> > - if (epid >= dtp->dt_maxprobe ||
> > - dtp->dt_ddesc[epid] == NULL || dtp->dt_pdesc[epid] == NULL)
> > + /* Remove the PRID portion of the EPID. */
> > + epid &= 0xffffffff;
> > +
> > + if (epid >= dtp->dt_clause_nextid)
> > return -1;
> >
> > - *ddp = dtp->dt_ddesc[epid];
> > + dtrace_difo_t *rdp = dt_dlib_get_func_difo(dtp, dtp->dt_stmts[epid]->dtsd_clause);
> > + *ddp = dt_datadesc_hold(rdp->dtdo_ddesc); // FIXME what releases the hold?
> > *pdp = dtp->dt_pdesc[epid];
> >
> > - return 0;
> > + return (*ddp == NULL) ? -1 : 0;
> > }
> >
> > void
> > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
> > index 77ffb6d2..8ae6cdfa 100644
> > --- a/libdtrace/dt_open.c
> > +++ b/libdtrace/dt_open.c
> > @@ -170,7 +170,7 @@ static const dt_ident_t _dtrace_globals[] = {
> > { "discard", DT_IDENT_ACTFUNC, 0, DT_ACT_DISCARD, DT_ATTR_STABCMN, DT_VERS_1_0,
> > &dt_idops_func, "void(int)" },
> > { "epid", DT_IDENT_SCALAR, 0, DIF_VAR_EPID, DT_ATTR_STABCMN, DT_VERS_1_0,
> > - &dt_idops_type, "uint_t" },
> > + &dt_idops_type, "uint64_t" },
> > { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0,
> > &dt_idops_type, "int" },
> > { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME,
> > diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
> > index afbf7265..ee743589 100644
> > --- a/libdtrace/dt_program.c
> > +++ b/libdtrace/dt_program.c
> > @@ -165,6 +165,13 @@ dt_prog_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
> > dtrace_probedesc_t *pdp = &sdp->dtsd_ecbdesc->dted_probe;
> > int rc;
> >
> > + if (dtp->dt_stmts == NULL) {
> > + dtp->dt_stmts = dt_calloc(dtp, dtp->dt_clause_nextid, sizeof(dtrace_stmtdesc_t *));
> > + if (dtp->dt_stmts == NULL)
> > + return dt_set_errno(dtp, EDT_NOMEM);
> > + }
> > + dtp->dt_stmts[sdp->dtsd_index] = sdp;
> > +
> > st.cnt = cnt;
> > st.sdp = sdp;
> > rc = dt_probe_iter(dtp, pdp, (dt_probe_f *)dt_stmt_probe, NULL, &st);
> > diff --git a/libdtrace/dtrace.h b/libdtrace/dtrace.h
> > index 09a87977..a23052e4 100644
> > --- a/libdtrace/dtrace.h
> > +++ b/libdtrace/dtrace.h
> > @@ -150,6 +150,7 @@ typedef struct dtrace_stmtdesc {
> > dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
> > dtrace_attribute_t dtsd_stmtattr; /* statement attributes */
> > int dtsd_clauseflags; /* clause flags */
> > + int dtsd_index; /* index in dtp->dt_stmts */
> > } dtrace_stmtdesc_t;
> >
> > /* dtsd clause flags */
> > diff --git a/test/demo/dtrace/error.r b/test/demo/dtrace/error.r
> > index d3904f47..50b52370 100644
> > --- a/test/demo/dtrace/error.r
> > +++ b/test/demo/dtrace/error.r
> > @@ -3,4 +3,4 @@
> >
> > -- @@stderr --
> > dtrace: script 'test/demo/dtrace/error.d' matched 2 probes
> > -dtrace: error on enabled probe ID 3 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
> > +dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): invalid address ({ptr}) in action #1 at BPF pc NNN
> > diff --git a/test/stress/buffering/tst.resize3-manual.r b/test/stress/buffering/tst.resize3-manual.r
> > index 43b647c7..5493783e 100644
> > --- a/test/stress/buffering/tst.resize3-manual.r
> > +++ b/test/stress/buffering/tst.resize3-manual.r
> > @@ -1,5 +1,5 @@
> > FUNCTION:NAME
> > - :BEGIN 3
> > + :BEGIN 4294967297
> > :BEGIN
> >
> > -- @@stderr --
> > diff --git a/test/stress/buffering/tst.resize3.r b/test/stress/buffering/tst.resize3.r
> > index 9c471158..807c4d1c 100644
> > --- a/test/stress/buffering/tst.resize3.r
> > +++ b/test/stress/buffering/tst.resize3.r
> > @@ -1,5 +1,5 @@
> > FUNCTION:NAME
> > - :BEGIN 3
> > + :BEGIN 4294967297
> > :BEGIN
> >
> > -- @@stderr --
> > diff --git a/test/unittest/actions/setopt/tst.badopt.r b/test/unittest/actions/setopt/tst.badopt.r
> > index 29e39fd4..9373951c 100644
> > --- a/test/unittest/actions/setopt/tst.badopt.r
> > +++ b/test/unittest/actions/setopt/tst.badopt.r
> > @@ -1,16 +1,16 @@
> >
> > -- @@stderr --
> > -dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): couldn't set option "Nixon" to "1": Invalid option name
> > +dtrace: error on enabled probe ID 4294967296 (ID 1: dtrace:::BEGIN): couldn't set option "Nixon" to "1": Invalid option name
> >
>
> I'm very much *not* familiar enough to say if this is intended but can I
> ask if it is?
>
> That starts to look kind of inelegant (to print such a large ID for a
> basic bad option diagnostic), where the probe wasn't doing anything
> fancy? What am I missing?
I asked Eugene to look at this from a different angle, because we are (in
essence) deprecating the concept of EPID as it existed in DTrace, and that
needs to be reflected more in the code.
Reporting enabled probe ID is not really useful anymore anyway, and probably
should be renamed but that needs a bit more attention on how to rename it so
that it actuallt makes sense. But there is no actual need here to make it
such a high value I think because it is meant to assist in identifying the
"function" or "clause" that triggered the failure and for that the raw EPID
(in its new meaning) is actually sufficient.
So, stay tuned for changes to this patch and others...
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 04/19] Eliminate dt_pdesc
2024-08-29 5:25 ` [PATCH 04/19] Eliminate dt_pdesc eugene.loh
@ 2024-09-03 17:47 ` Eugene Loh
0 siblings, 0 replies; 44+ messages in thread
From: Eugene Loh @ 2024-09-03 17:47 UTC (permalink / raw)
To: dtrace, dtrace-devel
Patch withdrawn. It's been squashed into v2 03/19.
On 8/29/24 01:25, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> The probe descriptions dt_pdesc are superfluous and are
> eliminated here.
>
> Consequently, we also no longer need the last args to
> dt_epid_add()
> dt_epid_lookup()
>
> Nor so we need to track prid in dt_link_construct().
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_cc.c | 8 +-------
> libdtrace/dt_consume.c | 3 +--
> libdtrace/dt_handle.c | 2 +-
> libdtrace/dt_impl.h | 7 ++-----
> libdtrace/dt_map.c | 33 ++++++---------------------------
> 5 files changed, 11 insertions(+), 42 deletions(-)
>
> diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
> index cf3c5504..e66d76fb 100644
> --- a/libdtrace/dt_cc.c
> +++ b/libdtrace/dt_cc.c
> @@ -959,7 +959,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> uint_t len = sdp->dtdo_brelen;
> const dof_relodesc_t *rp = sdp->dtdo_breltab;
> dof_relodesc_t *nrp = &dp->dtdo_breltab[rc];
> - dtrace_id_t prid = prp->desc->id;
> int no_deps = 0;
>
> if (idp != NULL) {
> @@ -1197,11 +1196,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> case DT_CONST_STACK_SKIP:
> nrp->dofr_data = prp->prov->impl->stack_skip;
> continue;
> - default:
> - /* probe name -> value is probe id */
> - if (strchr(idp->di_name, ':') != NULL)
> - prid = rp->dofr_data;
> - continue;
> }
>
> continue;
> @@ -1218,7 +1212,7 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> if (rdp == NULL)
> return -1;
> if (rdp->dtdo_ddesc != NULL) {
> - nepid = dt_epid_add(dtp, rdp->dtdo_ddesc, prid);
> + nepid = dt_epid_add(dtp, rdp->dtdo_ddesc);
> clid++;
> } else
> nepid = 0;
> diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
> index e3ce2d3b..88083b19 100644
> --- a/libdtrace/dt_consume.c
> +++ b/libdtrace/dt_consume.c
> @@ -2211,8 +2211,7 @@ dt_consume_one_probe(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
> pdat->dtpda_epid = epid;
> pdat->dtpda_data = data;
>
> - rval = dt_epid_lookup(dtp, epid, &pdat->dtpda_ddesc,
> - &pdat->dtpda_pdesc);
> + rval = dt_epid_lookup(dtp, epid, &pdat->dtpda_ddesc);
> if (rval != 0)
> return dt_set_errno(dtp, EDT_BADEPID);
> pdat->dtpda_pdesc = (dtrace_probedesc_t *)dtp->dt_probes[prid]->desc;
> diff --git a/libdtrace/dt_handle.c b/libdtrace/dt_handle.c
> index b1ba5f9f..79ecbac8 100644
> --- a/libdtrace/dt_handle.c
> +++ b/libdtrace/dt_handle.c
> @@ -150,7 +150,7 @@ dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
> */
> epid = DT_REC(uint64_t, 0);
>
> - if (dt_epid_lookup(dtp, epid, &errdd, &errpd) != 0)
> + if (dt_epid_lookup(dtp, epid, &errdd) != 0)
> return dt_set_errno(dtp, EDT_BADERROR);
> errpd = (dtrace_probedesc_t *)dtp->dt_probes[epid>>32]->desc;
> err.dteda_ddesc = errdd;
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index a2ae84f6..c2b18b0b 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -345,7 +345,6 @@ struct dtrace_hdl {
> dtrace_epid_t dt_nextepid; /* next enabled probe ID to assign */
> size_t dt_maxprobe; /* max enabled probe ID */
> dtrace_datadesc_t **dt_ddesc; /* probe data descriptions */
> - dtrace_probedesc_t **dt_pdesc; /* probe descriptions for enabled prbs */
> size_t dt_maxagg; /* max aggregation ID */
> dtrace_aggdesc_t **dt_adesc; /* aggregation descriptions */
> struct dt_aggregate *dt_aggregate; /* aggregate */
> @@ -774,10 +773,8 @@ extern dtrace_datadesc_t *dt_datadesc_hold(dtrace_datadesc_t *ddp);
> extern void dt_datadesc_release(dtrace_hdl_t *, dtrace_datadesc_t *);
> extern dtrace_datadesc_t *dt_datadesc_create(dtrace_hdl_t *);
> extern int dt_datadesc_finalize(dtrace_hdl_t *, dtrace_datadesc_t *);
> -extern dtrace_epid_t dt_epid_add(dtrace_hdl_t *, dtrace_datadesc_t *,
> - dtrace_id_t);
> -extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_datadesc_t **,
> - dtrace_probedesc_t **);
> +extern dtrace_epid_t dt_epid_add(dtrace_hdl_t *, dtrace_datadesc_t *);
> +extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_datadesc_t **);
> extern void dt_epid_destroy(dtrace_hdl_t *);
> typedef void (*dt_cg_gap_f)(dt_pcb_t *, int);
> extern uint32_t dt_rec_add(dtrace_hdl_t *, dt_cg_gap_f, dtrace_actkind_t,
> diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
> index 87ce5707..9011da5d 100644
> --- a/libdtrace/dt_map.c
> +++ b/libdtrace/dt_map.c
> @@ -92,7 +92,7 @@ dt_datadesc_finalize(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
> * description.
> */
> dtrace_epid_t
> -dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp, dtrace_id_t prid)
> +dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
> {
> dtrace_id_t max = dtp->dt_maxprobe;
> dtrace_epid_t epid;
> @@ -101,27 +101,19 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp, dtrace_id_t prid)
> if (epid >= max || dtp->dt_ddesc == NULL) {
> dtrace_id_t nmax = max ? (max << 1) : 2;
> dtrace_datadesc_t **nddesc;
> - dtrace_probedesc_t **npdesc;
>
> nddesc = dt_calloc(dtp, nmax, sizeof(void *));
> - npdesc = dt_calloc(dtp, nmax, sizeof(void *));
> - if (nddesc == NULL || npdesc == NULL) {
> - dt_free(dtp, nddesc);
> - dt_free(dtp, npdesc);
> + if (nddesc == NULL)
> return dt_set_errno(dtp, EDT_NOMEM);
> - }
>
> if (dtp->dt_ddesc != NULL) {
> size_t osize = max * sizeof(void *);
>
> memcpy(nddesc, dtp->dt_ddesc, osize);
> dt_free(dtp, dtp->dt_ddesc);
> - memcpy(npdesc, dtp->dt_pdesc, osize);
> - dt_free(dtp, dtp->dt_pdesc);
> }
>
> dtp->dt_ddesc = nddesc;
> - dtp->dt_pdesc = npdesc;
> dtp->dt_maxprobe = nmax;
> }
>
> @@ -129,14 +121,12 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp, dtrace_id_t prid)
> return epid;
>
> dtp->dt_ddesc[epid] = dt_datadesc_hold(ddp);
> - dtp->dt_pdesc[epid] = (dtrace_probedesc_t *)dtp->dt_probes[prid]->desc;
>
> return epid;
> }
>
> int
> -dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp,
> - dtrace_probedesc_t **pdp)
> +dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp)
> {
> /* Remove the PRID portion of the EPID. */
> epid &= 0xffffffff;
> @@ -146,7 +136,6 @@ dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp,
>
> dtrace_difo_t *rdp = dt_dlib_get_func_difo(dtp, dtp->dt_stmts[epid]->dtsd_clause);
> *ddp = dt_datadesc_hold(rdp->dtdo_ddesc); // FIXME what releases the hold?
> - *pdp = dtp->dt_pdesc[epid];
>
> return (*ddp == NULL) ? -1 : 0;
> }
> @@ -156,26 +145,16 @@ dt_epid_destroy(dtrace_hdl_t *dtp)
> {
> size_t i;
>
> - assert((dtp->dt_pdesc != NULL && dtp->dt_ddesc != NULL &&
> - dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
> - dtp->dt_ddesc == NULL && dtp->dt_maxprobe == 0));
> -
> - if (dtp->dt_pdesc == NULL)
> - return;
> + assert((dtp->dt_ddesc != NULL && dtp->dt_maxprobe > 0) ||
> + (dtp->dt_ddesc == NULL && dtp->dt_maxprobe == 0));
>
> for (i = 0; i < dtp->dt_maxprobe; i++) {
> - if (dtp->dt_ddesc[i] == NULL) {
> - assert(dtp->dt_pdesc[i] == NULL);
> + if (dtp->dt_ddesc[i] == NULL)
> continue;
> - }
>
> dt_datadesc_release(dtp, dtp->dt_ddesc[i]);
> - assert(dtp->dt_pdesc[i] != NULL);
> }
>
> - free(dtp->dt_pdesc);
> - dtp->dt_pdesc = NULL;
> -
> free(dtp->dt_ddesc);
> dtp->dt_ddesc = NULL;
> dtp->dt_nextepid = 0;
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 13/19] Get rid of relocatable EPID, dt_nextepid, and dt_ddesc[]
2024-08-29 5:25 ` [PATCH 13/19] Get rid of relocatable EPID, dt_nextepid, and dt_ddesc[] eugene.loh
@ 2024-09-03 17:49 ` Eugene Loh
0 siblings, 0 replies; 44+ messages in thread
From: Eugene Loh @ 2024-09-03 17:49 UTC (permalink / raw)
To: dtrace, dtrace-devel
Patch withdrawn. It's been squashed into v2 03/19.
On 8/29/24 01:25, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> We no longer have to assign an EPID value during relocation. So we
> no longer need dt_nextepid, dt_maxprobe, dt_ddesc[], dt_epid_add(),
> or dt_epid_destroy() or to track an EPID during linking.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_bpf.h | 47 +++++++++++++++++-----------------
> libdtrace/dt_cc.c | 20 +++++----------
> libdtrace/dt_dlibs.c | 1 -
> libdtrace/dt_impl.h | 5 ----
> libdtrace/dt_map.c | 61 --------------------------------------------
> libdtrace/dt_open.c | 3 ---
> 6 files changed, 29 insertions(+), 108 deletions(-)
>
> diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
> index 5b2df264..5981eb0e 100644
> --- a/libdtrace/dt_bpf.h
> +++ b/libdtrace/dt_bpf.h
> @@ -32,30 +32,29 @@ extern "C" {
> (dtp)->dt_bpffeatures |= (feat); \
> } while (0)
>
> -#define DT_CONST_EPID 1
> -#define DT_CONST_PRID 2
> -#define DT_CONST_CLID 3
> -#define DT_CONST_ARGC 4
> -#define DT_CONST_STBSZ 5
> -#define DT_CONST_STRSZ 6
> -#define DT_CONST_STKSIZ 7
> -#define DT_CONST_BOOTTM 8
> -#define DT_CONST_NSPEC 9
> -#define DT_CONST_NCPUS 10
> -#define DT_CONST_PC 11
> -#define DT_CONST_TUPSZ 12
> -#define DT_CONST_TASK_PID 13
> -#define DT_CONST_TASK_TGID 14
> -#define DT_CONST_TASK_REAL_PARENT 15
> -#define DT_CONST_TASK_COMM 16
> -#define DT_CONST_MUTEX_OWNER 17
> -#define DT_CONST_RWLOCK_CNTS 18
> -#define DT_CONST_DCTX_RODATA 19
> -#define DT_CONST_RODATA_OFF 20
> -#define DT_CONST_RODATA_SIZE 21
> -#define DT_CONST_ZERO_OFF 22
> -#define DT_CONST_STACK_OFF 23
> -#define DT_CONST_STACK_SKIP 24
> +#define DT_CONST_PRID 1
> +#define DT_CONST_CLID 2
> +#define DT_CONST_ARGC 3
> +#define DT_CONST_STBSZ 4
> +#define DT_CONST_STRSZ 5
> +#define DT_CONST_STKSIZ 6
> +#define DT_CONST_BOOTTM 7
> +#define DT_CONST_NSPEC 8
> +#define DT_CONST_NCPUS 9
> +#define DT_CONST_PC 10
> +#define DT_CONST_TUPSZ 11
> +#define DT_CONST_TASK_PID 12
> +#define DT_CONST_TASK_TGID 13
> +#define DT_CONST_TASK_REAL_PARENT 14
> +#define DT_CONST_TASK_COMM 15
> +#define DT_CONST_MUTEX_OWNER 16
> +#define DT_CONST_RWLOCK_CNTS 17
> +#define DT_CONST_DCTX_RODATA 18
> +#define DT_CONST_RODATA_OFF 19
> +#define DT_CONST_RODATA_SIZE 20
> +#define DT_CONST_ZERO_OFF 21
> +#define DT_CONST_STACK_OFF 22
> +#define DT_CONST_STACK_SKIP 23
>
> #define DT_BPF_LOG_SIZE_DEFAULT (UINT32_MAX >> 8)
> #define DT_BPF_LOG_SIZE_SMALL 4096
> diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
> index 2510db86..b801c87a 100644
> --- a/libdtrace/dt_cc.c
> +++ b/libdtrace/dt_cc.c
> @@ -949,7 +949,7 @@ static int get_boottime() {
> static int
> dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> dt_ident_t *idp, const dtrace_difo_t *sdp, uint_t *pcp,
> - uint_t *rcp, uint_t *vcp, dtrace_epid_t epid, uint_t clid)
> + uint_t *rcp, uint_t *vcp, uint_t clid)
> {
> uint_t pc = *pcp;
> uint_t rc = *rcp;
> @@ -1030,7 +1030,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> for (; len != 0; len--, rp++, nrp++) {
> const char *name = dt_difo_getstr(sdp, rp->dofr_name);
> dtrace_difo_t *rdp;
> - dtrace_epid_t nepid;
> int ipc;
>
> idp = dt_dlib_get_sym(dtp, name);
> @@ -1045,9 +1044,6 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> }
>
> switch (idp->di_id) {
> - case DT_CONST_EPID:
> - nrp->dofr_data = epid;
> - continue;
> case DT_CONST_PRID:
> nrp->dofr_data = prp->desc->id;
> continue;
> @@ -1212,13 +1208,10 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> rdp = dt_dlib_get_func_difo(dtp, idp);
> if (rdp == NULL)
> return -1;
> - if (rdp->dtdo_ddesc != NULL) {
> - nepid = dt_epid_add(dtp, rdp->dtdo_ddesc);
> - clid++;
> - } else
> - nepid = 0;
> + if (rdp->dtdo_ddesc != NULL)
> + clid++; /* FIXME: dump this? */
> ipc = dt_link_construct(dtp, prp, dp, idp, rdp, pcp,
> - rcp, vcp, nepid, clid);
> + rcp, vcp, clid);
> if (ipc == -1)
> return -1;
>
> @@ -1259,7 +1252,7 @@ dt_link_resolve(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
> continue;
>
> /*
> - * We are only relocating constants (EPID and ARGC) and call
> + * We are only relocating constants and call
> * instructions to functions that have been linked in.
> */
> switch (idp->di_kind) {
> @@ -1332,8 +1325,7 @@ dt_link(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
> */
> insc = relc = varc = 0;
>
> - rc = dt_link_construct(dtp, prp, fdp, idp, dp, &insc, &relc, &varc, 0,
> - 0);
> + rc = dt_link_construct(dtp, prp, fdp, idp, dp, &insc, &relc, &varc, 0);
> dt_dlib_reset(dtp, B_FALSE);
> if (rc == -1)
> goto fail;
> diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
> index 060cf28b..140ac9a6 100644
> --- a/libdtrace/dt_dlibs.c
> +++ b/libdtrace/dt_dlibs.c
> @@ -74,7 +74,6 @@ static const dt_ident_t dt_bpf_symbols[] = {
> DT_BPF_SYMBOL(tuples, DT_IDENT_PTR),
>
> /* BPF internal identifiers */
> - DT_BPF_SYMBOL_ID(EPID, DT_IDENT_SCALAR, DT_CONST_EPID),
> DT_BPF_SYMBOL_ID(PRID, DT_IDENT_SCALAR, DT_CONST_PRID),
> DT_BPF_SYMBOL_ID(CLID, DT_IDENT_SCALAR, DT_CONST_CLID),
> DT_BPF_SYMBOL_ID(ARGC, DT_IDENT_SCALAR, DT_CONST_ARGC),
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index 2378235c..3fa2b9d7 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -343,9 +343,6 @@ struct dtrace_hdl {
> ctf_id_t dt_type_symaddr; /* cached CTF identifier for _symaddr type */
> ctf_id_t dt_type_usymaddr; /* cached CTF ident. for _usymaddr type */
> ctf_id_t dt_type_void; /* cached CTF identifier for void type */
> - dtrace_epid_t dt_nextepid; /* next enabled probe ID to assign */
> - size_t dt_maxprobe; /* max enabled probe ID */
> - dtrace_datadesc_t **dt_ddesc; /* probe data descriptions */
> size_t dt_maxagg; /* max aggregation ID */
> dtrace_aggdesc_t **dt_adesc; /* aggregation descriptions */
> struct dt_aggregate *dt_aggregate; /* aggregate */
> @@ -779,9 +776,7 @@ extern dtrace_datadesc_t *dt_datadesc_hold(dtrace_datadesc_t *ddp);
> extern void dt_datadesc_release(dtrace_hdl_t *, dtrace_datadesc_t *);
> extern dtrace_datadesc_t *dt_datadesc_create(dtrace_hdl_t *);
> extern int dt_datadesc_finalize(dtrace_hdl_t *, dtrace_datadesc_t *);
> -extern dtrace_epid_t dt_epid_add(dtrace_hdl_t *, dtrace_datadesc_t *);
> extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_datadesc_t **);
> -extern void dt_epid_destroy(dtrace_hdl_t *);
> typedef void (*dt_cg_gap_f)(dt_pcb_t *, int);
> extern uint32_t dt_rec_add(dtrace_hdl_t *, dt_cg_gap_f, dtrace_actkind_t,
> uint32_t, uint16_t, dt_pfargv_t *, uint64_t);
> diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
> index 9011da5d..26f101e4 100644
> --- a/libdtrace/dt_map.c
> +++ b/libdtrace/dt_map.c
> @@ -85,46 +85,6 @@ dt_datadesc_finalize(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
> return 0;
> }
>
> -/*
> - * Associate a probe data description and probe description with an enabled
> - * probe ID. This means that the given ID refers to the program matching the
> - * probe data description being attached to the probe that matches the probe
> - * description.
> - */
> -dtrace_epid_t
> -dt_epid_add(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
> -{
> - dtrace_id_t max = dtp->dt_maxprobe;
> - dtrace_epid_t epid;
> -
> - epid = dtp->dt_nextepid++;
> - if (epid >= max || dtp->dt_ddesc == NULL) {
> - dtrace_id_t nmax = max ? (max << 1) : 2;
> - dtrace_datadesc_t **nddesc;
> -
> - nddesc = dt_calloc(dtp, nmax, sizeof(void *));
> - if (nddesc == NULL)
> - return dt_set_errno(dtp, EDT_NOMEM);
> -
> - if (dtp->dt_ddesc != NULL) {
> - size_t osize = max * sizeof(void *);
> -
> - memcpy(nddesc, dtp->dt_ddesc, osize);
> - dt_free(dtp, dtp->dt_ddesc);
> - }
> -
> - dtp->dt_ddesc = nddesc;
> - dtp->dt_maxprobe = nmax;
> - }
> -
> - if (dtp->dt_ddesc[epid] != NULL)
> - return epid;
> -
> - dtp->dt_ddesc[epid] = dt_datadesc_hold(ddp);
> -
> - return epid;
> -}
> -
> int
> dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp)
> {
> @@ -140,27 +100,6 @@ dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid, dtrace_datadesc_t **ddp)
> return (*ddp == NULL) ? -1 : 0;
> }
>
> -void
> -dt_epid_destroy(dtrace_hdl_t *dtp)
> -{
> - size_t i;
> -
> - assert((dtp->dt_ddesc != NULL && dtp->dt_maxprobe > 0) ||
> - (dtp->dt_ddesc == NULL && dtp->dt_maxprobe == 0));
> -
> - for (i = 0; i < dtp->dt_maxprobe; i++) {
> - if (dtp->dt_ddesc[i] == NULL)
> - continue;
> -
> - dt_datadesc_release(dtp, dtp->dt_ddesc[i]);
> - }
> -
> - free(dtp->dt_ddesc);
> - dtp->dt_ddesc = NULL;
> - dtp->dt_nextepid = 0;
> - dtp->dt_maxprobe = 0;
> -}
> -
> uint32_t
> dt_rec_add(dtrace_hdl_t *dtp, dt_cg_gap_f gapf, dtrace_actkind_t kind,
> uint32_t size, uint16_t alignment, dt_pfargv_t *pfp, uint64_t arg)
> diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
> index 8ae6cdfa..848141dd 100644
> --- a/libdtrace/dt_open.c
> +++ b/libdtrace/dt_open.c
> @@ -739,8 +739,6 @@ dt_vopen(int version, int flags, int *errp,
> dt_proc_hash_create(dtp);
> dt_proc_signal_init(dtp);
> dtp->dt_proc_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
> - dtp->dt_nextepid = 1;
> - dtp->dt_maxprobe = 0;
> if (dt_aggregate_init(dtp) == -1)
> return set_open_errno(dtp, errp, dtrace_errno(dtp));
> dtp->dt_vmax = DT_VERS_LATEST;
> @@ -1303,7 +1301,6 @@ dtrace_close(dtrace_hdl_t *dtp)
> if (dtp->dt_poll_fd != -1)
> close(dtp->dt_poll_fd);
>
> - dt_epid_destroy(dtp);
> dt_aggid_destroy(dtp);
> dt_buffered_destroy(dtp);
> dt_aggregate_destroy(dtp);
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp
2024-08-29 20:31 ` [DTrace-devel] " Sam James
@ 2024-09-03 19:54 ` Eugene Loh
2024-09-03 20:10 ` Kris Van Hees
0 siblings, 1 reply; 44+ messages in thread
From: Eugene Loh @ 2024-09-03 19:54 UTC (permalink / raw)
To: Sam James, eugene.loh--- via DTrace-devel; +Cc: dtrace
On 8/29/24 16:31, Sam James wrote:
> "eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
>
>> From: Eugene Loh <eugene.loh@oracle.com>
> Not that it really matters here, but I wonder why not an enum?
Yeah, good question. No particular good answer, I suppose. If someone
wants it, I suppose I can revise the patch. I would say that this would
not be the most striking use of #define for enumerating values. E.g.,
DIF_SUBR_*, DOF_SECT_*, DTRACEFLT_*, DTRACEOPT_*, DTRACE_STABILITY_*,
DTRACE_CLASS_*, DTRACE_CONST_*, DT_IDENT_*, DT_LINK_*, DT_PRAGMA_*,
DTRACE_CONSUME_*, DTRACE_STATUS_*, DTRACE_TRACEMEM_*, DTRACE_AGGWALK_*,
and DTRACE_OBJ_*. All give symbolic names to sequences of integers
using #define. There is strong precedence for the practice.
>> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
>> @@ -232,6 +233,10 @@ grow_strtab(dtrace_hdl_t *dtp)
>> +#define USDT_FLAG_UNINITIALIZED 0
>> +#define USDT_FLAG_POSSIBLE 1
>> +#define USDT_FLAG_IGNORE 2
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp
2024-09-03 19:54 ` Eugene Loh
@ 2024-09-03 20:10 ` Kris Van Hees
0 siblings, 0 replies; 44+ messages in thread
From: Kris Van Hees @ 2024-09-03 20:10 UTC (permalink / raw)
To: Eugene Loh; +Cc: Sam James, eugene.loh--- via DTrace-devel, dtrace
On Tue, Sep 03, 2024 at 03:54:00PM -0400, Eugene Loh via DTrace-devel wrote:
> On 8/29/24 16:31, Sam James wrote:
>
> > "eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
> >
> > > From: Eugene Loh <eugene.loh@oracle.com>
> > Not that it really matters here, but I wonder why not an enum?
>
> Yeah, good question. No particular good answer, I suppose. If someone
> wants it, I suppose I can revise the patch. I would say that this would not
> be the most striking use of #define for enumerating values. E.g.,
> DIF_SUBR_*, DOF_SECT_*, DTRACEFLT_*, DTRACEOPT_*, DTRACE_STABILITY_*,
> DTRACE_CLASS_*, DTRACE_CONST_*, DT_IDENT_*, DT_LINK_*, DT_PRAGMA_*,
> DTRACE_CONSUME_*, DTRACE_STATUS_*, DTRACE_TRACEMEM_*, DTRACE_AGGWALK_*, and
> DTRACE_OBJ_*. All give symbolic names to sequences of integers using
> #define. There is strong precedence for the practice.
I'd say that is merely because that is what the original developers of DTrace
used. We certainly do not need to follow their practice. But either way, I
don't have a real preference here.
Further review comments on this patch to come (soonish).
> > > diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> > > @@ -232,6 +233,10 @@ grow_strtab(dtrace_hdl_t *dtp)
> > > +#define USDT_FLAG_UNINITIALIZED 0
> > > +#define USDT_FLAG_POSSIBLE 1
> > > +#define USDT_FLAG_IGNORE 2
>
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel@oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 06/19] Allow for USDT wildcards
2024-08-29 5:25 ` [PATCH 06/19] Allow for USDT wildcards eugene.loh
@ 2024-09-17 17:34 ` Eugene Loh
0 siblings, 0 replies; 44+ messages in thread
From: Eugene Loh @ 2024-09-17 17:34 UTC (permalink / raw)
To: dtrace, dtrace-devel
This patch should really be part of a later patch (11/19 "Support USDT
wildcard provider descriptions"). When the two changes are separated,
the intervening patches are broken.
I'm withdrawing this patch, squashing it instead into the later 11/19
patch. I'll post a new version of that 11/19 patch.
On 8/29/24 01:25, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> To look for pid probes, we can require that the provider description
> should end in a digit. For USDT probes, however, there can be wildcard
> descriptions. This includes a blank provider description as well as
> a description that ends in an '*'.
>
> So expand the criteria appropriately.
> ---
> libdtrace/dt_cc.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
> index cfd4d3d1..a9934d10 100644
> --- a/libdtrace/dt_cc.c
> +++ b/libdtrace/dt_cc.c
> @@ -278,8 +278,9 @@ dt_setcontext(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
> * On an error, dt_pid_create_probes() will set the error message
> * and tag -- we just have to longjmp() out of here.
> */
> - if (pdp->prv && pdp->prv[0] &&
> - isdigit(pdp->prv[strlen(pdp->prv) - 1]) &&
> + if (pdp->prv &&
> + (pdp->prv[0] == '\0' || isdigit(pdp->prv[strlen(pdp->prv) - 1]) ||
> + pdp->prv[strlen(pdp->prv) - 1] == '*') &&
> ((pvp = dt_provider_lookup(dtp, pdp->prv)) == NULL ||
> pvp->pv_flags & DT_PROVIDER_PID) &&
> dt_pid_create_probes((dtrace_probedesc_t *)pdp, dtp, yypcb, 0) != 0) {
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 01/19] Change probes from having lists of clauses to lists of stmts
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
` (17 preceding siblings ...)
2024-08-29 5:25 ` [PATCH 19/19] test: Add another USDT open/close test eugene.loh
@ 2024-09-18 14:18 ` Kris Van Hees
18 siblings, 0 replies; 44+ messages in thread
From: Kris Van Hees @ 2024-09-18 14:18 UTC (permalink / raw)
To: eugene.loh; +Cc: dtrace, dtrace-devel
On Thu, Aug 29, 2024 at 01:25:40AM -0400, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> Each stmt has a clause and a probe description. Traditionally,
> we have added clauses to probes. Further, we have generated an
> enabled probe ID for each probe/clause combination, and the
> consumer has use the EPID to determine the PRID as well as the
> data descriptor for the clause.
>
> In an up-coming patch, we will move to a new scheme, in which a
> widened EPID will have the PRID in its upper 32 bits and a stmt
> ID in the lower 32 bits. The stmt ID will be used to identify
> clauses to call as well as the data descriptor for the clause.
No widening of EPID is happening anymore so the above paragraph needs
to be amended. Or can be omitted actually. I don't think it needed.
> In this patch, change from probes having clauses associated
> with them to having stmts.
>
> We move the definition of dt_probe_clause_t in dt_probe.c to
> be a definition of dt_probe_stmt_t in dt_impl.h so that the
> type will become available for providers that will need it.
No further patch seems to be using dt_probe_stmt_t *and* even if they
need to, they can just include probe.h, so I would still leave the
type in dt_probe.c.
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_cg.c | 17 +++++----
> libdtrace/dt_impl.h | 5 +++
> libdtrace/dt_probe.c | 79 +++++++++++++++++++++++-------------------
> libdtrace/dt_probe.h | 12 +++----
> libdtrace/dt_program.c | 8 ++---
> 5 files changed, 66 insertions(+), 55 deletions(-)
>
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index 4fab8eed..a7861829 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -844,9 +844,10 @@ typedef struct {
> } dt_clause_arg_t;
>
> static int
> -dt_cg_call_clause(dtrace_hdl_t *dtp, dt_ident_t *idp, dt_clause_arg_t *arg)
> +dt_cg_call_clause(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp, dt_clause_arg_t *arg)
> {
> dt_irlist_t *dlp = arg->dlp;
> + dt_ident_t *idp = sdp->dtsd_clause;
>
> /*
> * if (*dctx.act != act) // ldw %r0, [%r9 + DCTX_ACT]
> @@ -874,14 +875,12 @@ dt_cg_call_clause(dtrace_hdl_t *dtp, dt_ident_t *idp, dt_clause_arg_t *arg)
> }
>
> void
> -dt_cg_tramp_call_clauses(dt_pcb_t *pcb, const dt_probe_t *prp,
> - dt_activity_t act)
> +dt_cg_tramp_call_clauses(dt_pcb_t *pcb, const dt_probe_t *prp, dt_activity_t act)
> {
> dt_irlist_t *dlp = &pcb->pcb_ir;
> dt_clause_arg_t arg = { dlp, act, pcb->pcb_exitlbl };
>
> - dt_probe_clause_iter(pcb->pcb_hdl, prp,
> - (dt_clause_f *)dt_cg_call_clause, &arg);
> + dt_probe_stmt_iter(pcb->pcb_hdl, prp, (dt_stmt_f *)dt_cg_call_clause, &arg);
> }
>
> static int
> @@ -990,9 +989,10 @@ dt_cg_tramp_epilogue_advance(dt_pcb_t *pcb, dt_activity_t act)
> }
>
> static int
> -dt_cg_tramp_error_call_clause(dtrace_hdl_t *dtp, dt_ident_t *idp,
> - dt_irlist_t *dlp)
> +dt_cg_tramp_error_call_clause(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp, dt_irlist_t *dlp)
> {
> + dt_ident_t *idp = sdp->dtsd_clause;
> +
> /*
> * dt_error_#(dctx); // mov %r1, %r9
> * // call dt_error_#
> @@ -1029,8 +1029,7 @@ dt_cg_tramp_error(dt_pcb_t *pcb)
> TRACE_REGSET("Trampoline: Begin");
> emit(dlp, BPF_MOV_REG(BPF_REG_9, BPF_REG_1));
>
> - dt_probe_clause_iter(dtp, dtp->dt_error,
> - (dt_clause_f *)dt_cg_tramp_error_call_clause, dlp);
> + dt_probe_stmt_iter(dtp, dtp->dt_error, (dt_stmt_f *)dt_cg_tramp_error_call_clause, dlp);
>
> emit(dlp, BPF_MOV_IMM(BPF_REG_0, 0));
> emit(dlp, BPF_RETURN());
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index 44dd1415..98fddc23 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -258,6 +258,11 @@ typedef struct dt_percpu_drops {
>
> typedef uint32_t dt_version_t; /* encoded version (see below) */
>
> +typedef struct dt_probe_stmt {
> + dt_list_t list;
> + dtrace_stmtdesc_t *stmt;
> +} dt_probe_stmt_t;
> +
> struct dtrace_hdl {
> const dtrace_vector_t *dt_vector; /* library vector, if vectored open */
> void *dt_varg; /* vector argument, if vectored open */
> diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
> index ab90d2ed..bb28bbed 100644
> --- a/libdtrace/dt_probe.c
> +++ b/libdtrace/dt_probe.c
> @@ -24,11 +24,6 @@
> #include <dt_list.h>
> #include <dt_bpf.h>
>
> -typedef struct dt_probe_clause {
> - dt_list_t list;
> - dt_ident_t *clause;
> -} dt_probe_clause_t;
> -
> typedef struct dt_probe_dependent {
> dt_list_t list;
> dt_probe_t *probe;
> @@ -467,7 +462,7 @@ dt_probe_enable(dtrace_hdl_t *dtp, dt_probe_t *prp)
> void
> dt_probe_destroy(dt_probe_t *prp)
> {
> - dt_probe_clause_t *pcp, *pcp_next;
> + dt_probe_stmt_t *psp, *psp_next;
> dt_probe_instance_t *pip, *pip_next;
> dt_probe_dependent_t *dep, *dep_next;
> dtrace_hdl_t *dtp;
> @@ -499,9 +494,18 @@ dt_probe_destroy(dt_probe_t *prp)
> dt_free(dtp, prp->nargv);
> dt_free(dtp, prp->xargv);
>
> - for (pcp = dt_list_next(&prp->clauses); pcp != NULL; pcp = pcp_next) {
> - pcp_next = dt_list_next(pcp);
> - dt_free(dtp, pcp);
> + for (psp = dt_list_next(&prp->stmts); psp != NULL; psp = psp_next) {
> + psp_next = dt_list_next(psp);
> +
> + /*
> + * FIXME? Is there nothing inside we also need to free?
> + *
> + * If psp->stmt was created with dt_probe_error_stmt(), maybe:
> + * dt_ident_t *idp = psp->stmt->dtsd_clause;
> + * dt_iddtor_difo(idp);
> + * dt_ident_destroy(idp);
> + */
Since the identifier for the clause is added to the identifier hash, it will
be cleaned up when that hash is deleted, and the idops associated with the
clause identifier ensures that the identifier cleanup also gets rid of the
DIFO.
So the FIXME can be dropped.
> + dt_free(dtp, psp);
> }
>
> for (dep = dt_list_next(&prp->dependents); dep != NULL; dep = dep_next) {
> @@ -1283,24 +1287,24 @@ dtrace_probe_iter(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
> }
>
> /*
> - * Create an ERROR-probe specific copy of a given clause.
> + * Create an ERROR-probe specific copy of a given stmt.
> *
> - * A modified copy of the clause is necessary because the ERROR probe may share
> - * some clauses with other probes, and yet it needs to be handled differently.
> + * A modified copy of the stmt is necessary because the ERROR probe may share
> + * some stmts with other probes, and yet it needs to be handled differently.
> *
> - * The following modifications are made in the copy of the clause:
> - *
> - * - it is named dt_error_N where N is taken from the original clause
> - * dt_clause_N (which also guarantees uniqueness)
> + * In the copy of the stmt, the clause is named dt_error_N, where N is taken
> + * from the original stmt's dt_clause_N (which also guarantees uniqueness).
> */
> -dt_ident_t *
> -dt_probe_error_clause(dtrace_hdl_t *dtp, dt_ident_t *idp)
> +static dtrace_stmtdesc_t *
> +dt_probe_error_stmt(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
> {
> char *name;
> int len;
> + dt_ident_t *idp = sdp->dtsd_clause;
> dtrace_difo_t *dp = dt_dlib_get_func_difo(dtp, idp);
> dt_ident_t *nidp = NULL;
> dtrace_difo_t *ndp;
> + dtrace_stmtdesc_t *nsdp = NULL;
>
> /*
> * Copy the DIFO.
> @@ -1316,7 +1320,6 @@ dt_probe_error_clause(dtrace_hdl_t *dtp, dt_ident_t *idp)
> name = dt_alloc(dtp, len);
> if (name == NULL)
> goto no_mem;
> -
> snprintf(name, len, "dt_error_%s", idp->di_name + strlen("dt_clause_"));
>
> /*
> @@ -1330,7 +1333,12 @@ dt_probe_error_clause(dtrace_hdl_t *dtp, dt_ident_t *idp)
>
> dt_ident_set_data(nidp, ndp);
>
> - return nidp;
> + nsdp = dt_alloc(dtp, sizeof(dtrace_stmtdesc_t));
> + if (nsdp == NULL)
> + goto no_mem;
> + nsdp->dtsd_clause = nidp;
> +
> + return nsdp;
>
> no_mem:
> if (ndp != NULL)
> @@ -1343,40 +1351,39 @@ no_mem:
> }
>
> int
> -dt_probe_add_clause(dtrace_hdl_t *dtp, dt_probe_t *prp, dt_ident_t *idp)
> +dt_probe_add_stmt(dtrace_hdl_t *dtp, dt_probe_t *prp, dtrace_stmtdesc_t *sdp)
> {
> - dt_probe_clause_t *pcp;
> + dt_probe_stmt_t *psp;
>
> - pcp = dt_zalloc(dtp, sizeof(dt_probe_clause_t));
> - if (pcp == NULL)
> + psp = dt_zalloc(dtp, sizeof(dt_probe_stmt_t));
> + if (psp == NULL)
> return dt_set_errno(dtp, EDT_NOMEM);
>
> if (prp == dtp->dt_error) {
> - pcp->clause = dt_probe_error_clause(dtp, idp);
> - if (pcp->clause == NULL) {
> - dt_free(dtp, pcp);
> + psp->stmt = dt_probe_error_stmt(dtp, sdp);
> + if (psp->stmt == NULL) {
> + dt_free(dtp, psp);
> return 0;
> }
> } else
> - pcp->clause = idp;
> + psp->stmt = sdp;
>
> - dt_list_append(&prp->clauses, pcp);
> + dt_list_append(&prp->stmts, psp);
>
> return 0;
> }
>
> int
> -dt_probe_clause_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
> - dt_clause_f *func, void *arg)
> +dt_probe_stmt_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp, dt_stmt_f *func, void *arg)
> {
> - dt_probe_clause_t *pcp;
> - int rc;
> + dt_probe_stmt_t *psp;
> + int rc;
>
> assert(func != NULL);
>
> - for (pcp = dt_list_next(&prp->clauses); pcp != NULL;
> - pcp = dt_list_next(pcp)) {
> - rc = func(dtp, pcp->clause, arg);
> + for (psp = dt_list_next(&prp->stmts); psp != NULL;
> + psp = dt_list_next(psp)) {
> + rc = func(dtp, psp->stmt, arg);
>
> if (rc != 0)
> return rc;
> diff --git a/libdtrace/dt_probe.h b/libdtrace/dt_probe.h
> index b4c1a3e4..2a78cb9c 100644
> --- a/libdtrace/dt_probe.h
> +++ b/libdtrace/dt_probe.h
> @@ -32,7 +32,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 stmts; /* stmts */
> 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 */
> @@ -86,11 +86,11 @@ typedef int dt_probe_f(dtrace_hdl_t *dtp, dt_probe_t *prp, void *arg);
> extern int dt_probe_iter(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
> dt_probe_f *pfunc, dtrace_probe_f *dfunc, void *arg);
>
> -extern int dt_probe_add_clause(dtrace_hdl_t *dtp, dt_probe_t *prp,
> - dt_ident_t *idp);
> -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_stmt(dtrace_hdl_t *dtp, dt_probe_t *prp,
> + dtrace_stmtdesc_t *sdp);
> +typedef int dt_stmt_f(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp, void *arg);
> +extern int dt_probe_stmt_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp,
> + dt_stmt_f *func, void *arg);
>
> extern int dt_probe_add_dependent(dtrace_hdl_t *dtp, dt_probe_t *prp,
> dt_probe_t *idprp);
> diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c
> index bdb434e0..afbf7265 100644
> --- a/libdtrace/dt_program.c
> +++ b/libdtrace/dt_program.c
> @@ -139,8 +139,8 @@ dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
> }
>
> typedef struct pi_state {
> - int *cnt;
> - dt_ident_t *idp;
> + int *cnt;
> + dtrace_stmtdesc_t *sdp;
> } pi_state_t;
>
> static int
> @@ -151,7 +151,7 @@ dt_stmt_probe(dtrace_hdl_t *dtp, dt_probe_t *prp, pi_state_t *st)
> dt_probe_info(dtp, prp->desc, &p);
> dt_probe_enable(dtp, prp);
>
> - dt_probe_add_clause(dtp, prp, st->idp);
> + dt_probe_add_stmt(dtp, prp, st->sdp);
> (*st->cnt)++;
>
> return 0;
> @@ -166,7 +166,7 @@ dt_prog_stmt(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp,
> int rc;
>
> st.cnt = cnt;
> - st.idp = sdp->dtsd_clause;
> + st.sdp = sdp;
> rc = dt_probe_iter(dtp, pdp, (dt_probe_f *)dt_stmt_probe, NULL, &st);
>
> /*
> --
> 2.43.5
>
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 05/19] Add flag to dt_pid_create_probes()
2024-08-29 5:25 ` [PATCH 05/19] Add flag to dt_pid_create_probes() eugene.loh
@ 2024-09-18 20:33 ` Kris Van Hees
2024-09-24 20:24 ` Eugene Loh
0 siblings, 1 reply; 44+ messages in thread
From: Kris Van Hees @ 2024-09-18 20:33 UTC (permalink / raw)
To: eugene.loh; +Cc: dtrace, dtrace-devel
On Thu, Aug 29, 2024 at 01:25:44AM -0400, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> The function dt_pid_create_probes() creates both pid and usdt probes.
> Once the dtrace session has started, however, we only need to watch
> for new usdt probes. So add a usdt_only argument to the function.
It would be better I think to create two functions, one for trying to match pid
probes, and one for trying to match USDT probes, and to call those two functions
from dt_pid_create_probes(). And then, after tracing has started, only the one
dealing with USDT probes needs to be called.
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_cc.c | 2 +-
> libdtrace/dt_pid.c | 4 ++--
> libdtrace/dt_pid.h | 3 +--
> 3 files changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
> index e66d76fb..cfd4d3d1 100644
> --- a/libdtrace/dt_cc.c
> +++ b/libdtrace/dt_cc.c
> @@ -282,7 +282,7 @@ dt_setcontext(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
> isdigit(pdp->prv[strlen(pdp->prv) - 1]) &&
> ((pvp = dt_provider_lookup(dtp, pdp->prv)) == NULL ||
> pvp->pv_flags & DT_PROVIDER_PID) &&
> - dt_pid_create_probes((dtrace_probedesc_t *)pdp, dtp, yypcb) != 0) {
> + dt_pid_create_probes((dtrace_probedesc_t *)pdp, dtp, yypcb, 0) != 0) {
> longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER);
> }
>
> diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
> index 996543b1..3f3453af 100644
> --- a/libdtrace/dt_pid.c
> +++ b/libdtrace/dt_pid.c
> @@ -1095,7 +1095,7 @@ dt_pid_get_pid(const dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
> }
>
> int
> -dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
> +dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb, int usdt_only)
> {
> char provname[DTRACE_PROVNAMELEN];
> dt_proc_t *dpr;
> @@ -1109,7 +1109,7 @@ dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
>
> snprintf(provname, sizeof(provname), "pid%d", (int)pid);
>
> - if (gmatch(provname, pdp->prv) != 0) {
> + if ((usdt_only == 0) && gmatch(provname, pdp->prv) != 0) {
> if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING) < 0) {
> dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB,
> "failed to grab process %d", (int)pid);
> diff --git a/libdtrace/dt_pid.h b/libdtrace/dt_pid.h
> index 497c7751..dc200f4d 100644
> --- a/libdtrace/dt_pid.h
> +++ b/libdtrace/dt_pid.h
> @@ -16,8 +16,7 @@
> extern "C" {
> #endif
>
> -extern int dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *,
> - dt_pcb_t *);
> +extern int dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *, dt_pcb_t *, int);
> extern int dt_pid_create_probes_module(dtrace_hdl_t *, dt_proc_t *);
> extern pid_t dt_pid_get_pid(const dtrace_probedesc_t *, dtrace_hdl_t *, dt_pcb_t *,
> dt_proc_t *);
> --
> 2.43.5
>
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 05/19] Add flag to dt_pid_create_probes()
2024-09-18 20:33 ` Kris Van Hees
@ 2024-09-24 20:24 ` Eugene Loh
0 siblings, 0 replies; 44+ messages in thread
From: Eugene Loh @ 2024-09-24 20:24 UTC (permalink / raw)
To: dtrace, dtrace-devel
Okay. I'll patch a v2, whose Subject will now be: "Split
dt_pid_create_probes() into pid and USDT functions". There are
cascading impacts on some other following patches. So, I'll post new
versions of those patches as well.
On 9/18/24 16:33, Kris Van Hees wrote:
> On Thu, Aug 29, 2024 at 01:25:44AM -0400, eugene.loh@oracle.com wrote:
>> From: Eugene Loh <eugene.loh@oracle.com>
>>
>> The function dt_pid_create_probes() creates both pid and usdt probes.
>> Once the dtrace session has started, however, we only need to watch
>> for new usdt probes. So add a usdt_only argument to the function.
> It would be better I think to create two functions, one for trying to match pid
> probes, and one for trying to match USDT probes, and to call those two functions
> from dt_pid_create_probes(). And then, after tracing has started, only the one
> dealing with USDT probes needs to be called.
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 18/19] test: Add a lazy USDT test
2024-08-29 5:25 ` [PATCH 18/19] test: Add a lazy USDT test eugene.loh
@ 2024-09-28 2:11 ` Eugene Loh
0 siblings, 0 replies; 44+ messages in thread
From: Eugene Loh @ 2024-09-28 2:11 UTC (permalink / raw)
To: dtrace, dtrace-devel
I'm withdrawing this patch. The reason is I'm going to send a short
patch series on tracing USDT processes that appear after the dtrace
session has started. It will include new tests, and this test fits in
better there.
The new patch series will also expect the update_uprobe() function to
return an error code. So that modifies:
Add a hook for a provider-specific "update" function
Create the BPF usdt_prids map
and I'll send new versions of those patches out as well.
On 8/29/24 01:25, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> When new USDT processes start up, we do not immediately know
> about their probes. Our detecting these processes is "lazy."
> First, dtprobed has to see these processes and then dtrace has
> to find them. Hence, many of our tests XFAIL.
>
> Introduce a test that accounts for such laziness. That is,
> the target program spins in "phase 1" waiting for USR1. Our
> D script watches for a USDT probe in phase 1 and raises the
> anticipated USR1.
>
> Then we expect every USDT probe during phase 2 to fire.
>
> Currently, another limitation is that at least one USDT process
> has to be running when the dtrace session starts. So, start
> one process first, then the dtrace session, then many more processes.
>
> We start "many" processes so that we can filter on pids. Specifically,
> we expect the phase 2 USDT probe to match the last digit of the pid.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> test/unittest/usdt/tst.lazy.r | 1 +
> test/unittest/usdt/tst.lazy.sh | 245 +++++++++++++++++++++++++++++++++
> 2 files changed, 246 insertions(+)
> create mode 100644 test/unittest/usdt/tst.lazy.r
> create mode 100755 test/unittest/usdt/tst.lazy.sh
>
> diff --git a/test/unittest/usdt/tst.lazy.r b/test/unittest/usdt/tst.lazy.r
> new file mode 100644
> index 00000000..2e9ba477
> --- /dev/null
> +++ b/test/unittest/usdt/tst.lazy.r
> @@ -0,0 +1 @@
> +success
> diff --git a/test/unittest/usdt/tst.lazy.sh b/test/unittest/usdt/tst.lazy.sh
> new file mode 100755
> index 00000000..348a70f6
> --- /dev/null
> +++ b/test/unittest/usdt/tst.lazy.sh
> @@ -0,0 +1,245 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +#
> +# This test verifies that USDT will see new processes, even if detection
> +# is lazy.
> +
> +dtrace=$1
> +
> +# Set up test directory.
> +
> +DIRNAME=$tmpdir/lazy.$$.$RANDOM
> +mkdir -p $DIRNAME
> +cd $DIRNAME
> +
> +# Create test source files.
> +
> +cat > prov.d <<EOF
> +provider testprov {
> + probe foo();
> + probe bar(int, int, int);
> +};
> +EOF
> +
> +cat > main.c <<EOF
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include "prov.h"
> +
> +static int phase = 1;
> +
> +static void
> +interrupt(int sig)
> +{
> + phase = 2;
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> + struct sigaction act;
> + int i;
> + int nphase1 = 0, nphase1foo = 0, nphase1bar = 0;
> + int nphase2 = 0, nphase2foo = 0, nphase2bar = 0;
> +
> + /* set the handler to listen for SIGUSR1 */
> + act.sa_handler = interrupt;
> + act.sa_flags = 0;
> + if (sigaction(SIGUSR1, &act, NULL)) {
> + printf("set handler failed\n");
> + return 1;
> + }
> +
> + /* in phase 1, loop on probe "foo" to wait on USR1 */
> + while (phase == 1) {
> + nphase1++;
> + if (TESTPROV_FOO_ENABLED()) {
> + nphase1foo++;
> + phase = 2;
> + }
> + if (TESTPROV_BAR_ENABLED()) {
> + nphase1bar++;
> + phase = 2;
> + }
> + TESTPROV_FOO();
> + }
> +
> + /* in phase 2, just loop over probe "bar" a fixed number of times */
> + for (int i = 0; i < 10; i++) {
> + nphase2++;
> + usleep(2000);
> + if (TESTPROV_FOO_ENABLED())
> + nphase2foo++;
> + usleep(2000);
> + if (TESTPROV_BAR_ENABLED())
> + nphase2bar++;
> + usleep(2000);
> + TESTPROV_BAR(i, i + 2, i * 2);
> + }
> +
> + printf("%d: %d %d %d %d %d %d\n", getpid(),
> + nphase1, nphase1foo, nphase1bar, nphase2, nphase2foo, nphase2bar);
> +
> + return 0;
> +}
> +EOF
> +
> +# Build the test program.
> +
> +$dtrace -h -s prov.d
> +if [ $? -ne 0 ]; then
> + echo "failed to generate header file" >&2
> + exit 1
> +fi
> +cc $test_cppflags -c main.c
> +if [ $? -ne 0 ]; then
> + echo "failed to compile test" >&2
> + exit 1
> +fi
> +$dtrace -G -64 -s prov.d main.o
> +if [ $? -ne 0 ]; then
> + echo "failed to create DOF" >&2
> + exit 1
> +fi
> +cc $test_cppflags -o main main.o prov.o
> +if [ $? -ne 0 ]; then
> + echo "failed to link final executable" >&2
> + exit 1
> +fi
> +
> +# Check that the is-enabled probes are false when the USDT probes are not enabled.
> +# That is, nphase1foo == nphase1bar == nphase2foo == nphase2bar == 0.
> +# Also, nphase2 == 10.
> +# Note that nphase1 will be undefined.
> +
> +./main > main.out &
> +pid=$!
> +sleep 1
> +kill -USR1 $pid
> +wait
> +
> +echo "$pid: undefined 0 0 10 0 0" > main.out.expected
> +if ! awk '{ $2 = "undefined"; print }' main.out | diff -q - main.out.expected; then
> + echo program output looks wrong for the no-DTrace case
> + echo === got ===
> + cat main.out
> + echo === expected ===
> + cat main.out.expected
> + exit 1
> +fi
> +
> +# Run dtrace.
> +
> +num=10
> +
> +# Start one process.
> +./main > main.out0 &
> +pids[0]=$!
> +i=1
> +
> +# Figure out the pid's trailing digit.
> +lastdigit=$((${pids[0]} % 10))
> +
> +# Start dtrace.
> +$dtrace $dt_flags -wq -o dtrace.out -n '
> +testprov*:::foo
> +{
> + raise(SIGUSR1);
> +}
> +testprov*'$lastdigit':::bar
> +{
> + @[pid, 0] = sum(arg0);
> + @[pid, 1] = sum(arg1);
> + @[pid, 2] = sum(arg2);
> +}' &
> +dtpid=$!
> +sleep 2
> +
> +# Start remaining processes.
> +while [ $i -lt $num ]; do
> + ./main > main.out$i &
> + pids[$i]=$!
> + i=$(($i + 1))
> +done
> +
> +# Wait for processes to complete.
> +
> +i=0
> +while [ $i -lt $num ]; do
> + wait ${pids[$i]}
> + i=$(($i + 1))
> +done
> +
> +# Kill the dtrace process.
> +
> +kill $dtpid
> +wait
> +
> +# Check the program output (main.out$i files).
> +
> +i=0
> +while [ $i -lt $num ]; do
> + if [ $((${pids[$i]} % 10)) -eq $lastdigit ]; then
> + nphase2bar=10
> + else
> + nphase2bar=0
> + fi
> + echo "${pids[$i]}: undefined 0 0 10 10 $nphase2bar" > main.out$i.expected
> + awk '
> + $3 == "1" { $3 = 0 } # in phase 1, round 1 down to 0
> + $4 == "1" { $4 = 0 } # in phase 1, round 1 down to 0
> + { $2 = "undefined"; print }' main.out$i > main.out$i.post
> + if ! diff -q main.out$i.post main.out$i.expected; then
> + echo program output looks wrong for DTrace case $i
> + echo === was ===
> + cat main.out$i
> + echo === got ===
> + cat main.out$i.post
> + echo === expected ===
> + cat main.out$i.expected
> + exit 1
> + fi
> + i=$(($i + 1))
> +done
> +
> +# Check the dtrace output.
> +
> +# regularize the dtrace output.
> +awk 'NF != 0 { print $1, $2, $3 }' dtrace.out | sort > dtrace.out.post
> +
> +# determine what to expect
> +
> +i=0
> +while [ $i -lt $num ]; do
> + if [ $((${pids[$i]} % 10)) -eq $lastdigit ]; then
> + echo ${pids[$i]} 0 45 >> dtrace.out.expected
> + echo ${pids[$i]} 1 65 >> dtrace.out.expected
> + echo ${pids[$i]} 2 90 >> dtrace.out.expected
> + fi
> +
> + i=$(($i + 1))
> +done
> +
> +# diff
> +if ! sort dtrace.out.expected | diff -q - dtrace.out.post; then
> + echo dtrace output looks wrong for DTrace case $i
> + echo === was ===
> + cat dtrace.out
> + echo === got ===
> + cat dtrace.out.post
> + echo === expected ===
> + sort dtrace.out.expected
> + echo === diff ===
> + sort dtrace.out.expected | diff - dtrace.out.post
> + exit 1
> +fi
> +
> +echo success
> +
> +exit 0
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 17/19] test: Add a pid-USDT test
2024-08-29 20:32 ` [DTrace-devel] " Sam James
@ 2024-10-04 4:49 ` Eugene Loh
2024-10-04 5:51 ` Sam James
0 siblings, 1 reply; 44+ messages in thread
From: Eugene Loh @ 2024-10-04 4:49 UTC (permalink / raw)
To: Sam James, eugene.loh--- via DTrace-devel; +Cc: dtrace
On 8/29/24 16:32, Sam James wrote:
> "eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
>
>> From: Eugene Loh <eugene.loh@oracle.com>
>>
>> This checks that pid entry, pid return, pid offset, USDT, and USDT
>> is-enabled probes can all coexist. Specifically, pid offset probes
>> can sit on the same PCs as pid entry, USDT, and USDT is-enabled
>> probes.
>>
>> Note that PCs for pid return probes are apparently in the caller
>> function. I guess that's due to using uretprobe. I'm not convinced
>> yet that that isn't a bug. It isn't what Solaris did.
>>
>> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
>> ---
>> test/unittest/usdt/tst.pidprobes.r | 1 +
>> test/unittest/usdt/tst.pidprobes.sh | 243 ++++++++++++++++++++++++++++
>> 2 files changed, 244 insertions(+)
>> create mode 100644 test/unittest/usdt/tst.pidprobes.r
>> create mode 100755 test/unittest/usdt/tst.pidprobes.sh
>>
>> diff --git a/test/unittest/usdt/tst.pidprobes.r b/test/unittest/usdt/tst.pidprobes.r
>> new file mode 100644
>> index 00000000..2e9ba477
>> --- /dev/null
>> +++ b/test/unittest/usdt/tst.pidprobes.r
>> @@ -0,0 +1 @@
>> +success
>> diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh
>> new file mode 100755
>> index 00000000..7eadb9b7
>> --- /dev/null
>> +++ b/test/unittest/usdt/tst.pidprobes.sh
>> @@ -0,0 +1,243 @@
>> +#!/bin/bash
>> +#
>> +# Oracle Linux DTrace.
>> +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
>> +# Licensed under the Universal Permissive License v 1.0 as shown at
>> +# http://oss.oracle.com/licenses/upl.
>> +#
>> +# This test verifies that USDT and pid probes can share underlying probes.
>> +
>> +dtrace=$1
>> +
>> +# Set up test directory.
>> +
>> +DIRNAME=$tmpdir/pidprobes.$$.$RANDOM
>> +mkdir -p $DIRNAME
>> +cd $DIRNAME
>> +
> Let's do mktemp -d?
Thanks. On the other hand, that sequence is very common in the test
suite. Maybe there should be a massive conversion to mktemp if we want
to go that route.
>> [...]
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 17/19] test: Add a pid-USDT test
2024-10-04 4:49 ` Eugene Loh
@ 2024-10-04 5:51 ` Sam James
0 siblings, 0 replies; 44+ messages in thread
From: Sam James @ 2024-10-04 5:51 UTC (permalink / raw)
To: Eugene Loh; +Cc: eugene.loh--- via DTrace-devel, dtrace
Eugene Loh <eugene.loh@oracle.com> writes:
> On 8/29/24 16:32, Sam James wrote:
>> "eugene.loh--- via DTrace-devel" <dtrace-devel@oss.oracle.com> writes:
>>
>>> From: Eugene Loh <eugene.loh@oracle.com>
>>>
>>> This checks that pid entry, pid return, pid offset, USDT, and USDT
>>> is-enabled probes can all coexist. Specifically, pid offset probes
>>> can sit on the same PCs as pid entry, USDT, and USDT is-enabled
>>> probes.
>>>
>>> Note that PCs for pid return probes are apparently in the caller
>>> function. I guess that's due to using uretprobe. I'm not convinced
>>> yet that that isn't a bug. It isn't what Solaris did.
>>>
>>> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
>>> ---
>>> test/unittest/usdt/tst.pidprobes.r | 1 +
>>> test/unittest/usdt/tst.pidprobes.sh | 243 ++++++++++++++++++++++++++++
>>> 2 files changed, 244 insertions(+)
>>> create mode 100644 test/unittest/usdt/tst.pidprobes.r
>>> create mode 100755 test/unittest/usdt/tst.pidprobes.sh
>>>
>>> diff --git a/test/unittest/usdt/tst.pidprobes.r b/test/unittest/usdt/tst.pidprobes.r
>>> new file mode 100644
>>> index 00000000..2e9ba477
>>> --- /dev/null
>>> +++ b/test/unittest/usdt/tst.pidprobes.r
>>> @@ -0,0 +1 @@
>>> +success
>>> diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh
>>> new file mode 100755
>>> index 00000000..7eadb9b7
>>> --- /dev/null
>>> +++ b/test/unittest/usdt/tst.pidprobes.sh
>>> @@ -0,0 +1,243 @@
>>> +#!/bin/bash
>>> +#
>>> +# Oracle Linux DTrace.
>>> +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
>>> +# Licensed under the Universal Permissive License v 1.0 as shown at
>>> +# http://oss.oracle.com/licenses/upl.
>>> +#
>>> +# This test verifies that USDT and pid probes can share underlying probes.
>>> +
>>> +dtrace=$1
>>> +
>>> +# Set up test directory.
>>> +
>>> +DIRNAME=$tmpdir/pidprobes.$$.$RANDOM
>>> +mkdir -p $DIRNAME
>>> +cd $DIRNAME
>>> +
>> Let's do mktemp -d?
>
> Thanks. On the other hand, that sequence is very common in the test
> suite. Maybe there should be a massive conversion to mktemp if we
> want to go that route.
>
>>> [...]
Sure, can do. I've got some others I want to get in first.
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 12/19] Increase size of BPF probes map
2024-08-29 5:25 ` [PATCH 12/19] Increase size of BPF probes map eugene.loh
2024-08-29 20:30 ` [DTrace-devel] " Sam James
@ 2024-10-08 22:15 ` Eugene Loh
1 sibling, 0 replies; 44+ messages in thread
From: Eugene Loh @ 2024-10-08 22:15 UTC (permalink / raw)
To: dtrace, dtrace-devel
Just to be clear, this patch is (thankfully) being withdrawn. Whew.
On 8/29/24 01:25, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> We are going to support discovery of new probes after dtrace is
> launched. For example, there could be a pid or USDT probe with a
> wildcard pid specification that could be matched by a process that
> has not yet started. Or, a process could load a shared library.
>
> This means the probe map will have to grow. For now, just wire in
> some headroom, as ugly a hack as this is.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_bpf.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
> index 70803e3c..75e48962 100644
> --- a/libdtrace/dt_bpf.c
> +++ b/libdtrace/dt_bpf.c
> @@ -920,7 +920,7 @@ gmap_create_probes(dtrace_hdl_t *dtp)
>
> fd = create_gmap(dtp, "probes", BPF_MAP_TYPE_HASH, sizeof(uint32_t),
> sizeof(dt_bpf_probe_t),
> - dt_list_length(&dtp->dt_enablings));
> + dt_list_length(&dtp->dt_enablings) + 1000);
> if (fd == -1)
> return -1;
>
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline
2024-08-29 5:25 ` [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline eugene.loh
@ 2024-10-24 2:42 ` Kris Van Hees
2024-10-24 13:52 ` [DTrace-devel] " Kris Van Hees
0 siblings, 1 reply; 44+ messages in thread
From: Kris Van Hees @ 2024-10-24 2:42 UTC (permalink / raw)
To: eugene.loh; +Cc: dtrace, dtrace-devel
On Thu, Aug 29, 2024 at 01:25:47AM -0400, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> An underlying probe could support all sorts of overlying probes:
> - pid entry
> - pid return
> - pid offset
> - USDT
> - USDT is-enabled
>
> The overlying probes belonging to an underlying probe match the
> underlying probe -- except possibly in pid. So, an underlying
> probe loops over its overlying probes, looking for a pid match.
>
> The trampoline would look for only one match.
>
> However, more than one overlying probe might match. Therefore,
> change the loop to keep going even after a match has been found.
>
> Incidentally, it is actually only pid offset probes that could
> "collide" with any other overlying probes for a given pid:
>
> -) pid return probes are implemented with uretprobes
> and so cannot "collide" with any other probes
>
> -) no two USDT probes -- is-enabled or not -- can map
> to the same underlying probe for any pid
>
> -) no USDT probe -- is-enabled or not -- can map to
> to the same underlying probe as a pid entry
>
> So, possibly one could optimize the trampoline -- e.g., by adding
> BPF code to exit once two matches have been made.
>
> Incidentally, there is a small error in the patch. The flag we
> pass in to dt_cg_tramp_copy_args_from_regs() should depend on
> whether the overlying probe is a pid or USDT probe. We used to
> check PP_IS_FUNCALL, the upp could be for both. Instead of
> fixing this problem, let us simply pretend it's a pid probe --
> a later patch will move USDT probes to a different mechanism anyhow.
I think it is more clear to just keep the logic that is there for passing the
flag, even if it is not exactly correct. At least it is not a change from
something that might be wrong to something that is more likely to be wrong.
Either way, you are changing it in a subsequent patch so the change to a
hardcoded 1 is not really helping anything other than making someone perhaps
wonder why you changed it.
Alternatively, you could perhaps change the check for the PP_IS_FUNCALL flag
to checking the prp->prov->impl, and selecting 1 for dt_pid and 0 for dt_usdt?
Yes, you will change that in the subsequent patch, but it would be actually
fixing this to be the correct condition anyway, right?
Summary, wrong -> different-wrong seems silly, wrong -> wrong (keeping it
the same) is reasonable, wrong -> correct is of course preferred.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_prov_uprobe.c | 53 +++++-------
> test/unittest/pid/tst.entry_off0.sh | 125 ++++++++++++++++++++++++++++
> 2 files changed, 147 insertions(+), 31 deletions(-)
> create mode 100755 test/unittest/pid/tst.entry_off0.sh
>
> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> index 70e5c32d..bc5545fb 100644
> --- a/libdtrace/dt_prov_uprobe.c
> +++ b/libdtrace/dt_prov_uprobe.c
> @@ -687,45 +687,23 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> const list_probe_t *pop;
> uint_t lbl_exit = pcb->pcb_exitlbl;
>
> - dt_cg_tramp_prologue(pcb);
> + dt_cg_tramp_prologue(pcb); // call this only once... is PRID set/relocated correctly?
I do not believe this change is needed (adding the comment). A trampoline can
only ever have a single prologue.
>
> /*
> * After the dt_cg_tramp_prologue() call, we have:
> * // (%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);
> - else
> - dt_cg_tramp_copy_args_from_regs(pcb,
> - !(upp->flags & PP_IS_FUNCALL));
> -
> - /*
> - * Retrieve the PID of the process that caused the probe to fire.
> - */
> - emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> - emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
> + dt_cg_tramp_copy_regs(pcb); // call this only once for all clauses?
>
> /*
> - * Generate a composite conditional clause:
> - *
> - * 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 == ...) {
> - * < ... >
> - * }
> + * Loop over overlying probes, calling clauses for those that match:
> *
> - * 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.
> + * for overlying probes (that match except possibly for pid)
> + * if (pid matches) {
> + * dctx->mst->prid = PRID1;
> + * < any number of clause calls >
> + * }
> */
> for (pop = dt_list_next(&upp->probes); pop != NULL;
> pop = dt_list_next(pop)) {
> @@ -740,6 +718,20 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
> assert(idp != NULL);
>
> + /*
> + * Register copies. FIXME: What can be optimized?
> + */
I would drop the FIXME. There is not really much of anything that can be
optimized because we need the register content in case some clause makes use
of regs[]. And arguments need to be copied for argN and args[], unless we
want to implement arg-access using a provider callback during CG, and that
would be an optimization across all providers so definitely not something for
now. So, no need to have a FIXME. It's biger than USDT :)
> + if (upp->flags & PP_IS_RETURN)
> + dt_cg_tramp_copy_rval_from_regs(pcb);
> + else
> + dt_cg_tramp_copy_args_from_regs(pcb, 1);
Per my comment above, I think this should still retain the code that was here
before (well, higher up) to select the correct flag to pass rather than just
hardcoding it as 1 and mentioning it is a bug. It is easy enough to just keep
what was there as logic, and then change that in a subsequent patch.
Using (prp->prov->impl == &dt_pid ? 1 : 0) would do the trick, right?
> +
> + /*
> + * Retrieve the PID of the process that caused the probe to fire.
> + */
> + emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> + emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
Wouldn't it be better to retrieve the PID once, and store it in %r6, and then
use it at every branch rather than retrieving the PID for every case?
> +
> /*
> * Check whether this pid-provider probe serves the current
> * process, and emit a sequence of clauses for it when it does.
> @@ -747,7 +739,6 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> 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));
> emitl(dlp, lbl_next,
> BPF_NOP());
> }
> diff --git a/test/unittest/pid/tst.entry_off0.sh b/test/unittest/pid/tst.entry_off0.sh
> new file mode 100755
> index 00000000..f1a75b6a
> --- /dev/null
> +++ b/test/unittest/pid/tst.entry_off0.sh
> @@ -0,0 +1,125 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +#
> +
> +dtrace=$1
> +
> +trig=`pwd`/test/triggers/ustack-tst-basic
> +
> +DIRNAME="$tmpdir/enter_off0.$$.$RANDOM"
> +mkdir -p $DIRNAME
> +cd $DIRNAME
> +
> +# Run DTrace, dumping all probe functions and names, plus PC, in a.out.
> +
> +$dtrace $dt_flags -c $trig -n '
> +pid$target:a.out::
> +{
> + @[probefunc, probename, uregs[R_PC]] = count();
> +}
> +
> +profile:::tick-1s
> +{
> + exit(0);
> +}' > D.out
> +if [ $? -ne 0 ]; then
> + echo ERROR: dtrace
> + cat D.out
> + exit 1
> +fi
> +
> +# Generate the expected list of functions for our trigger program.
> +
> +echo main > expected.tmp
> +echo mycallee >> expected.tmp
> +for x in 0 1 2 3 4 5 6 7 8 9 \
> + a b c d e f g h i j k l m n o p q r s t u v w x y z \
> + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z; do
> + echo myfunc_$x >> expected.tmp
> +done
> +sort expected.tmp > expected.txt
> +
> +# Check output for probe name "0" or "entry".
> +
> +awk '$2 == "0" || $2 == "entry"' D.out | awk '
> +{
> + fun = $1;
> + prb = $2;
> + PC = $3;
> + cnt = $4;
> +}
> +
> +# Check that the count is 1.
> +cnt != 1 {
> + print "ERROR: count is not 1";
> + print;
> + exit(1);
> +}
> +
> +# Check that we have not gotten the same (fun,prb) already.
> +prb == "0" && fun in PC0 {
> + print "ERROR: already have offset 0 for this func";
> + print;
> + exit(1);
> +}
> +prb == "entry" && fun in PCentry {
> + print "ERROR: already have entry for this func";
> + print;
> + exit(1);
> +}
> +
> +# Record the PC.
> +prb == "0" { PC0[fun] = PC; }
> +prb == "entry" { PCentry[fun] = PC; }
> +
> +# Do final matchup.
> +END {
> + # Walk functions for the offset-0 probes.
> + for (fun in PC0) {
> + # Make sure each offset-0 probe has a matching entry probe.
> + if (!(fun in PCentry)) {
> + print "ERROR: func", fun, "has offset-0 but no entry";
> + exit(1);
> + }
> +
> + # Make sure the matching probes report the same PC.
> + if (PC0[fun] != PCentry[fun]) {
> + print "ERROR: func", fun, "has mismatching PCs for offset-0 and entry:", PC0[fun], PCentry[fun];
> + exit(1);
> + }
> +
> + # Dump the function name and delete these entries.
> + print fun;
> + delete PC0[fun];
> + delete PCentry[fun];
> + }
> +
> + # Check if there are any leftover entry probes.
> + for (fun in PCentry) {
> + print "ERROR: func", fun, "has entry but no offset-0";
> + exit(1);
> + }
> +}
> +' | sort > awk.out
> +
> +# Report any problems.
> +
> +if ! diff -q awk.out expected.txt; then
> + echo ERROR: diff failure
> + echo ==== function list
> + cat awk.out
> + echo ==== expected function list
> + cat expected.txt
> + echo ==== diff
> + diff awk.out expected.txt
> + echo ==== DTrace output
> + cat D.out
> + exit 1
> +fi
> +
> +echo success
> +exit 0
> --
> 2.43.5
>
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline
2024-10-24 2:42 ` Kris Van Hees
@ 2024-10-24 13:52 ` Kris Van Hees
2024-10-24 23:30 ` Eugene Loh
0 siblings, 1 reply; 44+ messages in thread
From: Kris Van Hees @ 2024-10-24 13:52 UTC (permalink / raw)
To: Kris Van Hees; +Cc: eugene.loh, dtrace, dtrace-devel
Additional comment below...
On Wed, Oct 23, 2024 at 10:42:34PM -0400, Kris Van Hees via DTrace-devel wrote:
> On Thu, Aug 29, 2024 at 01:25:47AM -0400, eugene.loh@oracle.com wrote:
> > From: Eugene Loh <eugene.loh@oracle.com>
> >
> > An underlying probe could support all sorts of overlying probes:
> > - pid entry
> > - pid return
> > - pid offset
> > - USDT
> > - USDT is-enabled
> >
> > The overlying probes belonging to an underlying probe match the
> > underlying probe -- except possibly in pid. So, an underlying
> > probe loops over its overlying probes, looking for a pid match.
> >
> > The trampoline would look for only one match.
> >
> > However, more than one overlying probe might match. Therefore,
> > change the loop to keep going even after a match has been found.
> >
> > Incidentally, it is actually only pid offset probes that could
> > "collide" with any other overlying probes for a given pid:
> >
> > -) pid return probes are implemented with uretprobes
> > and so cannot "collide" with any other probes
> >
> > -) no two USDT probes -- is-enabled or not -- can map
> > to the same underlying probe for any pid
> >
> > -) no USDT probe -- is-enabled or not -- can map to
> > to the same underlying probe as a pid entry
> >
> > So, possibly one could optimize the trampoline -- e.g., by adding
> > BPF code to exit once two matches have been made.
> >
> > Incidentally, there is a small error in the patch. The flag we
> > pass in to dt_cg_tramp_copy_args_from_regs() should depend on
> > whether the overlying probe is a pid or USDT probe. We used to
> > check PP_IS_FUNCALL, the upp could be for both. Instead of
> > fixing this problem, let us simply pretend it's a pid probe --
> > a later patch will move USDT probes to a different mechanism anyhow.
>
> I think it is more clear to just keep the logic that is there for passing the
> flag, even if it is not exactly correct. At least it is not a change from
> something that might be wrong to something that is more likely to be wrong.
> Either way, you are changing it in a subsequent patch so the change to a
> hardcoded 1 is not really helping anything other than making someone perhaps
> wonder why you changed it.
>
> Alternatively, you could perhaps change the check for the PP_IS_FUNCALL flag
> to checking the prp->prov->impl, and selecting 1 for dt_pid and 0 for dt_usdt?
> Yes, you will change that in the subsequent patch, but it would be actually
> fixing this to be the correct condition anyway, right?
>
> Summary, wrong -> different-wrong seems silly, wrong -> wrong (keeping it
> the same) is reasonable, wrong -> correct is of course preferred.
>
> >
> > Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> > ---
> > libdtrace/dt_prov_uprobe.c | 53 +++++-------
> > test/unittest/pid/tst.entry_off0.sh | 125 ++++++++++++++++++++++++++++
> > 2 files changed, 147 insertions(+), 31 deletions(-)
> > create mode 100755 test/unittest/pid/tst.entry_off0.sh
> >
> > diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> > index 70e5c32d..bc5545fb 100644
> > --- a/libdtrace/dt_prov_uprobe.c
> > +++ b/libdtrace/dt_prov_uprobe.c
> > @@ -687,45 +687,23 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> > const list_probe_t *pop;
> > uint_t lbl_exit = pcb->pcb_exitlbl;
> >
> > - dt_cg_tramp_prologue(pcb);
> > + dt_cg_tramp_prologue(pcb); // call this only once... is PRID set/relocated correctly?
>
> I do not believe this change is needed (adding the comment). A trampoline can
> only ever have a single prologue.
>
> >
> > /*
> > * After the dt_cg_tramp_prologue() call, we have:
> > * // (%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);
> > - else
> > - dt_cg_tramp_copy_args_from_regs(pcb,
> > - !(upp->flags & PP_IS_FUNCALL));
> > -
> > - /*
> > - * Retrieve the PID of the process that caused the probe to fire.
> > - */
> > - emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> > - emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
> > + dt_cg_tramp_copy_regs(pcb); // call this only once for all clauses?
> >
> > /*
> > - * Generate a composite conditional clause:
> > - *
> > - * 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 == ...) {
> > - * < ... >
> > - * }
> > + * Loop over overlying probes, calling clauses for those that match:
> > *
> > - * 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.
> > + * for overlying probes (that match except possibly for pid)
> > + * if (pid matches) {
> > + * dctx->mst->prid = PRID1;
> > + * < any number of clause calls >
> > + * }
> > */
> > for (pop = dt_list_next(&upp->probes); pop != NULL;
> > pop = dt_list_next(pop)) {
> > @@ -740,6 +718,20 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> > idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
> > assert(idp != NULL);
> >
> > + /*
> > + * Register copies. FIXME: What can be optimized?
> > + */
>
> I would drop the FIXME. There is not really much of anything that can be
> optimized because we need the register content in case some clause makes use
> of regs[]. And arguments need to be copied for argN and args[], unless we
> want to implement arg-access using a provider callback during CG, and that
> would be an optimization across all providers so definitely not something for
> now. So, no need to have a FIXME. It's biger than USDT :)
>
> > + if (upp->flags & PP_IS_RETURN)
> > + dt_cg_tramp_copy_rval_from_regs(pcb);
> > + else
> > + dt_cg_tramp_copy_args_from_regs(pcb, 1);
>
> Per my comment above, I think this should still retain the code that was here
> before (well, higher up) to select the correct flag to pass rather than just
> hardcoding it as 1 and mentioning it is a bug. It is easy enough to just keep
> what was there as logic, and then change that in a subsequent patch.
>
> Using (prp->prov->impl == &dt_pid ? 1 : 0) would do the trick, right?
Actually, since you already document that the pid return probe cannot collide
with other probes (but there could be multiple return probes, one per PID of
course), I think you can still keep the copy rval vs args outside the loop,
right? And that also still works after subsequent patches, because you have
this before the loop for pid probes, and later there will be a test to be done
if it is a return probe, and after that a args_froom_regs for USDT.
I see no reason to move this inside to the loop. What am I missing?
>
> > +
> > + /*
> > + * Retrieve the PID of the process that caused the probe to fire.
> > + */
> > + emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> > + emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
>
> Wouldn't it be better to retrieve the PID once, and store it in %r6, and then
> use it at every branch rather than retrieving the PID for every case?
>
> > +
> > /*
> > * Check whether this pid-provider probe serves the current
> > * process, and emit a sequence of clauses for it when it does.
> > @@ -747,7 +739,6 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> > 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));
> > emitl(dlp, lbl_next,
> > BPF_NOP());
> > }
> > diff --git a/test/unittest/pid/tst.entry_off0.sh b/test/unittest/pid/tst.entry_off0.sh
> > new file mode 100755
> > index 00000000..f1a75b6a
> > --- /dev/null
> > +++ b/test/unittest/pid/tst.entry_off0.sh
> > @@ -0,0 +1,125 @@
> > +#!/bin/bash
> > +#
> > +# Oracle Linux DTrace.
> > +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
> > +# Licensed under the Universal Permissive License v 1.0 as shown at
> > +# http://oss.oracle.com/licenses/upl.
> > +#
> > +
> > +dtrace=$1
> > +
> > +trig=`pwd`/test/triggers/ustack-tst-basic
> > +
> > +DIRNAME="$tmpdir/enter_off0.$$.$RANDOM"
> > +mkdir -p $DIRNAME
> > +cd $DIRNAME
> > +
> > +# Run DTrace, dumping all probe functions and names, plus PC, in a.out.
> > +
> > +$dtrace $dt_flags -c $trig -n '
> > +pid$target:a.out::
> > +{
> > + @[probefunc, probename, uregs[R_PC]] = count();
> > +}
> > +
> > +profile:::tick-1s
> > +{
> > + exit(0);
> > +}' > D.out
> > +if [ $? -ne 0 ]; then
> > + echo ERROR: dtrace
> > + cat D.out
> > + exit 1
> > +fi
> > +
> > +# Generate the expected list of functions for our trigger program.
> > +
> > +echo main > expected.tmp
> > +echo mycallee >> expected.tmp
> > +for x in 0 1 2 3 4 5 6 7 8 9 \
> > + a b c d e f g h i j k l m n o p q r s t u v w x y z \
> > + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z; do
> > + echo myfunc_$x >> expected.tmp
> > +done
> > +sort expected.tmp > expected.txt
> > +
> > +# Check output for probe name "0" or "entry".
> > +
> > +awk '$2 == "0" || $2 == "entry"' D.out | awk '
> > +{
> > + fun = $1;
> > + prb = $2;
> > + PC = $3;
> > + cnt = $4;
> > +}
> > +
> > +# Check that the count is 1.
> > +cnt != 1 {
> > + print "ERROR: count is not 1";
> > + print;
> > + exit(1);
> > +}
> > +
> > +# Check that we have not gotten the same (fun,prb) already.
> > +prb == "0" && fun in PC0 {
> > + print "ERROR: already have offset 0 for this func";
> > + print;
> > + exit(1);
> > +}
> > +prb == "entry" && fun in PCentry {
> > + print "ERROR: already have entry for this func";
> > + print;
> > + exit(1);
> > +}
> > +
> > +# Record the PC.
> > +prb == "0" { PC0[fun] = PC; }
> > +prb == "entry" { PCentry[fun] = PC; }
> > +
> > +# Do final matchup.
> > +END {
> > + # Walk functions for the offset-0 probes.
> > + for (fun in PC0) {
> > + # Make sure each offset-0 probe has a matching entry probe.
> > + if (!(fun in PCentry)) {
> > + print "ERROR: func", fun, "has offset-0 but no entry";
> > + exit(1);
> > + }
> > +
> > + # Make sure the matching probes report the same PC.
> > + if (PC0[fun] != PCentry[fun]) {
> > + print "ERROR: func", fun, "has mismatching PCs for offset-0 and entry:", PC0[fun], PCentry[fun];
> > + exit(1);
> > + }
> > +
> > + # Dump the function name and delete these entries.
> > + print fun;
> > + delete PC0[fun];
> > + delete PCentry[fun];
> > + }
> > +
> > + # Check if there are any leftover entry probes.
> > + for (fun in PCentry) {
> > + print "ERROR: func", fun, "has entry but no offset-0";
> > + exit(1);
> > + }
> > +}
> > +' | sort > awk.out
> > +
> > +# Report any problems.
> > +
> > +if ! diff -q awk.out expected.txt; then
> > + echo ERROR: diff failure
> > + echo ==== function list
> > + cat awk.out
> > + echo ==== expected function list
> > + cat expected.txt
> > + echo ==== diff
> > + diff awk.out expected.txt
> > + echo ==== DTrace output
> > + cat D.out
> > + exit 1
> > +fi
> > +
> > +echo success
> > +exit 0
> > --
> > 2.43.5
> >
>
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel@oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 10/19] Remove the is-enabled provider
2024-08-29 5:25 ` [PATCH 10/19] Remove the is-enabled provider eugene.loh
@ 2024-10-24 15:18 ` Kris Van Hees
2024-10-26 1:13 ` Eugene Loh
0 siblings, 1 reply; 44+ messages in thread
From: Kris Van Hees @ 2024-10-24 15:18 UTC (permalink / raw)
To: eugene.loh; +Cc: dtrace, dtrace-devel
On Thu, Aug 29, 2024 at 01:25:49AM -0400, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> The trampoline for the is-enabled provider is unnecessarily complicated.
> We do not need dt_cg_tramp_copy_regs() since the copied values will not
> be used. Nor do we need the (second) copy of regs[arg0] to mst->arg[0].
> We can inline copyout_val().
>
> Actually, we can simply consolidate the USDT and is-enabled providers.
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> libdtrace/dt_prov_uprobe.c | 165 ++++++-------------------------------
> 1 file changed, 26 insertions(+), 139 deletions(-)
>
> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> index 6403842f..98d7b79b 100644
> --- a/libdtrace/dt_prov_uprobe.c
> +++ b/libdtrace/dt_prov_uprobe.c
> @@ -44,7 +44,6 @@
>
> /* Provider name for the underlying probes. */
> static const char prvname[] = "uprobe";
> -static const char prvname_is_enabled[] = "uprobe__is_enabled";
>
> #define PP_IS_RETURN 1
> #define PP_IS_FUNCALL 2
> @@ -82,7 +81,6 @@ static const dtrace_pattr_t pattr = {
> { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
> };
>
> -dt_provimpl_t dt_uprobe_is_enabled;
> dt_provimpl_t dt_pid;
> dt_provimpl_t dt_usdt;
>
> @@ -93,8 +91,6 @@ static int populate(dtrace_hdl_t *dtp)
>
> if (dt_provider_create(dtp, dt_uprobe.name, &dt_uprobe, &pattr,
> NULL) == NULL ||
> - dt_provider_create(dtp, dt_uprobe_is_enabled.name,
> - &dt_uprobe_is_enabled, &pattr, NULL) == NULL ||
> dt_provider_create(dtp, dt_pid.name, &dt_pid, &pattr,
> NULL) == NULL ||
> dt_provider_create(dtp, dt_usdt.name, &dt_usdt, &pattr,
> @@ -404,7 +400,6 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> dtrace_probedesc_t pd;
> dt_probe_t *uprp;
> dt_uprobe_t *upp;
> - int is_enabled = 0;
>
> /*
> * The underlying probes (uprobes) represent the tracepoints that pid
> @@ -427,8 +422,6 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> strcpy(prb, "return");
> break;
> case DTPPT_IS_ENABLED:
> - is_enabled = 1;
> - /* Fallthrough. */
> case DTPPT_ENTRY:
> case DTPPT_OFFSETS:
> snprintf(prb, sizeof(prb), "%lx", psp->pps_off);
> @@ -439,7 +432,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp,
> }
>
> pd.id = DTRACE_IDNONE;
> - pd.prv = is_enabled ? prvname_is_enabled : prvname;
> + pd.prv = prvname;
> pd.mod = mod;
> pd.fun = psp->pps_fun;
> pd.prb = prb;
> @@ -631,21 +624,6 @@ static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp, int is_usdt)
> dt_probe_enable(dtp, uprp);
> }
>
> - /*
> - * If necessary, we need to enable is-enabled probes too (if they
> - * exist).
> - */
> - if (is_usdt) {
> - dtrace_probedesc_t pd;
> - dt_probe_t *iep;
> -
> - memcpy(&pd, &prp->desc, sizeof(pd));
> - pd.prv = prvname_is_enabled;
> - iep = dt_probe_lookup(dtp, &pd);
> - if (iep != NULL)
> - dt_probe_enable(dtp, iep);
> - }
> -
> /*
> * Finally, ensure we're in the list of enablings as well.
> * (This ensures that, among other things, the probes map
> @@ -790,6 +768,29 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> emit(dlp, BPF_CALL_HELPER(BPF_FUNC_map_lookup_elem));
> emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_exit));
>
> + if (upp->flags & PP_IS_ENABLED) {
> + /*
> + * Generate a BPF trampoline for an is-enabled probe. The is-enabled probe
> + * prototype looks like:
> + *
> + * int is_enabled(int *arg)
> + *
> + * The trampoline writes 1 into the location pointed to by the passed-in arg.
> + */
> + emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), 1));
> + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, PT_REGS_ARG0));
> + emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP));
> + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0)));
> + emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t)));
> + emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_write_user));
> +
> + goto out;
> + }
Something occured to me... Should the is-enabled probe also be PID-based?
Presumably, it is OK if we allow the guarded code to execute even if the
particular USDT pribe is not enabled for the PID, but it *could* lead to
inconsistent excution because if the associated USDT probe is not enabled,
is-enabled for thta USDT probe in that PID *should* not execute.
Right? So there should be a check to see if PID is in the usdt_prids BPF map,
and only execute the writing of the 1 into *arg0 if the PID was found for the
correct (prid, PID) key?
> +
> + /*
> + * Continue with normal USDT probes.
> + */
> +
> /* 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));
> @@ -839,110 +840,11 @@ out:
> return 0;
> }
>
> -/*
> - * Copy the given immediate value into the address given by the specified probe
> - * argument.
> - */
> -static void
> -copyout_val(dt_pcb_t *pcb, uint_t lbl, uint32_t val, int arg)
> -{
> - dt_regset_t *drp = pcb->pcb_regs;
> - dt_irlist_t *dlp = &pcb->pcb_ir;
> -
> - emitl(dlp, lbl, BPF_STORE_IMM(BPF_DW, BPF_REG_FP, DT_TRAMP_SP_SLOT(0),
> - val));
> -
> - if (dt_regset_xalloc_args(drp) == -1)
> - longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(arg)));
> - emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP));
> - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0)));
> - emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t)));
> - dt_regset_xalloc(drp, BPF_REG_0);
> - emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_write_user));
> -
> - /* XXX any point error-checking here? What can we possibly do? */
> - dt_regset_free(drp, BPF_REG_0);
> - dt_regset_free_args(drp);
> -}
> -
> -/*
> - * Generate a BPF trampoline for an is-enabled probe. The is-enabled probe
> - * prototype looks like:
> - *
> - * int is_enabled(int *arg)
> - *
> - * The trampoline dereferences the passed-in arg and writes 1 into it if this is
> - * one of the processes for which the probe is enabled.
> - */
> -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;
> - dt_ident_t *usdt_prids = dt_dlib_get_map(pcb->pcb_hdl, "usdt_prids");
> -
> - assert(usdt_prids != NULL);
> -
> - dt_cg_tramp_prologue(pcb);
> -
> - /*
> - * After the dt_cg_tramp_prologue() call, we have:
> - * // (%r7 = dctx->mst)
> - * // (%r8 = dctx->ctx)
> - */
> - dt_cg_tramp_copy_regs(pcb);
> -
> - /*
> - * Copy in the first function argument, a pointer value to which
> - * the is-enabled state of the probe will be written (necessarily
> - * 1 if this probe is running at all).
> - */
> - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, PT_REGS_ARG0));
> - emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0));
> -
> - /*
> - * Retrieve the PID of the process that caused the probe to fire.
> - */
> - emit(dlp, BPF_CALL_HELPER(BPF_FUNC_get_current_pid_tgid));
> - emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, 32));
> -
> - /*
> - * Look up in the BPF 'usdt_prids' map. Space for the look-up key
> - * will be used on the BPF stack:
> - *
> - * offset value
> - *
> - * -sizeof(usdt_prids_map_key_t) pid (in %r0)
> - *
> - * -sizeof(usdt_prids_map_key_t) + sizeof(pid_t)
> - * ==
> - * -sizeof(dtrace_id_t) underlying-probe prid
> - */
> - emit(dlp, BPF_STORE(BPF_W, BPF_REG_9, (int)(-sizeof(usdt_prids_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, usdt_prids, DT_LBL_NONE, BPF_REG_1, usdt_prids->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(usdt_prids_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));
> -
> - /*
> - * 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);
> -
> - return 0;
> -}
> -
> static char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int flags)
> {
> char *name;
>
> - if (asprintf(&name, "dt_pid%s/%c_%llx_%llx_%lx",
> - flags & PP_IS_ENABLED ? "_is_enabled" : "",
> + if (asprintf(&name, "dt_pid/%c_%llx_%llx_%lx",
> flags & PP_IS_RETURN ? 'r' : 'p', (unsigned long long)dev,
> (unsigned long long)ino, (unsigned long)addr) < 0)
> return NULL;
> @@ -952,7 +854,7 @@ static char *uprobe_name(dev_t dev, ino_t ino, uint64_t addr, int flags)
>
> /*
> * Create a uprobe for a given dev/ino, mapping filename, and address: the
> - * uprobe may be a uretprobe or an is-enabled probe. Return the probe's name as
> + * uprobe may be a uretprobe. Return the probe's name as
> * a new dynamically-allocated string, or NULL on error.
> */
> static char *uprobe_create(dev_t dev, ino_t ino, const char *mapping_fn,
> @@ -1114,21 +1016,6 @@ dt_provimpl_t dt_uprobe = {
> .update = &update_uprobe,
> };
>
> -/*
> - * Used for underlying is-enabled uprobes.
> - */
> -dt_provimpl_t dt_uprobe_is_enabled = {
> - .name = prvname_is_enabled,
> - .prog_type = BPF_PROG_TYPE_KPROBE,
> - .populate = &populate,
> - .load_prog = &dt_bpf_prog_load,
> - .trampoline = &trampoline_is_enabled,
> - .attach = &attach,
> - .probe_info = &probe_info,
> - .detach = &detach,
> - .probe_destroy = &probe_destroy_underlying,
> -};
> -
> /*
> * Used for pid probes.
> */
> --
> 2.43.5
>
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 16/19] Ignore clauses: use underlying probe's function information
2024-08-29 5:25 ` [PATCH 16/19] Ignore clauses: use underlying probe's function information eugene.loh
@ 2024-10-24 16:52 ` Kris Van Hees
0 siblings, 0 replies; 44+ messages in thread
From: Kris Van Hees @ 2024-10-24 16:52 UTC (permalink / raw)
To: eugene.loh; +Cc: dtrace, dtrace-devel
On Thu, Aug 29, 2024 at 01:25:55AM -0400, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees@orcle.com>
> ---
> libdtrace/dt_prov_uprobe.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> index 454c53dc..9d163d70 100644
> --- a/libdtrace/dt_prov_uprobe.c
> +++ b/libdtrace/dt_prov_uprobe.c
> @@ -291,6 +291,11 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp)
> * If USDT_FLAG_POSSIBLE, try to use uprp.
> */
>
> + /* We know what function we're in. It must match the probe description (unless "-"). */
> + if (strcmp(pdp->fun, "-") != 0 &&
> + !dt_gmatch(uprp->desc->fun, pdp->fun))
> + return 1;
> +
> return 0;
> }
>
> --
> 2.43.5
>
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 19/19] test: Add another USDT open/close test
2024-08-29 5:25 ` [PATCH 19/19] test: Add another USDT open/close test eugene.loh
@ 2024-10-24 17:01 ` Kris Van Hees
0 siblings, 0 replies; 44+ messages in thread
From: Kris Van Hees @ 2024-10-24 17:01 UTC (permalink / raw)
To: eugene.loh; +Cc: dtrace, dtrace-devel
On Thu, Aug 29, 2024 at 01:25:58AM -0400, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> There is already a test to check that "dtrace -l" sees USDT
> probes come and go as an executable loads and unloads a shared
> library with USDT probes. (See dlclose1.sh.) But it could
> also fail if DTrace does not immediately notice USDT probes
> coming or going.
>
> Introduce a test that allows a grace period before DTrace
> notices a USDT probe come or go.
>
> There is a deadlib.so here. It is not needed for the test.
> It simply mimics other, similar tests. The real thing to do
> might be to put these shared libraries, common to multiple
> tests, in test/triggers.
Perhaps a shared copy might be useful, but then again, these are generated
on-the-fly by the tests.
But keeping deadlib in this test makes no sense, since it is not used.
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> ---
> test/unittest/usdt/tst.dlclose4.r | 5 +
> test/unittest/usdt/tst.dlclose4.sh | 225 +++++++++++++++++++++++++++++
> 2 files changed, 230 insertions(+)
> create mode 100644 test/unittest/usdt/tst.dlclose4.r
> create mode 100755 test/unittest/usdt/tst.dlclose4.sh
>
> diff --git a/test/unittest/usdt/tst.dlclose4.r b/test/unittest/usdt/tst.dlclose4.r
> new file mode 100644
> index 00000000..07927a4a
> --- /dev/null
> +++ b/test/unittest/usdt/tst.dlclose4.r
> @@ -0,0 +1,5 @@
> +as expected: USDT probe appeared
> +as expected: USDT probe disappeared
> +as expected: USDT probe appeared
> +as expected: USDT probe disappeared
> +success
> diff --git a/test/unittest/usdt/tst.dlclose4.sh b/test/unittest/usdt/tst.dlclose4.sh
> new file mode 100755
> index 00000000..015bc52c
> --- /dev/null
> +++ b/test/unittest/usdt/tst.dlclose4.sh
> @@ -0,0 +1,225 @@
> +#!/bin/bash
> +#
> +# Oracle Linux DTrace.
> +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
> +# Licensed under the Universal Permissive License v 1.0 as shown at
> +# http://oss.oracle.com/licenses/upl.
> +#
> +PATH=/usr/bin:/usr/sbin:$PATH
> +
> +#
> +# In this test, we send alternating USR1 and USR2 signals to an executable
> +# that responds by opening and closing, respectively, a shared library with
> +# USDT probes. After each signal, we check "dtrace -l" to confirm that the
> +# USDT probes are and are not listed, as expected.
> +#
> +
> +dtrace=$1
> +CC=/usr/bin/gcc
> +CFLAGS=
> +
> +DIRNAME="$tmpdir/usdt-dlclose4.$$.$RANDOM"
> +mkdir -p $DIRNAME
> +cd $DIRNAME
> +
> +#
> +# Set up the source files.
> +#
> +
> +cat > Makefile <<EOF
> +all: main livelib.so deadlib.so
> +
> +main: main.o prov.o
> + \$(CC) -o main main.o -ldl
> +
> +main.o: main.c
> + \$(CC) -c main.c
> +
> +
> +livelib.so: livelib.o prov.o
> + \$(CC) -shared -o livelib.so livelib.o prov.o -lc
> +
> +livelib.o: livelib.c prov.h
> + \$(CC) -c livelib.c
> +
> +prov.o: livelib.o prov.d
> + $dtrace -G -s prov.d livelib.o
> +
> +prov.h: prov.d
> + $dtrace -h -s prov.d
> +
> +
> +deadlib.so: deadlib.o
> + \$(CC) -shared -o deadlib.so deadlib.o -lc
> +
> +deadlib.o: deadlib.c
> + \$(CC) -c deadlib.c
> +
> +clean:
> + rm -f main.o livelib.o prov.o prov.h deadlib.o
> +
> +clobber: clean
> + rm -f main livelib.so deadlib.so
> +EOF
> +
> +cat > prov.d <<EOF
> +provider test_prov {
> + probe go();
> +};
> +EOF
> +
> +cat > livelib.c <<EOF
> +#include "prov.h"
> +
> +void
> +go(void)
> +{
> + TEST_PROV_GO();
> +}
> +EOF
> +
> +cat > deadlib.c <<EOF
> +void
> +go(void)
> +{
> +}
> +EOF
> +
> +cat > main.c <<EOF
> +#include <dlfcn.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +void *live;
> +
> +/*
> + * Open and close livelib.so, thereby adding or removing USDT probes.
> + */
> +
> +static void my_open(int sig) {
> + live = dlopen("./livelib.so", RTLD_LAZY | RTLD_LOCAL);
> + if (live == NULL) {
> + printf("dlopen of livelib.so failed: %s\n", dlerror());
> + exit(1);
> + }
> +}
> +
> +static void my_close(int sig) {
> + dlclose(live);
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> + struct sigaction act;
> +
> + /*
> + * Set USR1 (USR2) to open (close) the livelib.so.
> + */
> + act.sa_flags = 0;
> + act.sa_handler = my_open;
> + if (sigaction(SIGUSR1, &act, NULL)) {
> + printf("set handler failed\n");
> + return 1;
> + }
> + act.sa_handler = my_close;
> + if (sigaction(SIGUSR2, &act, NULL)) {
> + printf("set handler failed\n");
> + return 1;
> + }
> +
> + /*
> + * Listen for signals.
> + */
> + while (pause() == -1)
> + ;
> +
> + return 0;
> +}
> +EOF
> +
> +#
> +# Build.
> +#
> +
> +make > /dev/null
> +if [ $? -ne 0 ]; then
> + echo "failed to build" >& 2
> + exit 1
> +fi
> +
> +# Define a function that looks for the USDT probe with "dtrace -l".
> +# For debugging, one could also check:
> +# ls /run/dtrace/probes/$pid/test_prov$pid/livelib.so/go/go
> +# ls /run/dtrace/stash/dof-pid/$pid/*/parsed/test_prov:livelib.so:go:go
> +
> +function check_USDT_probes() {
> + $dtrace -lP test_prov$pid |& awk '
> + /ID *PROVIDER *MODULE *FUNCTION *NAME/ { next }
> + /test_prov'$pid' *livelib\.so *go *go/ { exit(0) }
> + /No probe matches description/ { exit(1) }'
> + return $?
> +}
> +
> +# Define a function that checks loading the library:
> +# send USR1 and wait up to 6 seconds for the USDT probe to appear.
> +
> +function load_lib() {
> + kill -s USR1 $pid
> + for iter in `seq 6`; do
> + sleep 1
> + if check_USDT_probes; then
> + iter=0
> + break
> + fi
> + done
> + if [[ $iter -ne 0 ]]; then
> + echo did not see USDT probe
> + kill -s KILL $pid
> + exit 1
> + fi
> + echo as expected: USDT probe appeared
> +}
> +
> +# Define a function that checks unloading the library:
> +# send USR2 and wait up to 6 seconds for the USDT probe to disappear.
> +
> +function unload_lib() {
> + kill -s USR2 $pid # send USR2 to unload library and USDT probe
> + for iter in `seq 6`; do
> + sleep 1
> + if ! check_USDT_probes; then
> + iter=0
> + break
> + fi
> + done
> + if [[ $iter -ne 0 ]]; then
> + echo still see USDT probe after timeout
> + kill -s KILL $pid
> + exit 1
> + fi
> + echo as expected: USDT probe disappeared
> +}
> +
> +# Start the process.
> +
> +./main &
> +pid=$!
> +sleep 2
> +
> +# Check.
> +
> +load_lib
> +unload_lib
> +load_lib
> +unload_lib
> +
> +# Clean up.
> +
> +kill -s KILL $pid
> +wait $pid >& /dev/null
> +
> +echo success
> +exit 0
> --
> 2.43.5
>
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline
2024-10-24 13:52 ` [DTrace-devel] " Kris Van Hees
@ 2024-10-24 23:30 ` Eugene Loh
2024-10-25 0:14 ` Kris Van Hees
0 siblings, 1 reply; 44+ messages in thread
From: Eugene Loh @ 2024-10-24 23:30 UTC (permalink / raw)
To: dtrace, dtrace-devel
I'm going to do a bit more testing before posting the next version of
this patch, but here are some comments while they're still fresh on my
mind...
On 10/24/24 09:52, Kris Van Hees wrote:
> On Wed, Oct 23, 2024 at 10:42:34PM -0400, Kris Van Hees via DTrace-devel wrote:
>> On Thu, Aug 29, 2024 at 01:25:47AM -0400, eugene.loh@oracle.com wrote:
>>> From: Eugene Loh <eugene.loh@oracle.com>
>>>
>>> An underlying probe could support all sorts of overlying probes:
>>> - pid entry
>>> - pid return
>>> - pid offset
>>> - USDT
>>> - USDT is-enabled
>>>
>>> The overlying probes belonging to an underlying probe match the
>>> underlying probe -- except possibly in pid. So, an underlying
>>> probe loops over its overlying probes, looking for a pid match.
>>>
>>> The trampoline would look for only one match.
>>>
>>> However, more than one overlying probe might match. Therefore,
>>> change the loop to keep going even after a match has been found.
>>>
>>> Incidentally, it is actually only pid offset probes that could
>>> "collide" with any other overlying probes for a given pid:
>>>
>>> -) pid return probes are implemented with uretprobes
>>> and so cannot "collide" with any other probes
>>>
>>> -) no two USDT probes -- is-enabled or not -- can map
>>> to the same underlying probe for any pid
>>>
>>> -) no USDT probe -- is-enabled or not -- can map to
>>> to the same underlying probe as a pid entry
>>>
>>> So, possibly one could optimize the trampoline -- e.g., by adding
>>> BPF code to exit once two matches have been made.
>>>
>>> Incidentally, there is a small error in the patch. The flag we
>>> pass in to dt_cg_tramp_copy_args_from_regs() should depend on
>>> whether the overlying probe is a pid or USDT probe. We used to
>>> check PP_IS_FUNCALL, the upp could be for both. Instead of
>>> fixing this problem, let us simply pretend it's a pid probe --
>>> a later patch will move USDT probes to a different mechanism anyhow.
>> I think it is more clear to just keep the logic that is there for passing the
>> flag, even if it is not exactly correct. At least it is not a change from
>> something that might be wrong to something that is more likely to be wrong.
>> Either way, you are changing it in a subsequent patch so the change to a
>> hardcoded 1 is not really helping anything other than making someone perhaps
>> wonder why you changed it.
>>
>> Alternatively, you could perhaps change the check for the PP_IS_FUNCALL flag
>> to checking the prp->prov->impl, and selecting 1 for dt_pid and 0 for dt_usdt?
>> Yes, you will change that in the subsequent patch, but it would be actually
>> fixing this to be the correct condition anyway, right?
Okay, I'll go this route: I'll check prp->prov->impl in this patch and
simplify the check in the following patch.
>> Summary, wrong -> different-wrong seems silly, wrong -> wrong (keeping it
>> the same) is reasonable, wrong -> correct is of course preferred.
>>
>>> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
>>>
>>> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
>>> @@ -740,6 +718,20 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
>>> idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
>>> assert(idp != NULL);
>>>
>>> + /*
>>> + * Register copies. FIXME: What can be optimized?
>>> + */
>> I would drop the FIXME. There is not really much of anything that can be
>> optimized because we need the register content in case some clause makes use
>> of regs[]. And arguments need to be copied for argN and args[], unless we
>> want to implement arg-access using a provider callback during CG, and that
>> would be an optimization across all providers so definitely not something for
>> now. So, no need to have a FIXME. It's biger than USDT :)
>>
>>> + if (upp->flags & PP_IS_RETURN)
>>> + dt_cg_tramp_copy_rval_from_regs(pcb);
>>> + else
>>> + dt_cg_tramp_copy_args_from_regs(pcb, 1);
>> Per my comment above, I think this should still retain the code that was here
>> before (well, higher up) to select the correct flag to pass rather than just
>> hardcoding it as 1 and mentioning it is a bug. It is easy enough to just keep
>> what was there as logic, and then change that in a subsequent patch.
>>
>> Using (prp->prov->impl == &dt_pid ? 1 : 0) would do the trick, right?
> Actually, since you already document that the pid return probe cannot collide
> with other probes (but there could be multiple return probes, one per PID of
> course), I think you can still keep the copy rval vs args outside the loop,
> right? And that also still works after subsequent patches, because you have
> this before the loop for pid probes, and later there will be a test to be done
> if it is a return probe, and after that a args_froom_regs for USDT.
>
> I see no reason to move this inside to the loop. What am I missing?
Ha... that's why the "FIXME: What can be optimized?"
On a more serious note, it's an interesting idea, but maybe not worth
it. Your suggestion is to do this once rather than for every loop
iteration. But the reality is (I think):
*) If it's a return probe, the loop will be executed only once. So
there is no difference between doing the copy before the loop and doing
the copy each iteration.
*) If it's not a return probe, the number of loop iterations could be:
*) 0 (no pid probes, just USDT), in which case the "optimization"
is counterproductive
*) 1 (a pid probe), in which case the "optimization" is neither
good nor bad
*) 2 (a pid entry and a pid offset=0 probe overlap), which case
the "optimization" helps
So, which is more common? The first case or the last? I think the
first, but in any case I don't think there is a strong case to argue for
the last. I guess we could check if there are any loop iterations, but
this is starting to sound like a bit of complexity for a minimal gain.
By the way, this "optimization" would have to be in the following patch,
not in this one. In the present patch, the overlying probe could be pid
or USDT. So, passing the "correct" arg to
dt_cg_tramp_copy_args_from_regs() would mean args are copied differently
for different iterations of the loop.
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [DTrace-devel] [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline
2024-10-24 23:30 ` Eugene Loh
@ 2024-10-25 0:14 ` Kris Van Hees
0 siblings, 0 replies; 44+ messages in thread
From: Kris Van Hees @ 2024-10-25 0:14 UTC (permalink / raw)
To: Eugene Loh; +Cc: dtrace, dtrace-devel
On Thu, Oct 24, 2024 at 07:30:04PM -0400, Eugene Loh via DTrace-devel wrote:
> I'm going to do a bit more testing before posting the next version of this
> patch, but here are some comments while they're still fresh on my mind...
>
> On 10/24/24 09:52, Kris Van Hees wrote:
> > On Wed, Oct 23, 2024 at 10:42:34PM -0400, Kris Van Hees via DTrace-devel wrote:
> > > On Thu, Aug 29, 2024 at 01:25:47AM -0400, eugene.loh@oracle.com wrote:
> > > > From: Eugene Loh <eugene.loh@oracle.com>
> > > >
> > > > An underlying probe could support all sorts of overlying probes:
> > > > - pid entry
> > > > - pid return
> > > > - pid offset
> > > > - USDT
> > > > - USDT is-enabled
> > > >
> > > > The overlying probes belonging to an underlying probe match the
> > > > underlying probe -- except possibly in pid. So, an underlying
> > > > probe loops over its overlying probes, looking for a pid match.
> > > >
> > > > The trampoline would look for only one match.
> > > >
> > > > However, more than one overlying probe might match. Therefore,
> > > > change the loop to keep going even after a match has been found.
> > > >
> > > > Incidentally, it is actually only pid offset probes that could
> > > > "collide" with any other overlying probes for a given pid:
> > > >
> > > > -) pid return probes are implemented with uretprobes
> > > > and so cannot "collide" with any other probes
> > > >
> > > > -) no two USDT probes -- is-enabled or not -- can map
> > > > to the same underlying probe for any pid
> > > >
> > > > -) no USDT probe -- is-enabled or not -- can map to
> > > > to the same underlying probe as a pid entry
> > > >
> > > > So, possibly one could optimize the trampoline -- e.g., by adding
> > > > BPF code to exit once two matches have been made.
> > > >
> > > > Incidentally, there is a small error in the patch. The flag we
> > > > pass in to dt_cg_tramp_copy_args_from_regs() should depend on
> > > > whether the overlying probe is a pid or USDT probe. We used to
> > > > check PP_IS_FUNCALL, the upp could be for both. Instead of
> > > > fixing this problem, let us simply pretend it's a pid probe --
> > > > a later patch will move USDT probes to a different mechanism anyhow.
> > > I think it is more clear to just keep the logic that is there for passing the
> > > flag, even if it is not exactly correct. At least it is not a change from
> > > something that might be wrong to something that is more likely to be wrong.
> > > Either way, you are changing it in a subsequent patch so the change to a
> > > hardcoded 1 is not really helping anything other than making someone perhaps
> > > wonder why you changed it.
> > >
> > > Alternatively, you could perhaps change the check for the PP_IS_FUNCALL flag
> > > to checking the prp->prov->impl, and selecting 1 for dt_pid and 0 for dt_usdt?
> > > Yes, you will change that in the subsequent patch, but it would be actually
> > > fixing this to be the correct condition anyway, right?
>
> Okay, I'll go this route: I'll check prp->prov->impl in this patch and
> simplify the check in the following patch.
>
> > > Summary, wrong -> different-wrong seems silly, wrong -> wrong (keeping it
> > > the same) is reasonable, wrong -> correct is of course preferred.
> > >
> > > > Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> > > >
> > > > diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c
> > > > @@ -740,6 +718,20 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
> > > > idp = dt_dlib_add_probe_var(pcb->pcb_hdl, prp);
> > > > assert(idp != NULL);
> > > > + /*
> > > > + * Register copies. FIXME: What can be optimized?
> > > > + */
> > > I would drop the FIXME. There is not really much of anything that can be
> > > optimized because we need the register content in case some clause makes use
> > > of regs[]. And arguments need to be copied for argN and args[], unless we
> > > want to implement arg-access using a provider callback during CG, and that
> > > would be an optimization across all providers so definitely not something for
> > > now. So, no need to have a FIXME. It's biger than USDT :)
> > >
> > > > + if (upp->flags & PP_IS_RETURN)
> > > > + dt_cg_tramp_copy_rval_from_regs(pcb);
> > > > + else
> > > > + dt_cg_tramp_copy_args_from_regs(pcb, 1);
> > > Per my comment above, I think this should still retain the code that was here
> > > before (well, higher up) to select the correct flag to pass rather than just
> > > hardcoding it as 1 and mentioning it is a bug. It is easy enough to just keep
> > > what was there as logic, and then change that in a subsequent patch.
> > >
> > > Using (prp->prov->impl == &dt_pid ? 1 : 0) would do the trick, right?
> > Actually, since you already document that the pid return probe cannot collide
> > with other probes (but there could be multiple return probes, one per PID of
> > course), I think you can still keep the copy rval vs args outside the loop,
> > right? And that also still works after subsequent patches, because you have
> > this before the loop for pid probes, and later there will be a test to be done
> > if it is a return probe, and after that a args_froom_regs for USDT.
> >
> > I see no reason to move this inside to the loop. What am I missing?
>
> Ha... that's why the "FIXME: What can be optimized?"
>
> On a more serious note, it's an interesting idea, but maybe not worth it.
> Your suggestion is to do this once rather than for every loop iteration.
> But the reality is (I think):
>
> *) If it's a return probe, the loop will be executed only once. So there
> is no difference between doing the copy before the loop and doing the copy
> each iteration.
>
> *) If it's not a return probe, the number of loop iterations could be:
>
> *) 0 (no pid probes, just USDT), in which case the "optimization" is
> counterproductive
>
> *) 1 (a pid probe), in which case the "optimization" is neither good
> nor bad
>
> *) 2 (a pid entry and a pid offset=0 probe overlap), which case the
> "optimization" helps
>
> So, which is more common? The first case or the last? I think the first,
> but in any case I don't think there is a strong case to argue for the last.
> I guess we could check if there are any loop iterations, but this is
> starting to sound like a bit of complexity for a minimal gain.
>
> By the way, this "optimization" would have to be in the following patch, not
> in this one. In the present patch, the overlying probe could be pid or
> USDT. So, passing the "correct" arg to dt_cg_tramp_copy_args_from_regs()
> would mean args are copied differently for different iterations of the loop.
Yes, you are right. So yes, fixing the flag but keeping the call in the
loop is the right action here.
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [PATCH 10/19] Remove the is-enabled provider
2024-10-24 15:18 ` Kris Van Hees
@ 2024-10-26 1:13 ` Eugene Loh
0 siblings, 0 replies; 44+ messages in thread
From: Eugene Loh @ 2024-10-26 1:13 UTC (permalink / raw)
To: dtrace, dtrace-devel
On 10/24/24 11:18, Kris Van Hees wrote:
> On Thu, Aug 29, 2024 at 01:25:49AM -0400, eugene.loh@oracle.com wrote:
>> From: Eugene Loh <eugene.loh@oracle.com>
>>
>> The trampoline for the is-enabled provider is unnecessarily complicated.
>> We do not need dt_cg_tramp_copy_regs() since the copied values will not
>> be used. Nor do we need the (second) copy of regs[arg0] to mst->arg[0].
>> We can inline copyout_val().
>>
>> Actually, we can simply consolidate the USDT and is-enabled providers.
>>
>> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
> Something occured to me... Should the is-enabled probe also be PID-based?
Yes.
> Presumably, it is OK if we allow the guarded code to execute even if the
> particular USDT pribe is not enabled for the PID
Or not.
> but it *could* lead to
> inconsistent excution because if the associated USDT probe is not enabled,
> is-enabled for thta USDT probe in that PID *should* not execute.
Right. And I know of no rule that says that is-enabled can guard only D
probes.
> Right? So there should be a check to see if PID is in the usdt_prids BPF map,
> and only execute the writing of the 1 into *arg0 if the PID was found for the
> correct (prid, PID) key?
All USDT probes check pid,uprid.
But don't take my word for it. I'm posting a v2 with a test for this stuff.
^ permalink raw reply [flat|nested] 44+ messages in thread
end of thread, other threads:[~2024-10-26 1:13 UTC | newest]
Thread overview: 44+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-29 5:25 [PATCH 01/19] Change probes from having lists of clauses to lists of stmts eugene.loh
2024-08-29 5:25 ` [PATCH 02/19] Add a hook for a provider-specific "update" function eugene.loh
2024-08-29 5:25 ` [PATCH 03/19] Widen the EPID to include the PRID eugene.loh
2024-08-29 20:28 ` [DTrace-devel] " Sam James
2024-08-29 20:38 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 04/19] Eliminate dt_pdesc eugene.loh
2024-09-03 17:47 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 05/19] Add flag to dt_pid_create_probes() eugene.loh
2024-09-18 20:33 ` Kris Van Hees
2024-09-24 20:24 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 06/19] Allow for USDT wildcards eugene.loh
2024-09-17 17:34 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 07/19] Create the BPF usdt_prids map eugene.loh
2024-08-29 5:25 ` [PATCH 08/19] Support multiple overlying probes in the uprobe trampoline eugene.loh
2024-10-24 2:42 ` Kris Van Hees
2024-10-24 13:52 ` [DTrace-devel] " Kris Van Hees
2024-10-24 23:30 ` Eugene Loh
2024-10-25 0:14 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 09/19] Use usdt_prids map to call clauses conditionally for USDT probes eugene.loh
2024-08-29 5:25 ` [PATCH 10/19] Remove the is-enabled provider eugene.loh
2024-10-24 15:18 ` Kris Van Hees
2024-10-26 1:13 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 11/19] Support USDT wildcard provider descriptions eugene.loh
2024-08-29 5:25 ` [PATCH 12/19] Increase size of BPF probes map eugene.loh
2024-08-29 20:30 ` [DTrace-devel] " Sam James
2024-10-08 22:15 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 13/19] Get rid of relocatable EPID, dt_nextepid, and dt_ddesc[] eugene.loh
2024-09-03 17:49 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 14/19] Ignore clauses in USDT trampoline if we know they are impossible eugene.loh
2024-08-29 5:25 ` [PATCH 15/19] Ignore clauses: some clauses are impossible regardless of uprp eugene.loh
2024-08-29 20:31 ` [DTrace-devel] " Sam James
2024-09-03 19:54 ` Eugene Loh
2024-09-03 20:10 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 16/19] Ignore clauses: use underlying probe's function information eugene.loh
2024-10-24 16:52 ` Kris Van Hees
2024-08-29 5:25 ` [PATCH 17/19] test: Add a pid-USDT test eugene.loh
2024-08-29 20:32 ` [DTrace-devel] " Sam James
2024-10-04 4:49 ` Eugene Loh
2024-10-04 5:51 ` Sam James
2024-08-29 5:25 ` [PATCH 18/19] test: Add a lazy USDT test eugene.loh
2024-09-28 2:11 ` Eugene Loh
2024-08-29 5:25 ` [PATCH 19/19] test: Add another USDT open/close test eugene.loh
2024-10-24 17:01 ` Kris Van Hees
2024-09-18 14:18 ` [PATCH 01/19] Change probes from having lists of clauses to lists of stmts Kris Van Hees
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox